diff --git a/.coveragerc b/.coveragerc index 5bf9de194df..2827607a95a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -119,7 +119,6 @@ omit = homeassistant/components/buienradar/weather.py homeassistant/components/caldav/calendar.py homeassistant/components/canary/camera.py - homeassistant/components/cast/* homeassistant/components/cert_expiry/helper.py homeassistant/components/channels/* homeassistant/components/circuit/* @@ -305,6 +304,7 @@ omit = homeassistant/components/garmin_connect/__init__.py homeassistant/components/garmin_connect/const.py homeassistant/components/garmin_connect/sensor.py + homeassistant/components/garmin_connect/alarm_util.py homeassistant/components/gc100/* homeassistant/components/geniushub/* homeassistant/components/geizhals/sensor.py @@ -377,7 +377,6 @@ omit = homeassistant/components/hvv_departures/__init__.py homeassistant/components/hydrawise/* homeassistant/components/hyperion/light.py - homeassistant/components/ialarm/alarm_control_panel.py homeassistant/components/iammeter/sensor.py homeassistant/components/iaqualink/binary_sensor.py homeassistant/components/iaqualink/climate.py @@ -460,6 +459,7 @@ omit = homeassistant/components/lametric/* homeassistant/components/lannouncer/notify.py homeassistant/components/lastfm/sensor.py + homeassistant/components/launch_library/const.py homeassistant/components/launch_library/sensor.py homeassistant/components/lcn/* homeassistant/components/lg_netcast/media_player.py @@ -632,7 +632,6 @@ omit = homeassistant/components/openuv/sensor.py homeassistant/components/openweathermap/sensor.py homeassistant/components/openweathermap/weather.py - homeassistant/components/openweathermap/forecast_update_coordinator.py homeassistant/components/openweathermap/weather_update_coordinator.py homeassistant/components/openweathermap/abstract_owm_sensor.py homeassistant/components/opnsense/* @@ -730,6 +729,7 @@ omit = homeassistant/components/roomba/vacuum.py homeassistant/components/roon/__init__.py homeassistant/components/roon/const.py + homeassistant/components/roon/media_browser.py homeassistant/components/roon/media_player.py homeassistant/components/roon/server.py homeassistant/components/route53/* @@ -770,6 +770,7 @@ omit = homeassistant/components/shelly/light.py homeassistant/components/shelly/sensor.py homeassistant/components/shelly/switch.py + homeassistant/components/shelly/utils.py homeassistant/components/sht31/sensor.py homeassistant/components/sigfox/sensor.py homeassistant/components/simplepush/notify.py diff --git a/.github/lock.yml b/.github/lock.yml deleted file mode 100644 index 7ce0cc65619..00000000000 --- a/.github/lock.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Configuration for Lock Threads - https://github.com/dessant/lock-threads - -# Number of days of inactivity before a closed issue or pull request is locked -daysUntilLock: 1 - -# Skip issues and pull requests created before a given timestamp. Timestamp must -# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable -skipCreatedBefore: 2019-07-01 - -# Issues and pull requests with these labels will be ignored. Set to `[]` to disable -exemptLabels: [] - -# Label to add before locking, such as `outdated`. Set to `false` to disable -lockLabel: false - -# Comment to post before locking. Set to `false` to disable -lockComment: false - -# Assign `resolved` as the reason for locking. Set to `false` to disable -setLockReason: false - -# Limit to only `issues` or `pulls` -only: pulls - -# Optionally, specify configuration settings just for `issues` or `pulls` -issues: - daysUntilLock: 30 diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index f09f3733651..00000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,66 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 90 - -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 7 - -# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) -onlyLabels: [] - -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: - - under investigation - - Help wanted - -# Set to true to ignore issues in a project (defaults to false) -exemptProjects: true - -# Set to true to ignore issues in a milestone (defaults to false) -exemptMilestones: true - -# Set to true to ignore issues with an assignee (defaults to false) -exemptAssignees: false - -# Label to use when marking as stale -staleLabel: stale - -# Comment to post when marking as stale. Set to `false` to disable -markComment: > - There hasn't been any activity on this issue recently. Due to the high number - of incoming GitHub notifications, we have to clean some of the old issues, - as many of them have already been resolved with the latest updates. - - Please make sure to update to the latest Home Assistant version and check - if that solves the issue. Let us know if that works for you by adding a - comment 👍 - - This issue now has been marked as stale and will be closed if no further - activity occurs. Thank you for your contributions. - -# Comment to post when removing the stale label. -# unmarkComment: > -# Your comment here. - -# Comment to post when closing a stale Issue or Pull Request. -# closeComment: > -# Your comment here. - -# Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 30 - -# Limit to only `issues` or `pulls` -# only: issues - -# Handle pull requests a little bit faster and with an adjusted comment. -pulls: - daysUntilStale: 30 - exemptProjects: false - markComment: > - There hasn't been any activity on this pull request recently. This pull - request has been automatically marked as stale because of that and will - be closed if no further activity occurs within 7 days. - - Thank you for your contributions. diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8125f81df44..ad6becee4e2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -214,11 +214,11 @@ jobs: run: | echo "::add-matcher::.github/workflows/matchers/hadolint.json" - name: Check Dockerfile - uses: docker://hadolint/hadolint:v1.18.0 + uses: docker://hadolint/hadolint:v1.18.2 with: args: hadolint Dockerfile - name: Check Dockerfile.dev - uses: docker://hadolint/hadolint:v1.18.0 + uses: docker://hadolint/hadolint:v1.18.2 with: args: hadolint Dockerfile.dev @@ -590,7 +590,8 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v2 - - name: Restore full Python ${{ matrix.python-version }} virtual environment + - name: + Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2 with: @@ -604,7 +605,8 @@ jobs: ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('requirements_all.txt') }} ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }} ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}- - - name: Create full Python ${{ matrix.python-version }} virtual environment + - name: + Create full Python ${{ matrix.python-version }} virtual environment if: steps.cache-venv.outputs.cache-hit != 'true' run: | python -m venv venv @@ -625,7 +627,8 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v2 - - name: Restore full Python ${{ matrix.python-version }} virtual environment + - name: + Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2 with: @@ -659,7 +662,8 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v2 - - name: Restore full Python ${{ matrix.python-version }} virtual environment + - name: + Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2 with: @@ -695,7 +699,8 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v2 - - name: Restore full Python ${{ matrix.python-version }} virtual environment + - name: + Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2 with: @@ -755,7 +760,8 @@ jobs: steps: - name: Check out code from GitHub uses: actions/checkout@v2 - - name: Restore full Python ${{ matrix.python-version }} virtual environment + - name: + Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2 with: diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml new file mode 100644 index 00000000000..4f7a0efb2d7 --- /dev/null +++ b/.github/workflows/lock.yml @@ -0,0 +1,20 @@ +name: Lock + +# yamllint disable-line rule:truthy +on: + schedule: + - cron: "0 * * * *" + +jobs: + lock: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v2.0.1 + with: + github-token: ${{ github.token }} + issue-lock-inactive-days: "30" + issue-exclude-created-before: "2020-10-01T00:00:00Z" + issue-lock-reason: "" + pr-lock-inactive-days: "1" + pr-exclude-created-before: "2020-11-01T00:00:00Z" + pr-lock-reason: "" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000000..1fe635ac57f --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,84 @@ +name: Stale + +# yamllint disable-line rule:truthy +on: + schedule: + - cron: "0 * * * *" + +jobs: + stale: + runs-on: ubuntu-latest + steps: + # The 90 day stale policy + # Used for: Everything (unless 30 day policy below beats it) + - name: 90 days stale policy + uses: actions/stale@v3.0.13 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + days-before-stale: 90 + days-before-close: 7 + operations-per-run: 25 + remove-stale-when-updated: true + stale-issue-label: "stale" + exempt-issue-labels: "no-stale,Help%20wanted,help-wanted" + stale-issue-message: > + There hasn't been any activity on this issue recently. Due to the + high number of incoming GitHub notifications, we have to clean some + of the old issues, as many of them have already been resolved with + the latest updates. + + Please make sure to update to the latest Home Assistant version and + check if that solves the issue. Let us know if that works for you by + adding a comment 👍 + + This issue has now been marked as stale and will be closed if no + further activity occurs. Thank you for your contributions. + + stale-pr-label: "stale" + exempt-pr-labels: "no-stale" + stale-pr-message: > + There hasn't been any activity on this pull request recently. This + pull request has been automatically marked as stale because of that + and will be closed if no further activity occurs within 7 days. + + Thank you for your contributions. + + # The 30 day stale policy + # Used for: + # - Issues that are pending more information (incomplete issues) + # - PRs that are not marked as new-integration + - name: 30 days stale policy + uses: actions/stale@v3.0.13 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + # PRs have a CLA signed label, we can misuse it to apply this policy + only-labels: "cla-signed,needs-more-information" + days-before-stale: 30 + days-before-close: 7 + operations-per-run: 5 + remove-stale-when-updated: true + stale-issue-label: "stale" + exempt-issue-labels: "no-stale,Help%20wanted,help-wanted" + stale-issue-message: > + There hasn't been any activity on this issue recently. Due to the + high number of incoming GitHub notifications, we have to clean some + of the old issues, as many of them have already been resolved with + the latest updates. + + Please make sure to update to the latest Home Assistant version and + check if that solves the issue. Let us know if that works for you by + adding a comment 👍 + + This issue has now been marked as stale and will be closed if no + further activity occurs. Thank you for your contributions. + + stale-pr-label: "stale" + # Exempt new integrations, these often take more time. + # They will automatically be handled by the 90 day version above. + exempt-pr-labels: "no-stale,new-integration" + stale-pr-message: > + There hasn't been any activity on this pull request recently. This + pull request has been automatically marked as stale because of that + and will be closed if no further activity occurs within 7 days. + + Thank you for your contributions. diff --git a/.travis.yml b/.travis.yml index 88bc8b707cf..218bb1132a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -dist: bionic +dist: focal addons: apt: packages: @@ -11,9 +11,6 @@ addons: - libswscale-dev - libswresample-dev - libavfilter-dev - sources: - - sourceline: ppa:savoury1/ffmpeg4 - - sourceline: ppa:savoury1/multimedia python: - "3.7.1" @@ -42,4 +39,4 @@ cache: - $HOME/.cache/pre-commit install: pip install -U tox tox-travis language: python -script: ${TRAVIS_WAIT:+travis_wait $TRAVIS_WAIT} tox --develop ${TOX_ARGS-} +script: ${TRAVIS_WAIT:+travis_wait $TRAVIS_WAIT} tox -vv --develop ${TOX_ARGS-} diff --git a/CODEOWNERS b/CODEOWNERS index 064c690903d..e0096e7f217 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -9,6 +9,12 @@ homeassistant/*.py @home-assistant/core homeassistant/helpers/* @home-assistant/core homeassistant/util/* @home-assistant/core +# Home Assistant Supervisor +build.json @home-assistant/supervisor +machine/* @home-assistant/supervisor +rootfs/* @home-assistant/supervisor +Dockerfile @home-assistant/supervisor + # Other code homeassistant/scripts/check_config.py @kellerza @@ -58,6 +64,7 @@ homeassistant/components/bitcoin/* @fabaff homeassistant/components/bizkaibus/* @UgaitzEtxebarria homeassistant/components/blebox/* @gadgetmobile homeassistant/components/blink/* @fronzbot +homeassistant/components/blueprint/* @home-assistant/core homeassistant/components/bmp280/* @belidzs homeassistant/components/bmw_connected_drive/* @gerard33 @rikroe homeassistant/components/bond/* @prystupa @@ -76,6 +83,7 @@ homeassistant/components/cisco_mobility_express/* @fbradyirl homeassistant/components/cisco_webex_teams/* @fbradyirl homeassistant/components/cloud/* @home-assistant/cloud homeassistant/components/cloudflare/* @ludeeus @ctalkington +homeassistant/components/color_extractor/* @GenericStudent homeassistant/components/comfoconnect/* @michaelarnauts homeassistant/components/config/* @home-assistant/core homeassistant/components/configurator/* @home-assistant/core @@ -126,6 +134,7 @@ homeassistant/components/enocean/* @bdurrer homeassistant/components/entur_public_transport/* @hfurubotten homeassistant/components/environment_canada/* @michaeldavie homeassistant/components/ephember/* @ttroy50 +homeassistant/components/epson/* @pszafer homeassistant/components/epsonworkforce/* @ThaStealth homeassistant/components/eq3btsmart/* @rytilahti homeassistant/components/esphome/* @OttoWinter @@ -169,7 +178,7 @@ homeassistant/components/group/* @home-assistant/core homeassistant/components/growatt_server/* @indykoning homeassistant/components/guardian/* @bachya homeassistant/components/harmony/* @ehendrix23 @bramkragten @bdraco -homeassistant/components/hassio/* @home-assistant/hass-io +homeassistant/components/hassio/* @home-assistant/supervisor homeassistant/components/hdmi_cec/* @newAM homeassistant/components/heatmiser/* @andylockran homeassistant/components/heos/* @andrewsayre @@ -186,7 +195,6 @@ homeassistant/components/homekit/* @bdraco homeassistant/components/homekit_controller/* @Jc2k homeassistant/components/homematic/* @pvizeli @danielperna84 homeassistant/components/homematicip_cloud/* @SukramJ -homeassistant/components/honeywell/* @zxdavb homeassistant/components/http/* @home-assistant/core homeassistant/components/huawei_lte/* @scop @fphammerle homeassistant/components/huawei_router/* @abmantis @@ -257,7 +265,7 @@ homeassistant/components/met/* @danielhiversen @thimic homeassistant/components/meteo_france/* @hacf-fr @oncleben31 @Quentame homeassistant/components/meteoalarm/* @rolfberkenbosch homeassistant/components/metoffice/* @MrHarcombe -homeassistant/components/miflora/* @danielhiversen @ChristianKuehnel @basnijholt +homeassistant/components/miflora/* @danielhiversen @basnijholt homeassistant/components/mikrotik/* @engrbm87 homeassistant/components/mill/* @danielhiversen homeassistant/components/min_max/* @fabaff @@ -311,7 +319,7 @@ homeassistant/components/openerz/* @misialq homeassistant/components/opengarage/* @danielhiversen homeassistant/components/opentherm_gw/* @mvn23 homeassistant/components/openuv/* @bachya -homeassistant/components/openweathermap/* @fabaff @freekode +homeassistant/components/openweathermap/* @fabaff @freekode @nzapponi homeassistant/components/opnsense/* @mtreinish homeassistant/components/orangepi_gpio/* @pascallj homeassistant/components/oru/* @bvlaicu @@ -326,7 +334,6 @@ homeassistant/components/pi4ioe5v9xxxx/* @antonverburg homeassistant/components/pi_hole/* @fabaff @johnluetke @shenxn homeassistant/components/pilight/* @trekky12 homeassistant/components/plaato/* @JohNan -homeassistant/components/plant/* @ChristianKuehnel homeassistant/components/plex/* @jjlawren homeassistant/components/plugwise/* @CoMPaTech @bouwew homeassistant/components/plum_lightpad/* @ColinHarrington @prystupa @@ -382,7 +389,7 @@ homeassistant/components/seven_segments/* @fabaff homeassistant/components/seventeentrack/* @bachya homeassistant/components/sharkiq/* @ajmarks homeassistant/components/shell_command/* @home-assistant/core -homeassistant/components/shelly/* @balloob @bieniu +homeassistant/components/shelly/* @balloob @bieniu @thecode homeassistant/components/shiftr/* @fabaff homeassistant/components/shodan/* @fabaff homeassistant/components/sighthound/* @robmarkcole @@ -431,7 +438,7 @@ homeassistant/components/switchbot/* @danielhiversen homeassistant/components/switcher_kis/* @tomerfi homeassistant/components/switchmate/* @danielhiversen homeassistant/components/syncthru/* @nielstron -homeassistant/components/synology_dsm/* @hacf-fr @Quentame +homeassistant/components/synology_dsm/* @hacf-fr @Quentame @mib1185 homeassistant/components/synology_srm/* @aerialls homeassistant/components/syslog/* @fabaff homeassistant/components/tado/* @michaelarnauts @bdraco diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 2420c2e44a0..6da0b128e47 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -14,7 +14,7 @@ schedules: always: true variables: - name: versionBuilder - value: '7.2.0' + value: '2020.11.0' - group: docker - group: github - group: twine @@ -82,19 +82,14 @@ stages: matrix: amd64: buildArch: 'amd64' - buildMachine: 'qemux86-64,intel-nuc' i386: buildArch: 'i386' - buildMachine: 'qemux86' armhf: buildArch: 'armhf' - buildMachine: 'qemuarm,raspberrypi' armv7: buildArch: 'armv7' - buildMachine: 'raspberrypi2,raspberrypi3,raspberrypi4,odroid-xu,tinker' aarch64: buildArch: 'aarch64' - buildMachine: 'qemuarm-64,raspberrypi3-64,raspberrypi4-64,odroid-c2,odroid-n2' steps: - template: templates/azp-step-ha-version.yaml@azure - script: | @@ -111,6 +106,57 @@ stages: -v $(pwd):/data:ro \ homeassistant/amd64-builder:$(versionBuilder) \ --generic $(homeassistantRelease) "--$(buildArch)" -t /data \ + displayName: 'Build Release' + - job: 'ReleaseMachine' + dependsOn: + - ReleaseDocker + timeoutInMinutes: 240 + pool: + vmImage: 'ubuntu-latest' + strategy: + maxParallel: 15 + matrix: + qemux86-64: + buildMachine: 'qemux86-64' + intel-nuc: + buildMachine: 'intel-nuc' + qemux86: + buildMachine: 'qemux86' + qemuarm: + buildMachine: 'qemuarm' + raspberrypi: + buildMachine: 'raspberrypi' + raspberrypi2: + buildMachine: 'raspberrypi2' + raspberrypi3: + buildMachine: 'raspberrypi3' + raspberrypi4: + buildMachine: 'raspberrypi4' + odroid-xu: + buildMachine: 'odroid-xu' + tinker: + buildMachine: 'tinker' + qemuarm-64: + buildMachine: 'qemuarm-64' + raspberrypi3-64: + buildMachine: 'raspberrypi3-64' + raspberrypi4-64: + buildMachine: 'raspberrypi4-64' + odroid-c2: + buildMachine: 'odroid-c2' + odroid-c4: + buildMachine: 'odroid-c4' + odroid-n2: + buildMachine: 'odroid-n2' + steps: + - template: templates/azp-step-ha-version.yaml@azure + - script: | + docker login -u $(dockerUser) -p $(dockerPassword) + displayName: 'Docker hub login' + - script: docker pull homeassistant/amd64-builder:$(versionBuilder) + displayName: 'Install Builder' + - script: | + set -e docker run --rm --privileged \ -v ~/.docker:/root/.docker \ @@ -119,7 +165,7 @@ stages: homeassistant/amd64-builder:$(versionBuilder) \ --homeassistant-machine "$(homeassistantRelease)=$(buildMachine)" \ -t /data/machine --docker-hub homeassistant - displayName: 'Build Release' + displayName: 'Build Machine' - stage: 'Publish' jobs: diff --git a/build.json b/build.json index f48c5e217aa..43e23d32094 100644 --- a/build.json +++ b/build.json @@ -1,11 +1,11 @@ { "image": "homeassistant/{arch}-homeassistant", "build_from": { - "aarch64": "homeassistant/aarch64-homeassistant-base:2020.10.0", - "armhf": "homeassistant/armhf-homeassistant-base:2020.10.0", - "armv7": "homeassistant/armv7-homeassistant-base:2020.10.0", - "amd64": "homeassistant/amd64-homeassistant-base:2020.10.0", - "i386": "homeassistant/i386-homeassistant-base:2020.10.0" + "aarch64": "homeassistant/aarch64-homeassistant-base:2020.10.1", + "armhf": "homeassistant/armhf-homeassistant-base:2020.10.1", + "armv7": "homeassistant/armv7-homeassistant-base:2020.10.1", + "amd64": "homeassistant/amd64-homeassistant-base:2020.10.1", + "i386": "homeassistant/i386-homeassistant-base:2020.10.1" }, "labels": { "io.hass.type": "core" diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index b60fa8eff9c..1fe59346b00 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -207,7 +207,7 @@ class LoginFlow(data_entry_flow.FlowHandler): 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/bootstrap.py b/homeassistant/bootstrap.py index 1a8c1d554e3..0d63307a020 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -28,6 +28,7 @@ from homeassistant.setup import ( async_set_domains_to_be_loaded, async_setup_component, ) +from homeassistant.util.async_ import gather_with_concurrency from homeassistant.util.logging import async_activate_log_queue_handler from homeassistant.util.package import async_get_user_site, is_virtual_env from homeassistant.util.yaml import clear_secret_cache @@ -49,6 +50,8 @@ STAGE_2_TIMEOUT = 300 WRAP_UP_TIMEOUT = 300 COOLDOWN_TIME = 60 +MAX_LOAD_CONCURRENTLY = 6 + DEBUGGER_INTEGRATIONS = {"debugpy", "ptvsd"} CORE_INTEGRATIONS = ("homeassistant", "persistent_notification") LOGGING_INTEGRATIONS = { @@ -372,7 +375,7 @@ async def async_mount_local_lib_path(config_dir: str) -> str: def _get_domains(hass: core.HomeAssistant, config: Dict[str, Any]) -> Set[str]: """Get domains of components to set up.""" # Filter out the repeating and common config section [homeassistant] - domains = {key.split(" ")[0] for key in config.keys() if key != core.DOMAIN} + domains = {key.split(" ")[0] for key in config if key != core.DOMAIN} # Add config entry domains if not hass.config.safe_mode: @@ -442,7 +445,8 @@ async def _async_set_up_integrations( integrations_to_process = [ int_or_exc - for int_or_exc in await asyncio.gather( + for int_or_exc in await gather_with_concurrency( + loader.MAX_LOAD_CONCURRENTLY, *( loader.async_get_integration(hass, domain) for domain in old_to_resolve diff --git a/homeassistant/components/abode/translations/bg.json b/homeassistant/components/abode/translations/bg.json index 3489c8bc866..285bf18d330 100644 --- a/homeassistant/components/abode/translations/bg.json +++ b/homeassistant/components/abode/translations/bg.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430 Abode." }, - "error": { - "connection_error": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 Abode.", - "identifier_exists": "\u041f\u0440\u043e\u0444\u0438\u043b\u044a\u0442 \u0435 \u0432\u0435\u0447\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d.", - "invalid_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/ca.json b/homeassistant/components/abode/translations/ca.json index f33b51f6d6b..47bfd031c8e 100644 --- a/homeassistant/components/abode/translations/ca.json +++ b/homeassistant/components/abode/translations/ca.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No es pot connectar amb Abode.", - "identifier_exists": "Compte ja registrat.", - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Credencials inv\u00e0lides." + "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/cs.json b/homeassistant/components/abode/translations/cs.json index edd260bfbf5..36ff5f8b08f 100644 --- a/homeassistant/components/abode/translations/cs.json +++ b/homeassistant/components/abode/translations/cs.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nelze se p\u0159ipojit k Abode.", - "identifier_exists": "\u00da\u010det je ji\u017e zaregistrov\u00e1n.", - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje." + "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/da.json b/homeassistant/components/abode/translations/da.json index c00fd6ad5af..a6f8d3ddd66 100644 --- a/homeassistant/components/abode/translations/da.json +++ b/homeassistant/components/abode/translations/da.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning af Abode." }, - "error": { - "connection_error": "Kunne ikke oprette forbindelse til Abode.", - "identifier_exists": "Konto er allerede registreret.", - "invalid_credentials": "Ugyldige legitimationsoplysninger." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/de.json b/homeassistant/components/abode/translations/de.json index abbac44f2e3..b0f17918cd8 100644 --- a/homeassistant/components/abode/translations/de.json +++ b/homeassistant/components/abode/translations/de.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "Es ist nur eine einzige Konfiguration von Abode erlaubt." }, - "error": { - "connection_error": "Es kann keine Verbindung zu Abode hergestellt werden.", - "identifier_exists": "Das Konto ist bereits registriert.", - "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/en.json b/homeassistant/components/abode/translations/en.json index 34a1ad27484..36f8bbb10e4 100644 --- a/homeassistant/components/abode/translations/en.json +++ b/homeassistant/components/abode/translations/en.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "Failed to connect", - "connection_error": "Unable to connect to Abode.", - "identifier_exists": "Account already registered.", - "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid credentials." + "invalid_auth": "Invalid authentication" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/es-419.json b/homeassistant/components/abode/translations/es-419.json index ced57c4fdbd..3a7ca7a8cab 100644 --- a/homeassistant/components/abode/translations/es-419.json +++ b/homeassistant/components/abode/translations/es-419.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "Solo se permite una \u00fanica configuraci\u00f3n de Abode." }, - "error": { - "connection_error": "No se puede conectar a Abode.", - "identifier_exists": "Cuenta ya registrada.", - "invalid_credentials": "Credenciales inv\u00e1lidas." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/es.json b/homeassistant/components/abode/translations/es.json index 8d17f040136..2e5d21707b5 100644 --- a/homeassistant/components/abode/translations/es.json +++ b/homeassistant/components/abode/translations/es.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "connection_error": "No se puede conectar a Abode.", - "identifier_exists": "Cuenta ya registrada.", - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_credentials": "Credenciales inv\u00e1lidas." + "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/et.json b/homeassistant/components/abode/translations/et.json index fec80d8679b..7c711e252c8 100644 --- a/homeassistant/components/abode/translations/et.json +++ b/homeassistant/components/abode/translations/et.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "\u00dchendus Abode-iga nurjus.", - "identifier_exists": "Konto on juba seadistatud", - "invalid_auth": "Tuvastamise viga", - "invalid_credentials": "Sobimatu mandaat." + "invalid_auth": "Tuvastamise viga" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/fi.json b/homeassistant/components/abode/translations/fi.json deleted file mode 100644 index f236327a22c..00000000000 --- a/homeassistant/components/abode/translations/fi.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "error": { - "connection_error": "Yhteytt\u00e4 Abodeen ei voi muodostaa." - } - } -} \ No newline at end of file diff --git a/homeassistant/components/abode/translations/fr.json b/homeassistant/components/abode/translations/fr.json index 81056f44fa8..87be79571a4 100644 --- a/homeassistant/components/abode/translations/fr.json +++ b/homeassistant/components/abode/translations/fr.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "\u00c9chec de connexion", - "connection_error": "Impossible de se connecter \u00e0 Abode.", - "identifier_exists": "Compte d\u00e9j\u00e0 enregistr\u00e9.", - "invalid_auth": "Authentification invalide", - "invalid_credentials": "Informations d'identification invalides." + "invalid_auth": "Authentification invalide" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/hu.json b/homeassistant/components/abode/translations/hu.json index 90ca7cafb34..160810c8211 100644 --- a/homeassistant/components/abode/translations/hu.json +++ b/homeassistant/components/abode/translations/hu.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "Csak egyetlen Abode konfigur\u00e1ci\u00f3 enged\u00e9lyezett." }, - "error": { - "connection_error": "Nem lehet csatlakozni az Abode-hez.", - "identifier_exists": "Fi\u00f3k m\u00e1r regisztr\u00e1lva van", - "invalid_credentials": "\u00c9rv\u00e9nytelen hiteles\u00edt\u0151 adatok" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/it.json b/homeassistant/components/abode/translations/it.json index e6a43a31d0d..e1af6d27fc8 100644 --- a/homeassistant/components/abode/translations/it.json +++ b/homeassistant/components/abode/translations/it.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi ad Abode.", - "identifier_exists": "Account gi\u00e0 registrato", - "invalid_auth": "Autenticazione non valida", - "invalid_credentials": "Credenziali non valide" + "invalid_auth": "Autenticazione non valida" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/ko.json b/homeassistant/components/abode/translations/ko.json index a72d461252a..06c301550b4 100644 --- a/homeassistant/components/abode/translations/ko.json +++ b/homeassistant/components/abode/translations/ko.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "\ud558\ub098\uc758 Abode \ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4." }, - "error": { - "connection_error": "Abode \uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", - "identifier_exists": "\uacc4\uc815\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "invalid_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ud639\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/lb.json b/homeassistant/components/abode/translations/lb.json index f8021a1ab51..8a6d671b7f0 100644 --- a/homeassistant/components/abode/translations/lb.json +++ b/homeassistant/components/abode/translations/lb.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun ZHA ass erlaabt." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { "cannot_connect": "Feeler beim verbannen", - "connection_error": "Kann sech net mat Abode verbannen.", - "identifier_exists": "Konto ass scho registr\u00e9iert", - "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_credentials": "Ong\u00eblteg Login Informatioune" + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/nl.json b/homeassistant/components/abode/translations/nl.json index aa143794d2b..9ef9c74aa1a 100644 --- a/homeassistant/components/abode/translations/nl.json +++ b/homeassistant/components/abode/translations/nl.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met Abode.", - "identifier_exists": "Account is al geregistreerd.", - "invalid_credentials": "Ongeldige inloggegevens." + "invalid_auth": "Ongeldige authenticatie" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/no.json b/homeassistant/components/abode/translations/no.json index 40d649546f2..cda0a6aa221 100644 --- a/homeassistant/components/abode/translations/no.json +++ b/homeassistant/components/abode/translations/no.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kan ikke koble til Abode.", - "identifier_exists": "Kontoen er allerede registrert.", - "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig legitimasjon" + "invalid_auth": "Ugyldig godkjenning" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/pl.json b/homeassistant/components/abode/translations/pl.json index c06cb0bbb35..8331a58090f 100644 --- a/homeassistant/components/abode/translations/pl.json +++ b/homeassistant/components/abode/translations/pl.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z Abode", - "identifier_exists": "Konto jest ju\u017c zarejestrowane", - "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce" + "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/pt-BR.json b/homeassistant/components/abode/translations/pt-BR.json index 1f9cf968fb0..4c61f5d243d 100644 --- a/homeassistant/components/abode/translations/pt-BR.json +++ b/homeassistant/components/abode/translations/pt-BR.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "Somente uma \u00fanica configura\u00e7\u00e3o de Abode \u00e9 permitida." }, - "error": { - "connection_error": "N\u00e3o foi poss\u00edvel conectar ao Abode.", - "identifier_exists": "Conta j\u00e1 cadastrada.", - "invalid_credentials": "Credenciais inv\u00e1lidas." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/pt.json b/homeassistant/components/abode/translations/pt.json index 505e1a850ec..0df67a94182 100644 --- a/homeassistant/components/abode/translations/pt.json +++ b/homeassistant/components/abode/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Conta j\u00e1 registada" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/ru.json b/homeassistant/components/abode/translations/ru.json index bec110bb706..2a92a44e1b7 100644 --- a/homeassistant/components/abode/translations/ru.json +++ b/homeassistant/components/abode/translations/ru.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a Abode.", - "identifier_exists": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0430.", - "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_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { "user": { diff --git a/homeassistant/components/abode/translations/sl.json b/homeassistant/components/abode/translations/sl.json index d56b1335390..aa54e582af0 100644 --- a/homeassistant/components/abode/translations/sl.json +++ b/homeassistant/components/abode/translations/sl.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "Dovoljena je samo ena konfiguracija Abode." }, - "error": { - "connection_error": "Ni mogo\u010de vzpostaviti povezave z Abode.", - "identifier_exists": "Ra\u010dun je \u017ee registriran.", - "invalid_credentials": "Neveljavne poverilnice." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/sv.json b/homeassistant/components/abode/translations/sv.json index 40328574ba7..9faf392be51 100644 --- a/homeassistant/components/abode/translations/sv.json +++ b/homeassistant/components/abode/translations/sv.json @@ -3,11 +3,6 @@ "abort": { "single_instance_allowed": "Endast en enda konfiguration av Abode \u00e4r till\u00e5ten." }, - "error": { - "connection_error": "Det gick inte att ansluta till Abode.", - "identifier_exists": "Kontot \u00e4r redan registrerat.", - "invalid_credentials": "Ogiltiga autentiseringsuppgifter." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/abode/translations/zh-Hant.json b/homeassistant/components/abode/translations/zh-Hant.json index 760935accd7..b23eb9d3707 100644 --- a/homeassistant/components/abode/translations/zh-Hant.json +++ b/homeassistant/components/abode/translations/zh-Hant.json @@ -5,10 +5,7 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u7121\u6cd5\u9023\u7dda\u81f3 Abode\u3002", - "identifier_exists": "\u5e33\u865f\u5df2\u8a3b\u518a\u3002", - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u6191\u8b49\u7121\u6548\u3002" + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { "user": { diff --git a/homeassistant/components/accuweather/const.py b/homeassistant/components/accuweather/const.py index 5696a35ea2f..aac37604584 100644 --- a/homeassistant/components/accuweather/const.py +++ b/homeassistant/components/accuweather/const.py @@ -1,6 +1,7 @@ """Constants for AccuWeather integration.""" from homeassistant.const import ( ATTR_DEVICE_CLASS, + CONCENTRATION_PARTS_PER_CUBIC_METER, DEVICE_CLASS_TEMPERATURE, LENGTH_FEET, LENGTH_INCHES, @@ -13,7 +14,6 @@ from homeassistant.const import ( TEMP_FAHRENHEIT, TIME_HOURS, UV_INDEX, - VOLUME_CUBIC_METERS, ) ATTRIBUTION = "Data provided by AccuWeather" @@ -22,7 +22,6 @@ ATTR_FORECAST = CONF_FORECAST = "forecast" ATTR_LABEL = "label" ATTR_UNIT_IMPERIAL = "Imperial" ATTR_UNIT_METRIC = "Metric" -CONCENTRATION_PARTS_PER_CUBIC_METER = f"p/{VOLUME_CUBIC_METERS}" COORDINATOR = "coordinator" DOMAIN = "accuweather" MANUFACTURER = "AccuWeather, Inc." diff --git a/homeassistant/components/accuweather/translations/de.json b/homeassistant/components/accuweather/translations/de.json index 320c834e920..9291e17e865 100644 --- a/homeassistant/components/accuweather/translations/de.json +++ b/homeassistant/components/accuweather/translations/de.json @@ -4,7 +4,8 @@ "user": { "data": { "latitude": "Breitengrad", - "longitude": "L\u00e4ngengrad" + "longitude": "L\u00e4ngengrad", + "name": "Name" }, "title": "AccuWeather" } diff --git a/homeassistant/components/accuweather/translations/lb.json b/homeassistant/components/accuweather/translations/lb.json index fecb7e62a6f..e1a9306e004 100644 --- a/homeassistant/components/accuweather/translations/lb.json +++ b/homeassistant/components/accuweather/translations/lb.json @@ -16,7 +16,7 @@ "longitude": "L\u00e4ngegrad", "name": "Numm" }, - "description": "Falls du H\u00ebllef mat der Konfiguratioun brauch kuck h\u00e9i:\nhttps://www.home-assistant.io/integrations/accuweather/\n\nWieder Pr\u00e9visounen si standardm\u00e9isseg net aktiv. Du kanns d\u00e9i an den Optioune vun der Integratioun aschalten.", + "description": "Falls du H\u00ebllef mat der Konfiguratioun brauch kuck h\u00e9i:\nhttps://www.home-assistant.io/integrations/accuweather/\n\nVerschidde Sensoren si standardm\u00e9isseg net aktiv. Du kanns d\u00e9i an der Entit\u00e9ie Registry no der Konfiguratioun vun der Integratioun aschalten.\n\nWieder Pr\u00e9visounen si standardm\u00e9isseg net aktiv. Du kanns d\u00e9i an den Optioune vun der Integratioun aschalten.", "title": "AccuWeather" } } diff --git a/homeassistant/components/accuweather/translations/nl.json b/homeassistant/components/accuweather/translations/nl.json index 5173004cea6..ff0d81f94d3 100644 --- a/homeassistant/components/accuweather/translations/nl.json +++ b/homeassistant/components/accuweather/translations/nl.json @@ -1,11 +1,30 @@ { "config": { + "error": { + "invalid_api_key": "API-sleutel", + "requests_exceeded": "Het toegestane aantal verzoeken aan de Accuweather API is overschreden. U moet wachten of de API-sleutel wijzigen." + }, "step": { "user": { "data": { + "api_key": "API-sleutel", + "latitude": "Breedtegraad", "longitude": "Lengtegraad", "name": "Naam" - } + }, + "description": "Als je hulp nodig hebt bij de configuratie, kijk dan hier: https://www.home-assistant.io/integrations/accuweather/ \n\n Sommige sensoren zijn niet standaard ingeschakeld. U kunt ze inschakelen in het entiteitenregister na de integratieconfiguratie.\n Weersvoorspelling is niet standaard ingeschakeld. U kunt het inschakelen in de integratieopties.", + "title": "AccuWeather" + } + } + }, + "options": { + "step": { + "user": { + "data": { + "forecast": "Weervoorspelling" + }, + "description": "Vanwege de beperkingen van de gratis versie van de AccuWeather API-sleutel, worden gegevensupdates elke 64 minuten in plaats van elke 32 minuten uitgevoerd wanneer u weersvoorspelling inschakelt.", + "title": "AccuWeather-opties" } } } diff --git a/homeassistant/components/accuweather/translations/no.json b/homeassistant/components/accuweather/translations/no.json index b90baf17be9..78a0d22878a 100644 --- a/homeassistant/components/accuweather/translations/no.json +++ b/homeassistant/components/accuweather/translations/no.json @@ -16,7 +16,7 @@ "longitude": "Lengdegrad", "name": "Navn" }, - "description": "Hvis du trenger hjelp med konfigurasjonen, kan du se her: https://www.home-assistant.io/integrations/accuweather/ \n\n Noen sensorer er ikke aktivert som standard. Du kan aktivere dem i enhetsregisteret etter integrasjonskonfigurasjonen. \n V\u00e6rmelding er ikke aktivert som standard. Du kan aktivere det i integrasjonsalternativene.", + "description": "Hvis du trenger hjelp med konfigurasjonen, kan du se her: https://www.home-assistant.io/integrations/accuweather/ \n\nNoen sensorer er ikke aktivert som standard. Du kan aktivere dem i entitetsregisteret etter integrasjonskonfigurasjonen. \nV\u00e6rmelding er ikke aktivert som standard. Du kan aktivere det i integrasjonsalternativene.", "title": "" } } diff --git a/homeassistant/components/accuweather/translations/sensor.nl.json b/homeassistant/components/accuweather/translations/sensor.nl.json new file mode 100644 index 00000000000..4360149ccc4 --- /dev/null +++ b/homeassistant/components/accuweather/translations/sensor.nl.json @@ -0,0 +1,9 @@ +{ + "state": { + "accuweather__pressure_tendency": { + "falling": "Ondergang", + "rising": "Opkomst", + "steady": "Stabiel" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/acmeda/strings.json b/homeassistant/components/acmeda/strings.json index a2209fe1a88..f6c94581052 100644 --- a/homeassistant/components/acmeda/strings.json +++ b/homeassistant/components/acmeda/strings.json @@ -1,5 +1,4 @@ { - "title": "Rollease Acmeda Automate", "config": { "step": { "user": { diff --git a/homeassistant/components/acmeda/translations/ca.json b/homeassistant/components/acmeda/translations/ca.json index 2481794f8f2..3c31dac301d 100644 --- a/homeassistant/components/acmeda/translations/ca.json +++ b/homeassistant/components/acmeda/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "No s'han descobert nous hubs de Pulse.", "no_devices_found": "No s'han trobat dispositius a la xarxa" }, "step": { @@ -12,6 +11,5 @@ "title": "Selecci\u00f3 del Hub a afegir" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/cs.json b/homeassistant/components/acmeda/translations/cs.json index 3f0012e00d2..3f392ed0347 100644 --- a/homeassistant/components/acmeda/translations/cs.json +++ b/homeassistant/components/acmeda/translations/cs.json @@ -2,6 +2,13 @@ "config": { "abort": { "no_devices_found": "V s\u00edti nebyla nalezena \u017e\u00e1dn\u00e1 za\u0159\u00edzen\u00ed" + }, + "step": { + "user": { + "data": { + "id": "ID hostitele" + } + } } } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/en.json b/homeassistant/components/acmeda/translations/en.json index 77768f20d69..1447785f078 100644 --- a/homeassistant/components/acmeda/translations/en.json +++ b/homeassistant/components/acmeda/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "No new Pulse hubs discovered.", "no_devices_found": "No devices found on the network" }, "step": { @@ -12,6 +11,5 @@ "title": "Pick a hub to add" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/es.json b/homeassistant/components/acmeda/translations/es.json index dcdd885fe26..6e336c0315b 100644 --- a/homeassistant/components/acmeda/translations/es.json +++ b/homeassistant/components/acmeda/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "No se han descubierto nuevos hubs Pulse.", "no_devices_found": "No se encontraron dispositivos en la red" }, "step": { @@ -12,6 +11,5 @@ "title": "Elige un hub para a\u00f1adir" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/et.json b/homeassistant/components/acmeda/translations/et.json index 8f5881d9717..2d1b37de6aa 100644 --- a/homeassistant/components/acmeda/translations/et.json +++ b/homeassistant/components/acmeda/translations/et.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "Uusi Pulse'i jaotureid ei avastatud.", "no_devices_found": "V\u00f5rgus ei tuvastatud \u00fchtegi seadet" }, "step": { @@ -12,6 +11,5 @@ "title": "Vali lisatav jaotur" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/fr.json b/homeassistant/components/acmeda/translations/fr.json index 8270b13d76e..3ae9ff4234a 100644 --- a/homeassistant/components/acmeda/translations/fr.json +++ b/homeassistant/components/acmeda/translations/fr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "Aucun nouveau hub Pulse n'a \u00e9t\u00e9 d\u00e9couvert.", "no_devices_found": "Aucun appareil trouv\u00e9 sur le r\u00e9seau" }, "step": { @@ -12,6 +11,5 @@ "title": "Choisissez un hub \u00e0 ajouter" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/it.json b/homeassistant/components/acmeda/translations/it.json index dbf92d54db9..8592e6cc8da 100644 --- a/homeassistant/components/acmeda/translations/it.json +++ b/homeassistant/components/acmeda/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "Non sono stati scoperti nuovi hub Pulse.", "no_devices_found": "Nessun dispositivo trovato sulla rete" }, "step": { @@ -12,6 +11,5 @@ "title": "Scegliere un hub da aggiungere" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/ko.json b/homeassistant/components/acmeda/translations/ko.json index cc79dada5bd..345628eef02 100644 --- a/homeassistant/components/acmeda/translations/ko.json +++ b/homeassistant/components/acmeda/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "all_configured": "\ubc1c\uacac\ub41c \uc0c8\ub85c\uc6b4 Pulse \ud5c8\ube0c\uac00 \uc5c6\uc2b5\ub2c8\ub2e4." - }, "step": { "user": { "data": { @@ -11,6 +8,5 @@ "title": "\ucd94\uac00\ud560 \ud5c8\ube0c \uc120\ud0dd\ud558\uae30" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/lb.json b/homeassistant/components/acmeda/translations/lb.json index 27ae3072de5..8d5bfcf0edb 100644 --- a/homeassistant/components/acmeda/translations/lb.json +++ b/homeassistant/components/acmeda/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "all_configured": "Keng nei Pulse Hubs entdeckt." + "no_devices_found": "Keng Apparater am Netzwierk fonnt" }, "step": { "user": { @@ -11,6 +11,5 @@ "title": "Wiel den Hub aus dee soll dob\u00e4igesat ginn." } } - }, - "title": "Rollease ACmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/nl.json b/homeassistant/components/acmeda/translations/nl.json index 76b680a5f8c..470e0f8f698 100644 --- a/homeassistant/components/acmeda/translations/nl.json +++ b/homeassistant/components/acmeda/translations/nl.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "all_configured": "Geen nieuwe Pulse hubs ontdekt." - }, "step": { "user": { "data": { @@ -11,6 +8,5 @@ "title": "Kies een hub om toe te voegen" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/no.json b/homeassistant/components/acmeda/translations/no.json index 8ecb4ef889d..51eb5668bc9 100644 --- a/homeassistant/components/acmeda/translations/no.json +++ b/homeassistant/components/acmeda/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "Ingen nye Pulse-hub oppdaget.", "no_devices_found": "Ingen enheter funnet p\u00e5 nettverket" }, "step": { @@ -12,6 +11,5 @@ "title": "Velg en hub du vil legge til" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/pl.json b/homeassistant/components/acmeda/translations/pl.json index e2e68b4b327..bdc14d83bfb 100644 --- a/homeassistant/components/acmeda/translations/pl.json +++ b/homeassistant/components/acmeda/translations/pl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "Nie wykryto hub\u00f3w Pulse", "no_devices_found": "Nie znaleziono urz\u0105dze\u0144 w sieci" }, "step": { @@ -12,6 +11,5 @@ "title": "Wybierz hub, kt\u00f3ry chcesz doda\u0107" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/ru.json b/homeassistant/components/acmeda/translations/ru.json index b11fd876975..14114706bd9 100644 --- a/homeassistant/components/acmeda/translations/ru.json +++ b/homeassistant/components/acmeda/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u044b.", "no_devices_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u0441\u0435\u0442\u0438." }, "step": { @@ -12,6 +11,5 @@ "title": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0445\u0430\u0431, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/acmeda/translations/zh-Hant.json b/homeassistant/components/acmeda/translations/zh-Hant.json index e5f29fbb4bd..1e7d4d0f14e 100644 --- a/homeassistant/components/acmeda/translations/zh-Hant.json +++ b/homeassistant/components/acmeda/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "all_configured": "\u672a\u641c\u5c0b\u5230 Pulse hub", "no_devices_found": "\u7db2\u8def\u4e0a\u627e\u4e0d\u5230\u8a2d\u5099" }, "step": { @@ -12,6 +11,5 @@ "title": "\u9078\u64c7\u6240\u8981\u65b0\u589e\u7684 Hub" } } - }, - "title": "Rollease Acmeda Automate" + } } \ No newline at end of file diff --git a/homeassistant/components/adguard/translations/bg.json b/homeassistant/components/adguard/translations/bg.json index 46fdb6f0c96..1edfc9d8da6 100644 --- a/homeassistant/components/adguard/translations/bg.json +++ b/homeassistant/components/adguard/translations/bg.json @@ -4,9 +4,6 @@ "existing_instance_updated": "\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430\u0449\u0430\u0442\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f.", "single_instance_allowed": "\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430 AdGuard Home." }, - "error": { - "connection_error": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435." - }, "step": { "hassio_confirm": { "description": "\u0418\u0441\u043a\u0430\u0442\u0435 \u043b\u0438 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 Home Assistant \u0434\u0430 \u0441\u0435 \u0441\u0432\u044a\u0440\u0437\u0432\u0430 \u0441 AdGuard Home, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0435\u043d \u043e\u0442 Hass.io \u0434\u043e\u0431\u0430\u0432\u043a\u0430\u0442\u0430: {addon} ?", diff --git a/homeassistant/components/adguard/translations/ca.json b/homeassistant/components/adguard/translations/ca.json index aec7f6fc2da..422fde9479a 100644 --- a/homeassistant/components/adguard/translations/ca.json +++ b/homeassistant/components/adguard/translations/ca.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/adguard/translations/cs.json b/homeassistant/components/adguard/translations/cs.json index 1677e73d494..27b9d291fc2 100644 --- a/homeassistant/components/adguard/translations/cs.json +++ b/homeassistant/components/adguard/translations/cs.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "hassio_confirm": { @@ -21,7 +20,8 @@ "ssl": "Pou\u017e\u00edv\u00e1 SSL certifik\u00e1t", "username": "U\u017eivatelsk\u00e9 jm\u00e9no", "verify_ssl": "Ov\u011b\u0159it certifik\u00e1t SSL" - } + }, + "description": "Nastavte svou instanci AdGuard Home pro monitorov\u00e1n\u00ed a \u0159\u00edzen\u00ed." } } } diff --git a/homeassistant/components/adguard/translations/da.json b/homeassistant/components/adguard/translations/da.json index edc33cd7927..927fd03d50a 100644 --- a/homeassistant/components/adguard/translations/da.json +++ b/homeassistant/components/adguard/translations/da.json @@ -4,9 +4,6 @@ "existing_instance_updated": "Opdaterede eksisterende konfiguration.", "single_instance_allowed": "Kun en enkelt konfiguration af AdGuard Home er tilladt." }, - "error": { - "connection_error": "Forbindelse mislykkedes." - }, "step": { "hassio_confirm": { "description": "Vil du konfigurere Home Assistant til at oprette forbindelse til AdGuard Home leveret af Hass.io-tilf\u00f8jelsen: {addon}?", diff --git a/homeassistant/components/adguard/translations/de.json b/homeassistant/components/adguard/translations/de.json index 4de9d34f134..78db52ade45 100644 --- a/homeassistant/components/adguard/translations/de.json +++ b/homeassistant/components/adguard/translations/de.json @@ -4,9 +4,6 @@ "existing_instance_updated": "Bestehende Konfiguration wurde aktualisiert.", "single_instance_allowed": "Es ist nur eine einzige Konfiguration von AdGuard Home zul\u00e4ssig." }, - "error": { - "connection_error": "Fehler beim Herstellen einer Verbindung." - }, "step": { "hassio_confirm": { "description": "M\u00f6chtest du Home Assistant so konfigurieren, dass eine Verbindung mit AdGuard Home als Hass.io-Add-On hergestellt wird: {addon}?", diff --git a/homeassistant/components/adguard/translations/en.json b/homeassistant/components/adguard/translations/en.json index e0c1f6d7a0b..6c1ad2008ce 100644 --- a/homeassistant/components/adguard/translations/en.json +++ b/homeassistant/components/adguard/translations/en.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Already configured. Only a single configuration possible." }, "error": { - "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect." + "cannot_connect": "Failed to connect" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/adguard/translations/es-419.json b/homeassistant/components/adguard/translations/es-419.json index 8e6ee0ab41d..5efdfae1802 100644 --- a/homeassistant/components/adguard/translations/es-419.json +++ b/homeassistant/components/adguard/translations/es-419.json @@ -4,9 +4,6 @@ "existing_instance_updated": "Se actualiz\u00f3 la configuraci\u00f3n existente.", "single_instance_allowed": "Solo se permite una \u00fanica configuraci\u00f3n de AdGuard Home." }, - "error": { - "connection_error": "Error al conectar." - }, "step": { "hassio_confirm": { "description": "\u00bfDesea configurar Home Assistant para conectarse a la p\u00e1gina principal de AdGuard proporcionada por el complemento Hass.io: {addon}?", diff --git a/homeassistant/components/adguard/translations/es.json b/homeassistant/components/adguard/translations/es.json index b6c275a401c..a165a9b1c09 100644 --- a/homeassistant/components/adguard/translations/es.json +++ b/homeassistant/components/adguard/translations/es.json @@ -5,8 +5,7 @@ "single_instance_allowed": "S\u00f3lo se permite una \u00fanica configuraci\u00f3n de AdGuard Home." }, "error": { - "cannot_connect": "No se pudo conectar", - "connection_error": "No se conect\u00f3." + "cannot_connect": "No se pudo conectar" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/adguard/translations/et.json b/homeassistant/components/adguard/translations/et.json index 4f950ebb748..3408d752522 100644 --- a/homeassistant/components/adguard/translations/et.json +++ b/homeassistant/components/adguard/translations/et.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "error": { - "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "\u00dchenduse loomine nurjus" + "cannot_connect": "\u00dchendamine nurjus" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/adguard/translations/fi.json b/homeassistant/components/adguard/translations/fi.json index 4765338a5e3..fe41954e79b 100644 --- a/homeassistant/components/adguard/translations/fi.json +++ b/homeassistant/components/adguard/translations/fi.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "connection_error": "Yhdist\u00e4minen ep\u00e4onnistui." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/adguard/translations/fr.json b/homeassistant/components/adguard/translations/fr.json index 43cee03560c..613145ec0f2 100644 --- a/homeassistant/components/adguard/translations/fr.json +++ b/homeassistant/components/adguard/translations/fr.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Une seule configuration d'AdGuard Home est autoris\u00e9e." }, "error": { - "cannot_connect": "\u00c9chec de connexion", - "connection_error": "\u00c9chec de connexion." + "cannot_connect": "\u00c9chec de connexion" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/adguard/translations/id.json b/homeassistant/components/adguard/translations/id.json index c8357cad0f6..c5d61d91df0 100644 --- a/homeassistant/components/adguard/translations/id.json +++ b/homeassistant/components/adguard/translations/id.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "connection_error": "Gagal terhubung." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/adguard/translations/it.json b/homeassistant/components/adguard/translations/it.json index ff37f64aefc..3df01316aa1 100644 --- a/homeassistant/components/adguard/translations/it.json +++ b/homeassistant/components/adguard/translations/it.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "error": { - "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi." + "cannot_connect": "Impossibile connettersi" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/adguard/translations/ko.json b/homeassistant/components/adguard/translations/ko.json index 9c0a7b8fbba..e17bca1f0a2 100644 --- a/homeassistant/components/adguard/translations/ko.json +++ b/homeassistant/components/adguard/translations/ko.json @@ -4,9 +4,6 @@ "existing_instance_updated": "\uae30\uc874 \uad6c\uc131\uc744 \uc5c5\ub370\uc774\ud2b8\ud588\uc2b5\ub2c8\ub2e4.", "single_instance_allowed": "\ud558\ub098\uc758 AdGuard Home \ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4." }, - "error": { - "connection_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4." - }, "step": { "hassio_confirm": { "description": "Hass.io {addon} \uc560\ub4dc\uc628\uc73c\ub85c AdGuard Home \uc5d0 \uc5f0\uacb0\ud558\ub3c4\ub85d Home Assistant \ub97c \uad6c\uc131\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?", diff --git a/homeassistant/components/adguard/translations/lb.json b/homeassistant/components/adguard/translations/lb.json index 860abfeb27f..135451c061f 100644 --- a/homeassistant/components/adguard/translations/lb.json +++ b/homeassistant/components/adguard/translations/lb.json @@ -2,11 +2,10 @@ "config": { "abort": { "existing_instance_updated": "D\u00e9i bestehend Konfiguratioun ass ge\u00e4nnert.", - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun AdGuard Home ass erlaabt." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { - "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen." + "cannot_connect": "Feeler beim verbannen" }, "step": { "hassio_confirm": { @@ -18,9 +17,9 @@ "host": "Host", "password": "Passwuert", "port": "Port", - "ssl": "AdGuard Home benotzt een SSL Zertifikat", + "ssl": "Benotzt een SSL Zertifikat", "username": "Benotzernumm", - "verify_ssl": "AdGuard Home benotzt een eegenen Zertifikat" + "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" }, "description": "Konfigur\u00e9iert \u00e4r AdGuard Home Instanz fir d'Iwwerwaachung an d'Kontroll z'erlaben." } diff --git a/homeassistant/components/adguard/translations/nl.json b/homeassistant/components/adguard/translations/nl.json index 6451028e6d0..4c735333932 100644 --- a/homeassistant/components/adguard/translations/nl.json +++ b/homeassistant/components/adguard/translations/nl.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Slechts \u00e9\u00e9n configuratie van AdGuard Home is toegestaan." }, "error": { - "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kon niet verbinden." + "cannot_connect": "Kan geen verbinding maken" }, "step": { "hassio_confirm": { @@ -15,6 +14,7 @@ }, "user": { "data": { + "host": "Host", "password": "Wachtwoord", "port": "Poort", "ssl": "AdGuard Home maakt gebruik van een SSL certificaat", diff --git a/homeassistant/components/adguard/translations/no.json b/homeassistant/components/adguard/translations/no.json index d1f08720df1..f5aeea990c3 100644 --- a/homeassistant/components/adguard/translations/no.json +++ b/homeassistant/components/adguard/translations/no.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes." + "cannot_connect": "Tilkobling mislyktes" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/adguard/translations/pl.json b/homeassistant/components/adguard/translations/pl.json index 9991e30859a..2f8a134c04d 100644 --- a/homeassistant/components/adguard/translations/pl.json +++ b/homeassistant/components/adguard/translations/pl.json @@ -5,8 +5,7 @@ "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/adguard/translations/pt-BR.json b/homeassistant/components/adguard/translations/pt-BR.json index 57174a4cf3e..ae8899bb1a7 100644 --- a/homeassistant/components/adguard/translations/pt-BR.json +++ b/homeassistant/components/adguard/translations/pt-BR.json @@ -4,9 +4,6 @@ "existing_instance_updated": "Configura\u00e7\u00e3o existente atualizada.", "single_instance_allowed": "Apenas uma \u00fanica configura\u00e7\u00e3o do AdGuard Home \u00e9 permitida." }, - "error": { - "connection_error": "Falhou ao conectar." - }, "step": { "hassio_confirm": { "description": "Deseja configurar o Home Assistant para se conectar ao AdGuard Home fornecido pelo complemento Hass.io: {addon} ?", diff --git a/homeassistant/components/adguard/translations/pt.json b/homeassistant/components/adguard/translations/pt.json index 841abaf727f..6f56d996b63 100644 --- a/homeassistant/components/adguard/translations/pt.json +++ b/homeassistant/components/adguard/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "connection_error": "Falha na liga\u00e7\u00e3o" - }, "step": { "hassio_confirm": { "title": "AdGuard Home via Hass.io add-on" diff --git a/homeassistant/components/adguard/translations/ru.json b/homeassistant/components/adguard/translations/ru.json index 175d0bc1d5a..34c56342b5b 100644 --- a/homeassistant/components/adguard/translations/ru.json +++ b/homeassistant/components/adguard/translations/ru.json @@ -5,13 +5,12 @@ "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "hassio_confirm": { - "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 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a AdGuard Home (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", - "title": "AdGuard Home (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io)" + "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 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a AdGuard Home (\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", + "title": "AdGuard Home (\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io)" }, "user": { "data": { diff --git a/homeassistant/components/adguard/translations/sl.json b/homeassistant/components/adguard/translations/sl.json index 11c21a8bcc9..06ad40a17d6 100644 --- a/homeassistant/components/adguard/translations/sl.json +++ b/homeassistant/components/adguard/translations/sl.json @@ -4,9 +4,6 @@ "existing_instance_updated": "Posodobljena obstoje\u010da konfiguracija.", "single_instance_allowed": "Dovoljena je samo ena konfiguracija AdGuard Home." }, - "error": { - "connection_error": "Povezava ni uspela." - }, "step": { "hassio_confirm": { "description": "\u017delite konfigurirati Home Assistant-a za povezavo z AdGuard Home, ki ga ponuja Hass.io add-on {addon} ?", diff --git a/homeassistant/components/adguard/translations/sv.json b/homeassistant/components/adguard/translations/sv.json index 98aa6c2a9c0..5b9a0f9a969 100644 --- a/homeassistant/components/adguard/translations/sv.json +++ b/homeassistant/components/adguard/translations/sv.json @@ -4,9 +4,6 @@ "existing_instance_updated": "Uppdaterade existerande konfiguration.", "single_instance_allowed": "Endast en enda konfiguration av AdGuard Home \u00e4r till\u00e5ten." }, - "error": { - "connection_error": "Det gick inte att ansluta." - }, "step": { "hassio_confirm": { "description": "Vill du konfigurera Home Assistant f\u00f6r att ansluta till AdGuard Home som tillhandah\u00e5lls av Hass.io Add-on: {addon}?", diff --git a/homeassistant/components/adguard/translations/zh-Hans.json b/homeassistant/components/adguard/translations/zh-Hans.json index 64a68e91877..4204beb5268 100644 --- a/homeassistant/components/adguard/translations/zh-Hans.json +++ b/homeassistant/components/adguard/translations/zh-Hans.json @@ -3,9 +3,6 @@ "abort": { "existing_instance_updated": "\u66f4\u65b0\u4e86\u73b0\u6709\u914d\u7f6e\u3002" }, - "error": { - "connection_error": "\u8fde\u63a5\u5931\u8d25\u3002" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/adguard/translations/zh-Hant.json b/homeassistant/components/adguard/translations/zh-Hant.json index b883b0a01ba..b5c6863a94d 100644 --- a/homeassistant/components/adguard/translations/zh-Hant.json +++ b/homeassistant/components/adguard/translations/zh-Hant.json @@ -5,8 +5,7 @@ "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/ads/light.py b/homeassistant/components/ads/light.py index 82ead5fbf59..80ee5df0c4b 100644 --- a/homeassistant/components/ads/light.py +++ b/homeassistant/components/ads/light.py @@ -68,10 +68,9 @@ class AdsLight(AdsEntity, LightEntity): @property def supported_features(self): """Flag supported features.""" - support = 0 if self._ads_var_brightness is not None: - support = SUPPORT_BRIGHTNESS - return support + return SUPPORT_BRIGHTNESS + return 0 @property def is_on(self): diff --git a/homeassistant/components/advantage_air/strings.json b/homeassistant/components/advantage_air/strings.json index c8b9cd1dc5f..76ecb174f6d 100644 --- a/homeassistant/components/advantage_air/strings.json +++ b/homeassistant/components/advantage_air/strings.json @@ -1,6 +1,5 @@ { "config": { - "flow_title": "Advantage Air Setup", "error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" }, @@ -17,6 +16,5 @@ "title": "Connect" } } - }, - "title": "Advantage Air" -} \ No newline at end of file + } +} diff --git a/homeassistant/components/advantage_air/translations/ca.json b/homeassistant/components/advantage_air/translations/ca.json index 80d023a672b..7702b3b0588 100644 --- a/homeassistant/components/advantage_air/translations/ca.json +++ b/homeassistant/components/advantage_air/translations/ca.json @@ -6,7 +6,6 @@ "error": { "cannot_connect": "Ha fallat la connexi\u00f3" }, - "flow_title": "Configuraci\u00f3 d'Advantage Air", "step": { "user": { "data": { @@ -17,6 +16,5 @@ "title": "Connecta" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/cs.json b/homeassistant/components/advantage_air/translations/cs.json index d4dc0b3a5ae..e7823abb4f5 100644 --- a/homeassistant/components/advantage_air/translations/cs.json +++ b/homeassistant/components/advantage_air/translations/cs.json @@ -6,16 +6,15 @@ "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, - "flow_title": "Nastaven\u00ed Advantage Air", "step": { "user": { "data": { "ip_address": "IP adresa", "port": "Port" }, + "description": "P\u0159ipojte se k API va\u0161eho n\u00e1st\u011bnn\u00e9ho tabletu Advantage Air.", "title": "P\u0159ipojit" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/en.json b/homeassistant/components/advantage_air/translations/en.json index 209ba946545..de715c3ae1b 100644 --- a/homeassistant/components/advantage_air/translations/en.json +++ b/homeassistant/components/advantage_air/translations/en.json @@ -6,7 +6,6 @@ "error": { "cannot_connect": "Failed to connect" }, - "flow_title": "Advantage Air Setup", "step": { "user": { "data": { @@ -17,6 +16,5 @@ "title": "Connect" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/es.json b/homeassistant/components/advantage_air/translations/es.json index d3234a85c2e..8cd125526df 100644 --- a/homeassistant/components/advantage_air/translations/es.json +++ b/homeassistant/components/advantage_air/translations/es.json @@ -6,7 +6,6 @@ "error": { "cannot_connect": "No se pudo conectar" }, - "flow_title": "Configuraci\u00f3n de Advantage Air", "step": { "user": { "data": { @@ -17,6 +16,5 @@ "title": "Conectar" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/et.json b/homeassistant/components/advantage_air/translations/et.json index a4419dfcd6e..900265465e8 100644 --- a/homeassistant/components/advantage_air/translations/et.json +++ b/homeassistant/components/advantage_air/translations/et.json @@ -6,7 +6,6 @@ "error": { "cannot_connect": "\u00dchendus nurjus" }, - "flow_title": "Advantage Air-i seadistamine", "step": { "user": { "data": { @@ -17,6 +16,5 @@ "title": "\u00dchenda" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/fr.json b/homeassistant/components/advantage_air/translations/fr.json new file mode 100644 index 00000000000..e5f6c52ee2c --- /dev/null +++ b/homeassistant/components/advantage_air/translations/fr.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" + }, + "error": { + "cannot_connect": "\u00c9chec de connexion" + }, + "step": { + "user": { + "data": { + "ip_address": "Adresse IP", + "port": "Port" + }, + "description": "Connectez-vous \u00e0 l'API de votre tablette murale Advantage Air.", + "title": "Connecter" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/it.json b/homeassistant/components/advantage_air/translations/it.json index a755c3e1f00..c9ea54d85dc 100644 --- a/homeassistant/components/advantage_air/translations/it.json +++ b/homeassistant/components/advantage_air/translations/it.json @@ -6,7 +6,6 @@ "error": { "cannot_connect": "Impossibile connettersi" }, - "flow_title": "Configurazione di Advantage Air", "step": { "user": { "data": { @@ -17,6 +16,5 @@ "title": "Connetti" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/lb.json b/homeassistant/components/advantage_air/translations/lb.json new file mode 100644 index 00000000000..48e58149930 --- /dev/null +++ b/homeassistant/components/advantage_air/translations/lb.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_configured": "Apparat ass scho konfigur\u00e9iert" + }, + "error": { + "cannot_connect": "Feeler beim verbannen" + }, + "step": { + "user": { + "data": { + "ip_address": "IP Adresse", + "port": "Port" + }, + "description": "Mat der API vun dengem Advantage Air Tablet verbannen", + "title": "Verbannen" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/nl.json b/homeassistant/components/advantage_air/translations/nl.json index 554163d3278..95395d24bca 100644 --- a/homeassistant/components/advantage_air/translations/nl.json +++ b/homeassistant/components/advantage_air/translations/nl.json @@ -1,13 +1,16 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, "step": { "user": { "data": { "port": "Poort" }, + "description": "Maak verbinding met de API van uw Advantage Air-tablet voor wandmontage.", "title": "Verbind" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/no.json b/homeassistant/components/advantage_air/translations/no.json index a8cb3c0eaee..9ed185a7a7a 100644 --- a/homeassistant/components/advantage_air/translations/no.json +++ b/homeassistant/components/advantage_air/translations/no.json @@ -6,7 +6,6 @@ "error": { "cannot_connect": "Tilkobling mislyktes" }, - "flow_title": "[VOID] oppsett", "step": { "user": { "data": { @@ -17,6 +16,5 @@ "title": "Koble til" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/pl.json b/homeassistant/components/advantage_air/translations/pl.json index 9fb32ac283b..ef2d1909b9f 100644 --- a/homeassistant/components/advantage_air/translations/pl.json +++ b/homeassistant/components/advantage_air/translations/pl.json @@ -6,7 +6,6 @@ "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, - "flow_title": "Konfiguracja Advantage Air", "step": { "user": { "data": { @@ -17,6 +16,5 @@ "title": "Po\u0142\u0105czenie" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/ru.json b/homeassistant/components/advantage_air/translations/ru.json index bb2bdfebc8f..b978329896d 100644 --- a/homeassistant/components/advantage_air/translations/ru.json +++ b/homeassistant/components/advantage_air/translations/ru.json @@ -6,17 +6,15 @@ "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, - "flow_title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Advantage Air", "step": { "user": { "data": { "ip_address": "IP-\u0430\u0434\u0440\u0435\u0441", "port": "\u041f\u043e\u0440\u0442" }, - "description": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u0441\u044c \u043a API \u0412\u0430\u0448\u0435\u0433\u043e \u043d\u0430\u0441\u0442\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043b\u0430\u043d\u0448\u0435\u0442\u0430 Advantage Air.", + "description": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a API \u0412\u0430\u0448\u0435\u0433\u043e \u043d\u0430\u0441\u0442\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043b\u0430\u043d\u0448\u0435\u0442\u0430 Advantage Air.", "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/advantage_air/translations/zh-Hans.json b/homeassistant/components/advantage_air/translations/zh-Hans.json index a25ab477c70..db79116d5ea 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/advantage_air/translations/zh-Hant.json b/homeassistant/components/advantage_air/translations/zh-Hant.json index 68eac9fdf9b..eae6626685d 100644 --- a/homeassistant/components/advantage_air/translations/zh-Hant.json +++ b/homeassistant/components/advantage_air/translations/zh-Hant.json @@ -6,7 +6,6 @@ "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557" }, - "flow_title": "Advantage Air \u8a2d\u5b9a", "step": { "user": { "data": { @@ -17,6 +16,5 @@ "title": "\u9023\u63a5" } } - }, - "title": "Advantage Air" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/strings.json b/homeassistant/components/agent_dvr/strings.json index eb5d8a51763..127fbb69b33 100644 --- a/homeassistant/components/agent_dvr/strings.json +++ b/homeassistant/components/agent_dvr/strings.json @@ -1,5 +1,4 @@ { - "title": "Agent DVR", "config": { "step": { "user": { diff --git a/homeassistant/components/agent_dvr/translations/ca.json b/homeassistant/components/agent_dvr/translations/ca.json index fbd6f5e2d29..36f97cfd53e 100644 --- a/homeassistant/components/agent_dvr/translations/ca.json +++ b/homeassistant/components/agent_dvr/translations/ca.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs", - "cannot_connect": "Ha fallat la connexi\u00f3", - "device_unavailable": "Dispositiu no est\u00e0 disponible" + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Configuraci\u00f3 de Agent DVR" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/cs.json b/homeassistant/components/agent_dvr/translations/cs.json index 88e0dadfed6..8b5c6a4a2aa 100644 --- a/homeassistant/components/agent_dvr/translations/cs.json +++ b/homeassistant/components/agent_dvr/translations/cs.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "device_unavailable": "Za\u0159\u00edzen\u00ed nen\u00ed k dispozici" + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Nastaven\u00ed Agent DVR" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/de.json b/homeassistant/components/agent_dvr/translations/de.json index 7f5588fcb6f..d4f8fc4bcc6 100644 --- a/homeassistant/components/agent_dvr/translations/de.json +++ b/homeassistant/components/agent_dvr/translations/de.json @@ -4,8 +4,7 @@ "already_configured": "Ger\u00e4t ist bereits konfiguriert" }, "error": { - "already_in_progress": "Der Konfigurationsfluss f\u00fcr das Ger\u00e4t wird bereits ausgef\u00fchrt.", - "device_unavailable": "Ger\u00e4t ist nicht verf\u00fcgbar" + "already_in_progress": "Der Konfigurationsfluss f\u00fcr das Ger\u00e4t wird bereits ausgef\u00fchrt." }, "step": { "user": { @@ -16,6 +15,5 @@ "title": "Richten Sie den Agent DVR ein" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/en.json b/homeassistant/components/agent_dvr/translations/en.json index 001cad0ec7c..b295a465600 100644 --- a/homeassistant/components/agent_dvr/translations/en.json +++ b/homeassistant/components/agent_dvr/translations/en.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "Configuration flow is already in progress", - "cannot_connect": "Failed to connect", - "device_unavailable": "Device is not available" + "cannot_connect": "Failed to connect" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Set up Agent DVR" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/es-419.json b/homeassistant/components/agent_dvr/translations/es-419.json index 4b3e1211c31..63be2ce403a 100644 --- a/homeassistant/components/agent_dvr/translations/es-419.json +++ b/homeassistant/components/agent_dvr/translations/es-419.json @@ -4,8 +4,7 @@ "already_configured": "El dispositivo ya est\u00e1 configurado" }, "error": { - "already_in_progress": "El flujo de configuraci\u00f3n para el dispositivo ya est\u00e1 en progreso.", - "device_unavailable": "El dispositivo no est\u00e1 disponible" + "already_in_progress": "El flujo de configuraci\u00f3n para el dispositivo ya est\u00e1 en progreso." }, "step": { "user": { @@ -16,6 +15,5 @@ "title": "Configurar Agent DVR" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/es.json b/homeassistant/components/agent_dvr/translations/es.json index 314846ba2a2..c1771d7e80b 100644 --- a/homeassistant/components/agent_dvr/translations/es.json +++ b/homeassistant/components/agent_dvr/translations/es.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en proceso", - "cannot_connect": "No se pudo conectar", - "device_unavailable": "El dispositivo no est\u00e1 disponible" + "cannot_connect": "No se pudo conectar" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Configurar el Agente de DVR" } } - }, - "title": "Agente DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/et.json b/homeassistant/components/agent_dvr/translations/et.json index 4d67e6ced59..128f446d1a1 100644 --- a/homeassistant/components/agent_dvr/translations/et.json +++ b/homeassistant/components/agent_dvr/translations/et.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "Seadistamine on juba k\u00e4imas", - "cannot_connect": "\u00dchendamine nurjus", - "device_unavailable": "Seade pole saadaval" + "cannot_connect": "\u00dchendamine nurjus" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Seadista Agent DVR" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/fi.json b/homeassistant/components/agent_dvr/translations/fi.json index e824a41aad2..94b3d7c4d6a 100644 --- a/homeassistant/components/agent_dvr/translations/fi.json +++ b/homeassistant/components/agent_dvr/translations/fi.json @@ -4,8 +4,7 @@ "already_configured": "Laite on jo m\u00e4\u00e4ritetty" }, "error": { - "already_in_progress": "Laitteen m\u00e4\u00e4ritysvirta on jo k\u00e4ynniss\u00e4.", - "device_unavailable": "Laite ei ole k\u00e4ytett\u00e4viss\u00e4" + "already_in_progress": "Laitteen m\u00e4\u00e4ritysvirta on jo k\u00e4ynniss\u00e4." }, "step": { "user": { @@ -16,6 +15,5 @@ "title": "Asenna Agent DVR" } } - }, - "title": "Agent DVR" + } } \ 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 a16ad59afee..e78c1da7d8b 100644 --- a/homeassistant/components/agent_dvr/translations/fr.json +++ b/homeassistant/components/agent_dvr/translations/fr.json @@ -5,7 +5,7 @@ }, "error": { "already_in_progress": "La configuration de l'appareil est d\u00e9j\u00e0 en cours.", - "device_unavailable": "L'appareil n'est pas disponible" + "cannot_connect": "\u00c9chec de connexion" }, "step": { "user": { @@ -16,6 +16,5 @@ "title": "Configurer l'agent DVR" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/he.json b/homeassistant/components/agent_dvr/translations/he.json index 3ab81e908ec..6268822a90a 100644 --- a/homeassistant/components/agent_dvr/translations/he.json +++ b/homeassistant/components/agent_dvr/translations/he.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\u05d4\u05de\u05db\u05e9\u05d9\u05e8 \u05db\u05d1\u05e8 \u05de\u05d5\u05d2\u05d3\u05e8" }, - "error": { - "device_unavailable": "\u05d4\u05de\u05db\u05e9\u05d9\u05e8 \u05d0\u05d9\u05e0\u05d5 \u05d6\u05de\u05d9\u05df" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/agent_dvr/translations/it.json b/homeassistant/components/agent_dvr/translations/it.json index b004e7d2d43..8c33cfcc63b 100644 --- a/homeassistant/components/agent_dvr/translations/it.json +++ b/homeassistant/components/agent_dvr/translations/it.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso", - "cannot_connect": "Impossibile connettersi", - "device_unavailable": "Il dispositivo non \u00e8 disponibile" + "cannot_connect": "Impossibile connettersi" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Configurare Agent DVR" } } - }, - "title": "Agente DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/ko.json b/homeassistant/components/agent_dvr/translations/ko.json index dc72c932d69..30b96c00b63 100644 --- a/homeassistant/components/agent_dvr/translations/ko.json +++ b/homeassistant/components/agent_dvr/translations/ko.json @@ -4,8 +4,7 @@ "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "error": { - "already_in_progress": "\uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4.", - "device_unavailable": "\uae30\uae30\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4" + "already_in_progress": "\uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4." }, "step": { "user": { @@ -16,6 +15,5 @@ "title": "Agent DVR \uc124\uc815\ud558\uae30" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/lb.json b/homeassistant/components/agent_dvr/translations/lb.json index 8b56a09a17e..ec552e607f4 100644 --- a/homeassistant/components/agent_dvr/translations/lb.json +++ b/homeassistant/components/agent_dvr/translations/lb.json @@ -4,8 +4,8 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "already_in_progress": "Konfiguratioun's Oflaf fir den Apparat ass schonn am gaangen.", - "device_unavailable": "Apparat ass net erreechbar" + "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaangen.", + "cannot_connect": "Feeler beim verbannen" }, "step": { "user": { @@ -16,6 +16,5 @@ "title": "Agent DVR ariichten" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/nl.json b/homeassistant/components/agent_dvr/translations/nl.json index 79e2caae08d..ad625c169c8 100644 --- a/homeassistant/components/agent_dvr/translations/nl.json +++ b/homeassistant/components/agent_dvr/translations/nl.json @@ -1,13 +1,18 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, "error": { "cannot_connect": "Kan geen verbinding maken" }, "step": { "user": { "data": { + "host": "Host", "port": "Poort" - } + }, + "title": "Stel Agent DVR in" } } } diff --git a/homeassistant/components/agent_dvr/translations/no.json b/homeassistant/components/agent_dvr/translations/no.json index 2068258b894..efe83b8436f 100644 --- a/homeassistant/components/agent_dvr/translations/no.json +++ b/homeassistant/components/agent_dvr/translations/no.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede", - "cannot_connect": "Tilkobling mislyktes", - "device_unavailable": "Enheten er ikke tilgjengelig" + "cannot_connect": "Tilkobling mislyktes" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Konfigurere Agent DVR" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/pl.json b/homeassistant/components/agent_dvr/translations/pl.json index 14c9b00a464..fc97fdfa85a 100644 --- a/homeassistant/components/agent_dvr/translations/pl.json +++ b/homeassistant/components/agent_dvr/translations/pl.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "Konfiguracja jest ju\u017c w toku", - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "device_unavailable": "Urz\u0105dzenie nie jest dost\u0119pne" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Konfiguracja Agent DVR" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/pt-BR.json b/homeassistant/components/agent_dvr/translations/pt-BR.json index 713cdd8cd0b..0077ceddd46 100644 --- a/homeassistant/components/agent_dvr/translations/pt-BR.json +++ b/homeassistant/components/agent_dvr/translations/pt-BR.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "device_unavailable": "O dispositivo n\u00e3o est\u00e1 dispon\u00edvel" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/agent_dvr/translations/ru.json b/homeassistant/components/agent_dvr/translations/ru.json index 20a6eebc73f..7c76fa87813 100644 --- a/homeassistant/components/agent_dvr/translations/ru.json +++ b/homeassistant/components/agent_dvr/translations/ru.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.", - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "device_unavailable": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "Agent DVR" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/sv.json b/homeassistant/components/agent_dvr/translations/sv.json index 537f6c0e11b..cf600b98e96 100644 --- a/homeassistant/components/agent_dvr/translations/sv.json +++ b/homeassistant/components/agent_dvr/translations/sv.json @@ -4,8 +4,7 @@ "already_configured": "Enheten \u00e4r redan konfigurerad" }, "error": { - "already_in_progress": "Konfigurationsfl\u00f6de f\u00f6r enhet p\u00e5g\u00e5r redan.", - "device_unavailable": "Enheten \u00e4r inte tillg\u00e4nglig" + "already_in_progress": "Konfigurationsfl\u00f6de f\u00f6r enhet p\u00e5g\u00e5r redan." }, "step": { "user": { @@ -16,6 +15,5 @@ "title": "Konfigurera DVR Agent" } } - }, - "title": "DVR Agent" + } } \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/zh-Hant.json b/homeassistant/components/agent_dvr/translations/zh-Hant.json index 9acbf536f8d..16de4fd1039 100644 --- a/homeassistant/components/agent_dvr/translations/zh-Hant.json +++ b/homeassistant/components/agent_dvr/translations/zh-Hant.json @@ -5,8 +5,7 @@ }, "error": { "already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d", - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "device_unavailable": "\u8a2d\u5099\u7121\u6cd5\u4f7f\u7528" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "user": { @@ -17,6 +16,5 @@ "title": "\u8a2d\u5b9a Agent DVR" } } - }, - "title": "Agent DVR" + } } \ No newline at end of file diff --git a/homeassistant/components/airly/translations/bg.json b/homeassistant/components/airly/translations/bg.json index d4e7dd2ec28..f0836c8e5ed 100644 --- a/homeassistant/components/airly/translations/bg.json +++ b/homeassistant/components/airly/translations/bg.json @@ -1,7 +1,6 @@ { "config": { "error": { - "auth": "API \u043a\u043b\u044e\u0447\u044a\u0442 \u043d\u0435 \u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d.", "wrong_location": "\u0412 \u0442\u0430\u0437\u0438 \u043e\u0431\u043b\u0430\u0441\u0442 \u043d\u044f\u043c\u0430 \u0438\u0437\u043c\u0435\u0440\u0432\u0430\u0442\u0435\u043b\u043d\u0438 \u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043d\u0430 Airly." }, "step": { diff --git a/homeassistant/components/airly/translations/ca.json b/homeassistant/components/airly/translations/ca.json index 95e26e5b888..2aba1db84c3 100644 --- a/homeassistant/components/airly/translations/ca.json +++ b/homeassistant/components/airly/translations/ca.json @@ -4,7 +4,6 @@ "already_configured": "La ubicaci\u00f3 ja est\u00e0 configurada" }, "error": { - "auth": "La clau API no \u00e9s correcta.", "invalid_api_key": "Clau API inv\u00e0lida", "wrong_location": "No hi ha estacions de mesura Airly en aquesta zona." }, diff --git a/homeassistant/components/airly/translations/cs.json b/homeassistant/components/airly/translations/cs.json index 279f0328274..86d678d31af 100644 --- a/homeassistant/components/airly/translations/cs.json +++ b/homeassistant/components/airly/translations/cs.json @@ -4,7 +4,6 @@ "already_configured": "Um\u00edst\u011bn\u00ed je ji\u017e nastaveno" }, "error": { - "auth": "Kl\u00ed\u010d API nen\u00ed spr\u00e1vn\u00fd.", "invalid_api_key": "Neplatn\u00fd kl\u00ed\u010d API", "wrong_location": "\u017d\u00e1dn\u00e9 m\u011b\u0159ic\u00ed stanice Airly v t\u00e9to oblasti." }, @@ -16,6 +15,7 @@ "longitude": "Zem\u011bpisn\u00e1 d\u00e9lka", "name": "Jm\u00e9no" }, + "description": "Nastavte integraci kvality vzduchu Airly. Chcete-li vygenerovat kl\u00ed\u010d rozhran\u00ed API, p\u0159ejd\u011bte na https://developer.airly.eu/register", "title": "Airly" } } diff --git a/homeassistant/components/airly/translations/da.json b/homeassistant/components/airly/translations/da.json index 5eaaeac8cfc..53b05a38992 100644 --- a/homeassistant/components/airly/translations/da.json +++ b/homeassistant/components/airly/translations/da.json @@ -4,7 +4,6 @@ "already_configured": "Airly-integration for disse koordinater er allerede konfigureret." }, "error": { - "auth": "API-n\u00f8glen er ikke korrekt.", "wrong_location": "Ingen Airly-m\u00e5lestationer i dette omr\u00e5de." }, "step": { diff --git a/homeassistant/components/airly/translations/de.json b/homeassistant/components/airly/translations/de.json index 9816ec75537..19768cad7db 100644 --- a/homeassistant/components/airly/translations/de.json +++ b/homeassistant/components/airly/translations/de.json @@ -4,7 +4,6 @@ "already_configured": "Die Airly-Integration ist f\u00fcr diese Koordinaten bereits konfiguriert." }, "error": { - "auth": "Der API-Schl\u00fcssel ist nicht korrekt.", "wrong_location": "Keine Airly Luftmessstation an diesem Ort" }, "step": { diff --git a/homeassistant/components/airly/translations/en.json b/homeassistant/components/airly/translations/en.json index 620e77f32ca..4aa35c3cada 100644 --- a/homeassistant/components/airly/translations/en.json +++ b/homeassistant/components/airly/translations/en.json @@ -4,7 +4,6 @@ "already_configured": "Location is already configured" }, "error": { - "auth": "API key is not correct.", "invalid_api_key": "Invalid API key", "wrong_location": "No Airly measuring stations in this area." }, diff --git a/homeassistant/components/airly/translations/es-419.json b/homeassistant/components/airly/translations/es-419.json index 43770d1767b..b4bd813d715 100644 --- a/homeassistant/components/airly/translations/es-419.json +++ b/homeassistant/components/airly/translations/es-419.json @@ -4,7 +4,6 @@ "already_configured": "La integraci\u00f3n a\u00e9rea para estas coordenadas ya est\u00e1 configurada." }, "error": { - "auth": "La clave API no es correcta.", "wrong_location": "No hay estaciones de medici\u00f3n Airly en esta \u00e1rea." }, "step": { diff --git a/homeassistant/components/airly/translations/es.json b/homeassistant/components/airly/translations/es.json index 8491b130a4a..4fb6a0905cc 100644 --- a/homeassistant/components/airly/translations/es.json +++ b/homeassistant/components/airly/translations/es.json @@ -4,7 +4,6 @@ "already_configured": "La ubicaci\u00f3n ya est\u00e1 configurada" }, "error": { - "auth": "La clave de la API no es correcta.", "invalid_api_key": "Clave API no v\u00e1lida", "wrong_location": "No hay estaciones de medici\u00f3n Airly en esta zona." }, diff --git a/homeassistant/components/airly/translations/et.json b/homeassistant/components/airly/translations/et.json index 01ed979e0aa..270c97004f8 100644 --- a/homeassistant/components/airly/translations/et.json +++ b/homeassistant/components/airly/translations/et.json @@ -4,7 +4,6 @@ "already_configured": "Asukoht on juba m\u00e4\u00e4ratud" }, "error": { - "auth": "API v\u00f5ti on vale.", "invalid_api_key": "Vigane API v\u00f5ti", "wrong_location": "Selles piirkonnas pole Airly m\u00f5\u00f5tejaamu." }, diff --git a/homeassistant/components/airly/translations/fr.json b/homeassistant/components/airly/translations/fr.json index 4259112dbc9..5ac31e130f9 100644 --- a/homeassistant/components/airly/translations/fr.json +++ b/homeassistant/components/airly/translations/fr.json @@ -4,7 +4,6 @@ "already_configured": "L'int\u00e9gration des coordonn\u00e9es d'Airly est d\u00e9j\u00e0 configur\u00e9." }, "error": { - "auth": "La cl\u00e9 API n'est pas correcte.", "invalid_api_key": "Cl\u00e9 API invalide", "wrong_location": "Aucune station de mesure Airly dans cette zone." }, diff --git a/homeassistant/components/airly/translations/hu.json b/homeassistant/components/airly/translations/hu.json index b6b6790c1e0..b96734935a0 100644 --- a/homeassistant/components/airly/translations/hu.json +++ b/homeassistant/components/airly/translations/hu.json @@ -4,7 +4,6 @@ "already_configured": "Ezen koordin\u00e1t\u00e1k Airly integr\u00e1ci\u00f3ja m\u00e1r konfigur\u00e1lva van." }, "error": { - "auth": "Az API kulcs nem megfelel\u0151.", "wrong_location": "Ezen a ter\u00fcleten nincs Airly m\u00e9r\u0151\u00e1llom\u00e1s." }, "step": { diff --git a/homeassistant/components/airly/translations/it.json b/homeassistant/components/airly/translations/it.json index 0b8e7eb4f68..6f3fd919df5 100644 --- a/homeassistant/components/airly/translations/it.json +++ b/homeassistant/components/airly/translations/it.json @@ -4,7 +4,6 @@ "already_configured": "La posizione \u00e8 gi\u00e0 configurata" }, "error": { - "auth": "La chiave API non \u00e8 corretta.", "invalid_api_key": "Chiave API non valida", "wrong_location": "Nessuna stazione di misurazione Airly in quest'area." }, diff --git a/homeassistant/components/airly/translations/ko.json b/homeassistant/components/airly/translations/ko.json index 3faebcd5744..a0b20ed8c44 100644 --- a/homeassistant/components/airly/translations/ko.json +++ b/homeassistant/components/airly/translations/ko.json @@ -4,7 +4,6 @@ "already_configured": "\uc774 \uc88c\ud45c\uc5d0 \ub300\ud55c Airly \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "error": { - "auth": "API \ud0a4\uac00 \uc62c\ubc14\ub974\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.", "wrong_location": "\uc774 \uc9c0\uc5ed\uc5d0\ub294 Airly \uce21\uc815 \uc2a4\ud14c\uc774\uc158\uc774 \uc5c6\uc2b5\ub2c8\ub2e4." }, "step": { diff --git a/homeassistant/components/airly/translations/lb.json b/homeassistant/components/airly/translations/lb.json index b6d0ea03569..46eb3a91f04 100644 --- a/homeassistant/components/airly/translations/lb.json +++ b/homeassistant/components/airly/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "Airly Integratioun fir d\u00ebs Koordinaten ass scho konfigur\u00e9iert." + "already_configured": "Standuert ass scho konfigur\u00e9iert" }, "error": { - "auth": "Api Schl\u00ebssel ass net korrekt.", + "invalid_api_key": "Ong\u00ebltegen API Schl\u00ebssel", "wrong_location": "Keng Airly Moos Statioun an d\u00ebsem Ber\u00e4ich" }, "step": { @@ -13,7 +13,7 @@ "api_key": "API Schl\u00ebssel", "latitude": "Breedegrad", "longitude": "L\u00e4ngegrad", - "name": "Numm vun der Installatioun" + "name": "Numm" }, "description": "Airly Loft Qualit\u00e9it Integratioun ariichten. Fir een API Schl\u00ebssel z'erstelle gitt op https://developer.airly.eu/register", "title": "Airly" diff --git a/homeassistant/components/airly/translations/nl.json b/homeassistant/components/airly/translations/nl.json index f8edf64daa2..a7bc9966f63 100644 --- a/homeassistant/components/airly/translations/nl.json +++ b/homeassistant/components/airly/translations/nl.json @@ -4,7 +4,7 @@ "already_configured": "Airly-integratie voor deze co\u00f6rdinaten is al geconfigureerd." }, "error": { - "auth": "API-sleutel is niet correct.", + "invalid_api_key": "Ongeldige API-sleutel", "wrong_location": "Geen Airly meetstations in dit gebied." }, "step": { diff --git a/homeassistant/components/airly/translations/no.json b/homeassistant/components/airly/translations/no.json index 1fd5bd2e77f..f0a657d33d3 100644 --- a/homeassistant/components/airly/translations/no.json +++ b/homeassistant/components/airly/translations/no.json @@ -4,7 +4,6 @@ "already_configured": "Plasseringen er allerede konfigurert" }, "error": { - "auth": "API-n\u00f8kkelen er ikke korrekt.", "invalid_api_key": "Ugyldig API-n\u00f8kkel", "wrong_location": "Ingen Airly m\u00e5lestasjoner i dette omr\u00e5det." }, diff --git a/homeassistant/components/airly/translations/pl.json b/homeassistant/components/airly/translations/pl.json index bcda47006ab..f13c212e25a 100644 --- a/homeassistant/components/airly/translations/pl.json +++ b/homeassistant/components/airly/translations/pl.json @@ -4,7 +4,6 @@ "already_configured": "Lokalizacja jest ju\u017c skonfigurowana" }, "error": { - "auth": "Nieprawid\u0142owy klucz API", "invalid_api_key": "Nieprawid\u0142owy klucz API", "wrong_location": "Brak stacji pomiarowych Airly w tym rejonie" }, diff --git a/homeassistant/components/airly/translations/ru.json b/homeassistant/components/airly/translations/ru.json index 1d89090646f..a047d1e7477 100644 --- a/homeassistant/components/airly/translations/ru.json +++ b/homeassistant/components/airly/translations/ru.json @@ -4,7 +4,6 @@ "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." }, "error": { - "auth": "\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API.", "invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API.", "wrong_location": "\u0412 \u044d\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043d\u0435\u0442 \u0438\u0437\u043c\u0435\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0442\u0430\u043d\u0446\u0438\u0439 Airly." }, diff --git a/homeassistant/components/airly/translations/sl.json b/homeassistant/components/airly/translations/sl.json index 9fe84c532d1..71bea5a4d88 100644 --- a/homeassistant/components/airly/translations/sl.json +++ b/homeassistant/components/airly/translations/sl.json @@ -4,7 +4,6 @@ "already_configured": "Airly integracija za te koordinate je \u017ee nastavljen." }, "error": { - "auth": "Klju\u010d API ni pravilen.", "wrong_location": "Na tem obmo\u010dju ni merilnih postaj Airly." }, "step": { diff --git a/homeassistant/components/airly/translations/sv.json b/homeassistant/components/airly/translations/sv.json index 4a79f9cefe9..e47cb5cd328 100644 --- a/homeassistant/components/airly/translations/sv.json +++ b/homeassistant/components/airly/translations/sv.json @@ -4,7 +4,6 @@ "already_configured": "Airly-integrationen f\u00f6r dessa koordinater \u00e4r redan konfigurerad." }, "error": { - "auth": "API-nyckeln \u00e4r inte korrekt.", "wrong_location": "Inga Airly m\u00e4tstationer i detta omr\u00e5de." }, "step": { diff --git a/homeassistant/components/airly/translations/zh-Hans.json b/homeassistant/components/airly/translations/zh-Hans.json new file mode 100644 index 00000000000..f5b95a57f06 --- /dev/null +++ b/homeassistant/components/airly/translations/zh-Hans.json @@ -0,0 +1,14 @@ +{ + "config": { + "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/airly/translations/zh-Hant.json b/homeassistant/components/airly/translations/zh-Hant.json index 4a4955953f0..e8deb533de8 100644 --- a/homeassistant/components/airly/translations/zh-Hant.json +++ b/homeassistant/components/airly/translations/zh-Hant.json @@ -4,7 +4,6 @@ "already_configured": "\u5ea7\u6a19\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "auth": "API \u5bc6\u9470\u4e0d\u6b63\u78ba\u3002", "invalid_api_key": "API \u5bc6\u9470\u7121\u6548", "wrong_location": "\u8a72\u5340\u57df\u6c92\u6709 Arily \u76e3\u6e2c\u7ad9\u3002" }, diff --git a/homeassistant/components/airvisual/__init__.py b/homeassistant/components/airvisual/__init__.py index ef8a4ced1bd..17a96629d60 100644 --- a/homeassistant/components/airvisual/__init__.py +++ b/homeassistant/components/airvisual/__init__.py @@ -10,9 +10,8 @@ from pyairvisual.errors import ( KeyExpiredError, NodeProError, ) -import voluptuous as vol -from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_REAUTH +from homeassistant.config_entries import SOURCE_REAUTH from homeassistant.const import ( ATTR_ATTRIBUTION, CONF_API_KEY, @@ -45,36 +44,12 @@ from .const import ( 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} -GEOGRAPHY_COORDINATES_SCHEMA = vol.Schema( - { - vol.Required(CONF_LATITUDE): cv.latitude, - vol.Required(CONF_LONGITUDE): cv.longitude, - } -) - -GEOGRAPHY_PLACE_SCHEMA = vol.Schema( - { - vol.Required(CONF_CITY): cv.string, - vol.Required(CONF_STATE): cv.string, - vol.Required(CONF_COUNTRY): cv.string, - } -) - -CLOUD_API_SCHEMA = vol.Schema( - { - vol.Required(CONF_API_KEY): cv.string, - vol.Optional(CONF_GEOGRAPHIES, default=[]): vol.All( - cv.ensure_list, - [vol.Any(GEOGRAPHY_COORDINATES_SCHEMA, GEOGRAPHY_PLACE_SCHEMA)], - ), - } -) - -CONFIG_SCHEMA = vol.Schema({DOMAIN: CLOUD_API_SCHEMA}, extra=vol.ALLOW_EXTRA) +CONFIG_SCHEMA = cv.deprecated(DOMAIN, invalidation_version="0.119") @callback @@ -151,25 +126,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: {}} - - if DOMAIN not in config: - return True - - conf = config[DOMAIN] - - for geography in conf.get( - CONF_GEOGRAPHIES, - [{CONF_LATITUDE: hass.config.latitude, CONF_LONGITUDE: hass.config.longitude}], - ): - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={CONF_API_KEY: conf[CONF_API_KEY], **geography}, - ) - ) - + hass.data[DOMAIN] = {DATA_COORDINATOR: {}, DATA_LISTENER: {}} return True @@ -281,7 +238,9 @@ async def async_setup_entry(hass, config_entry): ) # 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) @@ -343,7 +302,7 @@ async def async_migrate_entry(hass, config_entry): hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, - context={"source": SOURCE_IMPORT}, + context={"source": "geography"}, data={CONF_API_KEY: config_entry.data[CONF_API_KEY], **geography}, ) ) @@ -365,9 +324,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] ) diff --git a/homeassistant/components/airvisual/config_flow.py b/homeassistant/components/airvisual/config_flow.py index 7cf1262fa43..b086aeefc27 100644 --- a/homeassistant/components/airvisual/config_flow.py +++ b/homeassistant/components/airvisual/config_flow.py @@ -146,10 +146,6 @@ class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): data={**user_input, CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY}, ) - async def async_step_import(self, import_config): - """Import a config entry from configuration.yaml.""" - return await self.async_step_geography(import_config) - async def async_step_node_pro(self, user_input=None): """Handle the initialization of the integration with a Node/Pro.""" if not user_input: diff --git a/homeassistant/components/airvisual/translations/ca.json b/homeassistant/components/airvisual/translations/ca.json index c4e246adc55..d7a0ec2bd99 100644 --- a/homeassistant/components/airvisual/translations/ca.json +++ b/homeassistant/components/airvisual/translations/ca.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "Ha fallat la connexi\u00f3", "general_error": "Error inesperat", - "invalid_api_key": "Clau API inv\u00e0lida", - "unable_to_connect": "No s'ha pogut connectar a la unitat Node/Pro." + "invalid_api_key": "Clau API inv\u00e0lida" }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/cs.json b/homeassistant/components/airvisual/translations/cs.json index 507581d0286..5c26dcf98ef 100644 --- a/homeassistant/components/airvisual/translations/cs.json +++ b/homeassistant/components/airvisual/translations/cs.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "general_error": "Neo\u010dek\u00e1van\u00e1 chyba", - "invalid_api_key": "Neplatn\u00fd kl\u00ed\u010d API", - "unable_to_connect": "Nelze se p\u0159ipojit k jednotce Node/Pro." + "invalid_api_key": "Neplatn\u00fd kl\u00ed\u010d API" }, "step": { "geography": { @@ -45,6 +44,9 @@ "options": { "step": { "init": { + "data": { + "show_on_map": "Uk\u00e1zat monitorovanou oblast na map\u011b" + }, "title": "Nastavte AirVisual" } } diff --git a/homeassistant/components/airvisual/translations/de.json b/homeassistant/components/airvisual/translations/de.json index 22ecae71a73..7c3467ca550 100644 --- a/homeassistant/components/airvisual/translations/de.json +++ b/homeassistant/components/airvisual/translations/de.json @@ -5,8 +5,7 @@ }, "error": { "general_error": "Es gab einen unbekannten Fehler.", - "invalid_api_key": "Ung\u00fcltiger API-Schl\u00fcssel bereitgestellt.", - "unable_to_connect": "Verbindung zum Node/Pro-Ger\u00e4t nicht m\u00f6glich." + "invalid_api_key": "Ung\u00fcltiger API-Schl\u00fcssel bereitgestellt." }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/en.json b/homeassistant/components/airvisual/translations/en.json index cb76d524d38..129abcc29e5 100644 --- a/homeassistant/components/airvisual/translations/en.json +++ b/homeassistant/components/airvisual/translations/en.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "Failed to connect", "general_error": "Unexpected error", - "invalid_api_key": "Invalid API key", - "unable_to_connect": "Unable to connect to Node/Pro unit." + "invalid_api_key": "Invalid API key" }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/es-419.json b/homeassistant/components/airvisual/translations/es-419.json index e552deb2242..8c88c259230 100644 --- a/homeassistant/components/airvisual/translations/es-419.json +++ b/homeassistant/components/airvisual/translations/es-419.json @@ -5,8 +5,7 @@ }, "error": { "general_error": "Se ha producido un error desconocido.", - "invalid_api_key": "Se proporciona una clave de API no v\u00e1lida.", - "unable_to_connect": "No se puede conectar a la unidad Node/Pro." + "invalid_api_key": "Se proporciona una clave de API no v\u00e1lida." }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/es.json b/homeassistant/components/airvisual/translations/es.json index f9d6460cd87..4325f1561b9 100644 --- a/homeassistant/components/airvisual/translations/es.json +++ b/homeassistant/components/airvisual/translations/es.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "No se pudo conectar", "general_error": "Se ha producido un error desconocido.", - "invalid_api_key": "Se proporciona una clave API no v\u00e1lida.", - "unable_to_connect": "No se puede conectar a la unidad Node/Pro." + "invalid_api_key": "Se proporciona una clave API no v\u00e1lida." }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/et.json b/homeassistant/components/airvisual/translations/et.json index e6ff1700852..4bbf04817f9 100644 --- a/homeassistant/components/airvisual/translations/et.json +++ b/homeassistant/components/airvisual/translations/et.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "\u00dchendamine nurjus", "general_error": "Tundmatu viga", - "invalid_api_key": "Vale API v\u00f5ti", - "unable_to_connect": "Node / Pro-seadmega ei saa \u00fchendust luua." + "invalid_api_key": "Vale API v\u00f5ti" }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/fr.json b/homeassistant/components/airvisual/translations/fr.json index 55247360306..90857d826ea 100644 --- a/homeassistant/components/airvisual/translations/fr.json +++ b/homeassistant/components/airvisual/translations/fr.json @@ -1,13 +1,13 @@ { "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", "general_error": "Une erreur inconnue est survenue.", - "invalid_api_key": "La cl\u00e9 API fournie n'est pas valide.", - "unable_to_connect": "Impossible de se connecter \u00e0 l'unit\u00e9 Node / Pro." + "invalid_api_key": "La cl\u00e9 API fournie n'est pas valide." }, "step": { "geography": { @@ -27,6 +27,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/airvisual/translations/hi.json b/homeassistant/components/airvisual/translations/hi.json index 42fbf50a829..bb21909ede0 100644 --- a/homeassistant/components/airvisual/translations/hi.json +++ b/homeassistant/components/airvisual/translations/hi.json @@ -1,8 +1,7 @@ { "config": { "error": { - "general_error": "\u0915\u094b\u0908 \u0905\u091c\u094d\u091e\u093e\u0924 \u0924\u094d\u0930\u0941\u091f\u093f \u0925\u0940\u0964", - "unable_to_connect": "\u0928\u094b\u0921 / \u092a\u094d\u0930\u094b \u0907\u0915\u093e\u0908 \u0938\u0947 \u0915\u0928\u0947\u0915\u094d\u091f \u0915\u0930\u0928\u0947 \u092e\u0947\u0902 \u0905\u0938\u092e\u0930\u094d\u0925\u0964" + "general_error": "\u0915\u094b\u0908 \u0905\u091c\u094d\u091e\u093e\u0924 \u0924\u094d\u0930\u0941\u091f\u093f \u0925\u0940\u0964" }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/it.json b/homeassistant/components/airvisual/translations/it.json index 670030c8a70..7a4062fbe76 100644 --- a/homeassistant/components/airvisual/translations/it.json +++ b/homeassistant/components/airvisual/translations/it.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "Impossibile connettersi", "general_error": "Errore imprevisto", - "invalid_api_key": "Chiave API non valida", - "unable_to_connect": "Impossibile connettersi all'unit\u00e0 Node/Pro." + "invalid_api_key": "Chiave API non valida" }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/ko.json b/homeassistant/components/airvisual/translations/ko.json index 19cd136cc0f..d25df4c213f 100644 --- a/homeassistant/components/airvisual/translations/ko.json +++ b/homeassistant/components/airvisual/translations/ko.json @@ -5,8 +5,7 @@ }, "error": { "general_error": "\uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.", - "invalid_api_key": "API \ud0a4\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "unable_to_connect": "AirVisual Node/Pro \uae30\uae30\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." + "invalid_api_key": "API \ud0a4\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/lb.json b/homeassistant/components/airvisual/translations/lb.json index 12e4c020341..5e45098c11d 100644 --- a/homeassistant/components/airvisual/translations/lb.json +++ b/homeassistant/components/airvisual/translations/lb.json @@ -1,13 +1,13 @@ { "config": { "abort": { - "already_configured": "D\u00ebs Koordinate oder ode/Pro ID si schon registr\u00e9iert." + "already_configured": "Standuert ass scho konfigur\u00e9iert oder Node/Pro ID ass scho registr\u00e9iert.", + "reauth_successful": "Re-authentifikatioun war erfollegr\u00e4ich" }, "error": { "cannot_connect": "Feeler beim verbannen", "general_error": "Onerwaarte Feeler", - "invalid_api_key": "Ong\u00ebltegen API Schl\u00ebssel uginn", - "unable_to_connect": "Kann sech net mat der Node/Pri verbannen." + "invalid_api_key": "Ong\u00ebltegen API Schl\u00ebssel" }, "step": { "geography": { @@ -21,12 +21,18 @@ }, "node_pro": { "data": { - "ip_address": "IP Adresse / Numm vun der Unit\u00e9it", + "ip_address": "Host", "password": "Passwuert" }, "description": "Pers\u00e9inlech Airvisual Unit\u00e9it iwwerwaachen. Passwuert kann vum UI vum Apparat ausgelies ginn.", "title": "Airvisual Node/Pro ariichten" }, + "reauth_confirm": { + "data": { + "api_key": "API Schl\u00ebssel" + }, + "title": "AirVisual re-authentifiz\u00e9ieren" + }, "user": { "data": { "cloud_api": "Geografesche Standuert", diff --git a/homeassistant/components/airvisual/translations/nl.json b/homeassistant/components/airvisual/translations/nl.json index 503f3580c18..85f8be5f8e0 100644 --- a/homeassistant/components/airvisual/translations/nl.json +++ b/homeassistant/components/airvisual/translations/nl.json @@ -6,11 +6,12 @@ "error": { "cannot_connect": "Kan geen verbinding maken", "general_error": "Er is een onbekende fout opgetreden.", - "unable_to_connect": "Kan geen verbinding maken met Node / Pro-apparaat." + "invalid_api_key": "Ongeldige API-sleutel" }, "step": { "geography": { "data": { + "api_key": "API-sleutel", "latitude": "Breedtegraad", "longitude": "Lengtegraad" }, @@ -25,6 +26,12 @@ "description": "Monitor een persoonlijke AirVisual-eenheid. Het wachtwoord kan worden opgehaald uit de gebruikersinterface van het apparaat.", "title": "Configureer een AirVisual Node / Pro" }, + "reauth_confirm": { + "data": { + "api_key": "API-sleutel" + }, + "title": "Verifieer AirVisual opnieuw" + }, "user": { "data": { "cloud_api": "Geografische ligging", diff --git a/homeassistant/components/airvisual/translations/no.json b/homeassistant/components/airvisual/translations/no.json index 68f0b672825..138b84f6fda 100644 --- a/homeassistant/components/airvisual/translations/no.json +++ b/homeassistant/components/airvisual/translations/no.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "Tilkobling mislyktes", "general_error": "Uventet feil", - "invalid_api_key": "Ugyldig API-n\u00f8kkel", - "unable_to_connect": "Kan ikke koble til Node / Pro-enheten." + "invalid_api_key": "Ugyldig API-n\u00f8kkel" }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/pl.json b/homeassistant/components/airvisual/translations/pl.json index 430fb5c348b..10af1fc2ee0 100644 --- a/homeassistant/components/airvisual/translations/pl.json +++ b/homeassistant/components/airvisual/translations/pl.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "general_error": "Nieoczekiwany b\u0142\u0105d", - "invalid_api_key": "Nieprawid\u0142owy klucz API", - "unable_to_connect": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z jednostk\u0105 Node/Pro" + "invalid_api_key": "Nieprawid\u0142owy klucz API" }, "step": { "geography": { @@ -32,7 +31,7 @@ "data": { "api_key": "Klucz API" }, - "title": "Ponownie uwierzytelnij z AirVisual" + "title": "Ponownie uwierzytelnij integracj\u0119" }, "user": { "data": { diff --git a/homeassistant/components/airvisual/translations/ru.json b/homeassistant/components/airvisual/translations/ru.json index 50f6a482d02..de9e5a730fe 100644 --- a/homeassistant/components/airvisual/translations/ru.json +++ b/homeassistant/components/airvisual/translations/ru.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "general_error": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", - "invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API.", - "unable_to_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443." + "invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API." }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/sl.json b/homeassistant/components/airvisual/translations/sl.json index f9121852d62..201b696a8ce 100644 --- a/homeassistant/components/airvisual/translations/sl.json +++ b/homeassistant/components/airvisual/translations/sl.json @@ -5,8 +5,7 @@ }, "error": { "general_error": "Pri\u0161lo je do neznane napake.", - "invalid_api_key": "Vpisan neveljaven API klju\u010d", - "unable_to_connect": "Ni mogo\u010de povezati z enoto Node/Pro." + "invalid_api_key": "Vpisan neveljaven API klju\u010d" }, "step": { "geography": { diff --git a/homeassistant/components/airvisual/translations/zh-Hant.json b/homeassistant/components/airvisual/translations/zh-Hant.json index 431dfb223ac..913173f98cc 100644 --- a/homeassistant/components/airvisual/translations/zh-Hant.json +++ b/homeassistant/components/airvisual/translations/zh-Hant.json @@ -7,8 +7,7 @@ "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", "general_error": "\u672a\u9810\u671f\u932f\u8aa4", - "invalid_api_key": "API \u5bc6\u9470\u7121\u6548", - "unable_to_connect": "\u7121\u6cd5\u9023\u7dda\u81f3 Node/Pro \u8a2d\u5099\u3002" + "invalid_api_key": "API \u5bc6\u9470\u7121\u6548" }, "step": { "geography": { diff --git a/homeassistant/components/alarm_control_panel/translations/pl.json b/homeassistant/components/alarm_control_panel/translations/pl.json index ca61dc870ea..0fd3045d1df 100644 --- a/homeassistant/components/alarm_control_panel/translations/pl.json +++ b/homeassistant/components/alarm_control_panel/translations/pl.json @@ -8,18 +8,18 @@ "trigger": "wyzw\u00f3l {entity_name}" }, "condition_type": { - "is_armed_away": "{entity_name} jest uzbrojony (poza domem)", - "is_armed_home": "{entity_name} jest uzbrojony (w domu)", - "is_armed_night": "{entity_name} jest uzbrojony (noc)", - "is_disarmed": "{entity_name} jest rozbrojony", - "is_triggered": "{entity_name} jest wyzwolony" + "is_armed_away": "alarm {entity_name} jest uzbrojony (poza domem)", + "is_armed_home": "alarm {entity_name} jest uzbrojony (w domu)", + "is_armed_night": "alarm {entity_name} jest uzbrojony (noc)", + "is_disarmed": "alarm {entity_name} jest rozbrojony", + "is_triggered": "alarm {entity_name} jest wyzwolony" }, "trigger_type": { - "armed_away": "{entity_name} zostanie uzbrojony (poza domem)", - "armed_home": "{entity_name} zostanie uzbrojony (w domu)", - "armed_night": "{entity_name} zostanie uzbrojony (noc)", - "disarmed": "{entity_name} zostanie rozbrojony", - "triggered": "{entity_name} zostanie wyzwolony" + "armed_away": "alarm {entity_name} zostanie uzbrojony (poza domem)", + "armed_home": "alarm {entity_name} zostanie uzbrojony (w domu)", + "armed_night": "alarm {entity_name} zostanie uzbrojony (noc)", + "disarmed": "alarm {entity_name} zostanie rozbrojony", + "triggered": "alarm {entity_name} zostanie wyzwolony" } }, "state": { diff --git a/homeassistant/components/alarm_control_panel/translations/tr.json b/homeassistant/components/alarm_control_panel/translations/tr.json index e352755fdf3..ebbcf568338 100644 --- a/homeassistant/components/alarm_control_panel/translations/tr.json +++ b/homeassistant/components/alarm_control_panel/translations/tr.json @@ -3,12 +3,12 @@ "_": { "armed": "Etkin", "armed_away": "Etkin d\u0131\u015far\u0131da", - "armed_custom_bypass": "\u00d6zel alarm atlatmas\u0131", + "armed_custom_bypass": "Alarm etkin \u00f6zel baypas", "armed_home": "Etkin evde", "armed_night": "Etkin gece", - "arming": "Etkinle\u015fiyor", + "arming": "Alarm etkinle\u015fiyor", "disarmed": "Etkisiz", - "disarming": "Etkisizle\u015ftiriliyor", + "disarming": "Alarm devre d\u0131\u015f\u0131", "pending": "Beklemede", "triggered": "Tetiklendi" } diff --git a/homeassistant/components/alarmdecoder/translations/ca.json b/homeassistant/components/alarmdecoder/translations/ca.json index d21231e0a75..da882bb614d 100644 --- a/homeassistant/components/alarmdecoder/translations/ca.json +++ b/homeassistant/components/alarmdecoder/translations/ca.json @@ -7,8 +7,7 @@ "default": "S'ha connectat correctament amb AlarmDecoder." }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "service_unavailable": "Ha fallat la connexi\u00f3" + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/cs.json b/homeassistant/components/alarmdecoder/translations/cs.json index 86408d58623..9bbef349d5a 100644 --- a/homeassistant/components/alarmdecoder/translations/cs.json +++ b/homeassistant/components/alarmdecoder/translations/cs.json @@ -7,8 +7,7 @@ "default": "\u00dasp\u011b\u0161n\u011b p\u0159ipojen k AlarmDecoder." }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "service_unavailable": "Nepoda\u0159ilo se p\u0159ipojit" + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "protocol": { @@ -34,6 +33,7 @@ "step": { "arm_settings": { "data": { + "alt_night_mode": "Alternativn\u00ed no\u010dn\u00ed re\u017eim", "code_arm_required": "K\u00f3d vy\u017eadovan\u00fd pro zabezpe\u010den\u00ed" }, "title": "Konfigurovat AlarmDecoder" diff --git a/homeassistant/components/alarmdecoder/translations/de.json b/homeassistant/components/alarmdecoder/translations/de.json index 8e72173d150..c00ee65c278 100644 --- a/homeassistant/components/alarmdecoder/translations/de.json +++ b/homeassistant/components/alarmdecoder/translations/de.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "service_unavailable": "Verbindung konnte nicht hergestellt werden" - }, "step": { "protocol": { "data": { diff --git a/homeassistant/components/alarmdecoder/translations/el.json b/homeassistant/components/alarmdecoder/translations/el.json index 44197dbe5fb..7c3b0b6737c 100644 --- a/homeassistant/components/alarmdecoder/translations/el.json +++ b/homeassistant/components/alarmdecoder/translations/el.json @@ -6,9 +6,6 @@ "create_entry": { "default": "\u0395\u03c0\u03b9\u03c4\u03c5\u03c7\u03ae\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03c3\u03c4\u03bf AlarmDecoder." }, - "error": { - "service_unavailable": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2" - }, "step": { "protocol": { "data": { diff --git a/homeassistant/components/alarmdecoder/translations/en.json b/homeassistant/components/alarmdecoder/translations/en.json index 978e4d298f2..747ccb51f9f 100644 --- a/homeassistant/components/alarmdecoder/translations/en.json +++ b/homeassistant/components/alarmdecoder/translations/en.json @@ -7,8 +7,7 @@ "default": "Successfully connected to AlarmDecoder." }, "error": { - "cannot_connect": "Failed to connect", - "service_unavailable": "Failed to connect" + "cannot_connect": "Failed to connect" }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/es.json b/homeassistant/components/alarmdecoder/translations/es.json index 6d30e28c437..5dfd7ab5745 100644 --- a/homeassistant/components/alarmdecoder/translations/es.json +++ b/homeassistant/components/alarmdecoder/translations/es.json @@ -7,8 +7,7 @@ "default": "Conectado con \u00e9xito a AlarmDecoder." }, "error": { - "cannot_connect": "No se pudo conectar", - "service_unavailable": "No se pudo conectar" + "cannot_connect": "No se pudo conectar" }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/et.json b/homeassistant/components/alarmdecoder/translations/et.json index 27d4c64cfaf..12395b1d078 100644 --- a/homeassistant/components/alarmdecoder/translations/et.json +++ b/homeassistant/components/alarmdecoder/translations/et.json @@ -7,8 +7,7 @@ "default": "AlarmDecoderiga \u00fchendamine \u00f5nnestus." }, "error": { - "cannot_connect": "\u00dchendamine nurjus", - "service_unavailable": "\u00dchendamine nurjus" + "cannot_connect": "\u00dchendamine nurjus" }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/fr.json b/homeassistant/components/alarmdecoder/translations/fr.json index c48cf00cded..1d1a200503f 100644 --- a/homeassistant/components/alarmdecoder/translations/fr.json +++ b/homeassistant/components/alarmdecoder/translations/fr.json @@ -7,7 +7,7 @@ "default": "Connexion r\u00e9ussie \u00e0 AlarmDecoder." }, "error": { - "service_unavailable": "\u00c9chec de connexion" + "cannot_connect": "\u00c9chec de connexion" }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/it.json b/homeassistant/components/alarmdecoder/translations/it.json index bbff7529851..70be8d733fe 100644 --- a/homeassistant/components/alarmdecoder/translations/it.json +++ b/homeassistant/components/alarmdecoder/translations/it.json @@ -7,8 +7,7 @@ "default": "Collegato con successo ad AlarmDecoder." }, "error": { - "cannot_connect": "Impossibile connettersi", - "service_unavailable": "Impossibile connettersi" + "cannot_connect": "Impossibile connettersi" }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/ko.json b/homeassistant/components/alarmdecoder/translations/ko.json index c4038572ece..ed29a3260ef 100644 --- a/homeassistant/components/alarmdecoder/translations/ko.json +++ b/homeassistant/components/alarmdecoder/translations/ko.json @@ -6,9 +6,6 @@ "create_entry": { "default": "AlarmDecoder\uc5d0 \uc131\uacf5\uc801\uc73c\ub85c \uc5f0\uacb0\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, - "error": { - "service_unavailable": "\uc5f0\uacb0 \uc2e4\ud328" - }, "step": { "protocol": { "data": { diff --git a/homeassistant/components/alarmdecoder/translations/lb.json b/homeassistant/components/alarmdecoder/translations/lb.json index 082e279c764..2df09bda41a 100644 --- a/homeassistant/components/alarmdecoder/translations/lb.json +++ b/homeassistant/components/alarmdecoder/translations/lb.json @@ -7,7 +7,7 @@ "default": "Erfollegr\u00e4ich mat Alarmdecoder verbonnen." }, "error": { - "service_unavailable": "Feeler beim verbannen" + "cannot_connect": "Feeler beim verbannen" }, "step": { "protocol": { @@ -30,6 +30,8 @@ "options": { "error": { "int": "D'Feld hei \u00ebnnen muss eng ganz Zuel sinn.", + "loop_range": "RF Loop muss eng ganz Zuel t\u00ebscht 1 a 4 sinn.", + "loop_rfid": "RF Loop kann net ouni RF Serial benotzt ginn.", "relay_inclusive": "Relais Adress a Relais Kanal sin vuneneen ofh\u00e4ngeg a musse mat abegraff sinn." }, "step": { diff --git a/homeassistant/components/alarmdecoder/translations/nl.json b/homeassistant/components/alarmdecoder/translations/nl.json index ac47fdf8730..1af1e8d803c 100644 --- a/homeassistant/components/alarmdecoder/translations/nl.json +++ b/homeassistant/components/alarmdecoder/translations/nl.json @@ -7,8 +7,7 @@ "default": "Succesvol verbonden met AlarmDecoder." }, "error": { - "cannot_connect": "Kan geen verbinding maken", - "service_unavailable": "Kon niet verbinden" + "cannot_connect": "Kan geen verbinding maken" }, "step": { "protocol": { @@ -60,6 +59,7 @@ "zone_rfid": "RF Serieel", "zone_type": "Zone Type" }, + "description": "Voer details in voor zone {zone_number}. Om zone {zone_number} te verwijderen, laat u Zone Name leeg.", "title": "Configureer AlarmDecoder" }, "zone_select": { diff --git a/homeassistant/components/alarmdecoder/translations/no.json b/homeassistant/components/alarmdecoder/translations/no.json index 881250b9686..b7776822e13 100644 --- a/homeassistant/components/alarmdecoder/translations/no.json +++ b/homeassistant/components/alarmdecoder/translations/no.json @@ -7,8 +7,7 @@ "default": "Vellykket koblet til AlarmDecoder." }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "service_unavailable": "Tilkobling mislyktes" + "cannot_connect": "Tilkobling mislyktes" }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/pl.json b/homeassistant/components/alarmdecoder/translations/pl.json index 8dfcc0a1a24..3fc77149178 100644 --- a/homeassistant/components/alarmdecoder/translations/pl.json +++ b/homeassistant/components/alarmdecoder/translations/pl.json @@ -7,8 +7,7 @@ "default": "Pomy\u015blnie po\u0142\u0105czono z AlarmDecoder." }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "service_unavailable": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/ru.json b/homeassistant/components/alarmdecoder/translations/ru.json index 700b4fe6a88..34fe0d9c718 100644 --- a/homeassistant/components/alarmdecoder/translations/ru.json +++ b/homeassistant/components/alarmdecoder/translations/ru.json @@ -7,8 +7,7 @@ "default": "\u0423\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043e \u043a AlarmDecoder." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "service_unavailable": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "protocol": { diff --git a/homeassistant/components/alarmdecoder/translations/zh-Hant.json b/homeassistant/components/alarmdecoder/translations/zh-Hant.json index b510b700b37..ee630bc7a1b 100644 --- a/homeassistant/components/alarmdecoder/translations/zh-Hant.json +++ b/homeassistant/components/alarmdecoder/translations/zh-Hant.json @@ -7,8 +7,7 @@ "default": "\u6210\u529f\u9023\u7dda\u81f3 AlarmDecoder\u3002" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "service_unavailable": "\u9023\u7dda\u5931\u6557" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "protocol": { diff --git a/homeassistant/components/alexa/capabilities.py b/homeassistant/components/alexa/capabilities.py index 63d8bb751bc..1163d0de101 100644 --- a/homeassistant/components/alexa/capabilities.py +++ b/homeassistant/components/alexa/capabilities.py @@ -784,7 +784,7 @@ class AlexaInputController(AlexaCapability): formatted_source = ( source.lower().replace("-", "").replace("_", "").replace(" ", "") ) - if formatted_source in Inputs.VALID_SOURCE_NAME_MAP.keys(): + if formatted_source in Inputs.VALID_SOURCE_NAME_MAP: input_list.append( {"name": Inputs.VALID_SOURCE_NAME_MAP[formatted_source]} ) diff --git a/homeassistant/components/alexa/handlers.py b/homeassistant/components/alexa/handlers.py index 783c7a36949..65c48ba0206 100644 --- a/homeassistant/components/alexa/handlers.py +++ b/homeassistant/components/alexa/handlers.py @@ -488,7 +488,7 @@ async def async_api_select_input(hass, config, directive, context): ) media_input = media_input.lower().replace(" ", "") if ( - formatted_source in Inputs.VALID_SOURCE_NAME_MAP.keys() + formatted_source in Inputs.VALID_SOURCE_NAME_MAP and formatted_source == media_input ) or ( media_input.endswith("1") and formatted_source == media_input.rstrip("1") diff --git a/homeassistant/components/almond/translations/bg.json b/homeassistant/components/almond/translations/bg.json index c2bcab535f3..bb0c874517b 100644 --- a/homeassistant/components/almond/translations/bg.json +++ b/homeassistant/components/almond/translations/bg.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u041c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u0438\u043d Almond \u0430\u043a\u0430\u0443\u043d\u0442.", "cannot_connect": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 Almond \u0441\u044a\u0440\u0432\u044a\u0440\u0430.", "missing_configuration": "\u041c\u043e\u043b\u044f, \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u0442\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430 \u043a\u0430\u043a \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 Almond." }, diff --git a/homeassistant/components/almond/translations/ca.json b/homeassistant/components/almond/translations/ca.json index b995d65e6ce..8ba96e603f5 100644 --- a/homeassistant/components/almond/translations/ca.json +++ b/homeassistant/components/almond/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Nom\u00e9s pots configurar un \u00fanic compte amb Almond.", "cannot_connect": "Ha fallat la connexi\u00f3", "missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3.", "no_url_available": "No hi ha cap URL disponible. Per a m\u00e9s informaci\u00f3 sobre aquest error, [consulta la secci\u00f3 d'ajuda]({docs_url})", diff --git a/homeassistant/components/almond/translations/cs.json b/homeassistant/components/almond/translations/cs.json index aa8a9d29939..1c667c9d55e 100644 --- a/homeassistant/components/almond/translations/cs.json +++ b/homeassistant/components/almond/translations/cs.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "M\u016f\u017eete nastavit pouze jeden \u00fa\u010det Almond.", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace.", "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})", diff --git a/homeassistant/components/almond/translations/da.json b/homeassistant/components/almond/translations/da.json index 9ce415cf8f9..37c66ea8efd 100644 --- a/homeassistant/components/almond/translations/da.json +++ b/homeassistant/components/almond/translations/da.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan kun konfigurere en Almond-konto.", "cannot_connect": "Kan ikke oprette forbindelse til Almond-serveren.", "missing_configuration": "Tjek venligst dokumentationen om, hvordan man indstiller Almond." }, diff --git a/homeassistant/components/almond/translations/de.json b/homeassistant/components/almond/translations/de.json index d90bbc9154f..e3a61026774 100644 --- a/homeassistant/components/almond/translations/de.json +++ b/homeassistant/components/almond/translations/de.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kannst nur ein Almond-Konto konfigurieren.", "cannot_connect": "Verbindung zum Almond-Server nicht m\u00f6glich.", "missing_configuration": "Bitte \u00fcberpr\u00fcfe die Dokumentation zur Einrichtung von Almond." }, diff --git a/homeassistant/components/almond/translations/en.json b/homeassistant/components/almond/translations/en.json index 909ebc6f601..b7f76e8933b 100644 --- a/homeassistant/components/almond/translations/en.json +++ b/homeassistant/components/almond/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "You can only configure one Almond account.", "cannot_connect": "Failed to connect", "missing_configuration": "The component is not configured. Please follow the documentation.", "no_url_available": "No URL available. For information about this error, [check the help section]({docs_url})", diff --git a/homeassistant/components/almond/translations/es-419.json b/homeassistant/components/almond/translations/es-419.json index fbcf901c2e5..50a43d67b6d 100644 --- a/homeassistant/components/almond/translations/es-419.json +++ b/homeassistant/components/almond/translations/es-419.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Solo puede configurar una cuenta Almond.", "cannot_connect": "No se puede conectar con el servidor Almond.", "missing_configuration": "Por favor, consulte la documentaci\u00f3n sobre c\u00f3mo configurar Almond." }, diff --git a/homeassistant/components/almond/translations/es.json b/homeassistant/components/almond/translations/es.json index 0da3c878b48..f14d3cd04ee 100644 --- a/homeassistant/components/almond/translations/es.json +++ b/homeassistant/components/almond/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "S\u00f3lo puede configurar una cuenta de Almond.", "cannot_connect": "No se puede conectar al servidor Almond.", "missing_configuration": "Consulte la documentaci\u00f3n sobre c\u00f3mo configurar Almond.", "no_url_available": "No hay URL disponible. Para obtener informaci\u00f3n sobre este error, [consulta la secci\u00f3n de ayuda]({docs_url})", diff --git a/homeassistant/components/almond/translations/et.json b/homeassistant/components/almond/translations/et.json index f5fa4a7d975..55ab29b2a81 100644 --- a/homeassistant/components/almond/translations/et.json +++ b/homeassistant/components/almond/translations/et.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Saad h\u00e4\u00e4lestada ainult \u00fche Almondi konto.", "cannot_connect": "\u00dchendamine nurjus", "missing_configuration": "Osis on seadistamata. Vaata dokumentatsiooni.", "no_url_available": "URL pole saadaval. Rohkem teavet [spikrijaotis]({docs_url})", diff --git a/homeassistant/components/almond/translations/fr.json b/homeassistant/components/almond/translations/fr.json index 7b7f4bff1e4..e4fb8610cd0 100644 --- a/homeassistant/components/almond/translations/fr.json +++ b/homeassistant/components/almond/translations/fr.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "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/almond/translations/hu.json b/homeassistant/components/almond/translations/hu.json index 2f9be096d79..7654f66bc28 100644 --- a/homeassistant/components/almond/translations/hu.json +++ b/homeassistant/components/almond/translations/hu.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Csak egy Almond fi\u00f3kot konfigur\u00e1lhat.", "cannot_connect": "Nem lehet csatlakozni az Almond szerverhez.", "missing_configuration": "K\u00e9rj\u00fck, ellen\u0151rizze az Almond be\u00e1ll\u00edt\u00e1s\u00e1nak dokument\u00e1ci\u00f3j\u00e1t." }, diff --git a/homeassistant/components/almond/translations/it.json b/homeassistant/components/almond/translations/it.json index e3522ed0c29..ab5d7f86f19 100644 --- a/homeassistant/components/almond/translations/it.json +++ b/homeassistant/components/almond/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u00c8 possibile configurare un solo account Almond.", "cannot_connect": "Impossibile connettersi", "missing_configuration": "Il componente non \u00e8 configurato. Si prega di seguire la documentazione.", "no_url_available": "Nessun URL disponibile. Per informazioni su questo errore, [controlla la sezione della guida]({docs_url})", diff --git a/homeassistant/components/almond/translations/ko.json b/homeassistant/components/almond/translations/ko.json index 08cb120bf9d..eff796699e3 100644 --- a/homeassistant/components/almond/translations/ko.json +++ b/homeassistant/components/almond/translations/ko.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\ud558\ub098\uc758 Almond \uacc4\uc815\ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.", "cannot_connect": "Almond \uc11c\ubc84\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", "missing_configuration": "Almond \uc124\uc815 \ubc29\ubc95\uc5d0 \ub300\ud55c \uc124\uba85\uc11c\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694.", "no_url_available": "\uac00\ub2a5\ud55c URL\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. \uc774 \uc5d0\ub7ec\uc5d0 \ub300\ud55c \uc815\ubcf4\ub294 \ub3c4\uc6c0\ub9d0 \uc139\uc158\uc744 \ud655\uc778\ud558\uc138\uc694({docs_url})" diff --git a/homeassistant/components/almond/translations/lb.json b/homeassistant/components/almond/translations/lb.json index bfcdad87e52..5a59645cdaa 100644 --- a/homeassistant/components/almond/translations/lb.json +++ b/homeassistant/components/almond/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_setup": "Dir k\u00ebnnt n\u00ebmmen een eenzegen Almond Kont konfigur\u00e9ieren.", - "cannot_connect": "Kann sech net mam Almond Server verbannen.", - "missing_configuration": "Kuckt w.e.g. Dokumentatioun iwwert d'ariichten vun Almond.", - "no_url_available": "Keng URL disponibel. Fir Informatiounen iwwert d\u00ebse Feeler, [kuck H\u00ebllef Sektioun]({docs_url})" + "cannot_connect": "Feeler beim verbannen", + "missing_configuration": "Komponent net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun.", + "no_url_available": "Keng URL disponibel. Fir Informatiounen iwwert d\u00ebse Feeler, [kuck H\u00ebllef Sektioun]({docs_url})", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "hassio_confirm": { @@ -12,7 +12,7 @@ "title": "Almond via Hass.io Erweiderung" }, "pick_implementation": { - "title": "Wielt Authentifikatiouns Method aus" + "title": "Wiel Authentifikatiouns Method aus" } } } diff --git a/homeassistant/components/almond/translations/nl.json b/homeassistant/components/almond/translations/nl.json index 59caf8a1144..26bbc8dea87 100644 --- a/homeassistant/components/almond/translations/nl.json +++ b/homeassistant/components/almond/translations/nl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "U kunt slechts \u00e9\u00e9n Almond-account configureren.", "cannot_connect": "Kan geen verbinding maken met de Almond-server.", "missing_configuration": "Raadpleeg de documentatie over het instellen van Almond.", "no_url_available": "Geen URL beschikbaar. Voor informatie over deze fout, [check de helpsectie]({docs_url})", diff --git a/homeassistant/components/almond/translations/no.json b/homeassistant/components/almond/translations/no.json index 15052133615..03606193945 100644 --- a/homeassistant/components/almond/translations/no.json +++ b/homeassistant/components/almond/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan bare konfigurere en Almond konto.", "cannot_connect": "Tilkobling mislyktes", "missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen.", "no_url_available": "Ingen URL tilgjengelig. For informasjon om denne feilen, [sjekk hjelpseksjonen]({docs_url})", @@ -9,8 +8,8 @@ }, "step": { "hassio_confirm": { - "description": "Vil du konfigurere Home Assistant til \u00e5 koble til Almond levert av Hass.io add-on: {addon}?", - "title": "" + "description": "Vil du konfigurere Home Assistant til \u00e5 koble til Almond levert av Hass.io tillegget: {addon}?", + "title": "Almond via Hass.io tillegg" }, "pick_implementation": { "title": "Velg godkjenningsmetode" diff --git a/homeassistant/components/almond/translations/pl.json b/homeassistant/components/almond/translations/pl.json index 7fea4c52ae3..110ab5a6a39 100644 --- a/homeassistant/components/almond/translations/pl.json +++ b/homeassistant/components/almond/translations/pl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno konto Almond", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105.", "no_url_available": "Brak dost\u0119pnego adresu URL. Aby uzyska\u0107 informacje na temat tego b\u0142\u0119du, [sprawd\u017a sekcj\u0119 pomocy] ({docs_url})", diff --git a/homeassistant/components/almond/translations/ru.json b/homeassistant/components/almond/translations/ru.json index 5a5d6a4c5c4..27870a46e95 100644 --- a/homeassistant/components/almond/translations/ru.json +++ b/homeassistant/components/almond/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438.", "no_url_available": "URL-\u0430\u0434\u0440\u0435\u0441 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d. \u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439]({docs_url}) \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u044d\u0442\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0435.", @@ -9,8 +8,8 @@ }, "step": { "hassio_confirm": { - "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 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a Almond (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", - "title": "Almond (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io)" + "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 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a Almond (\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", + "title": "Almond (\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io)" }, "pick_implementation": { "title": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u043f\u043e\u0441\u043e\u0431 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438" diff --git a/homeassistant/components/almond/translations/sl.json b/homeassistant/components/almond/translations/sl.json index cc2197ffaba..573df43876f 100644 --- a/homeassistant/components/almond/translations/sl.json +++ b/homeassistant/components/almond/translations/sl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Konfigurirate lahko samo en ra\u010dun Almond.", "cannot_connect": "Ni mogo\u010de vzpostaviti povezave s stre\u017enikom Almond.", "missing_configuration": "Prosimo, preverite dokumentacijo o tem, kako nastaviti Almond." }, diff --git a/homeassistant/components/almond/translations/sv.json b/homeassistant/components/almond/translations/sv.json index 70743f68e4d..6a7dfdb970c 100644 --- a/homeassistant/components/almond/translations/sv.json +++ b/homeassistant/components/almond/translations/sv.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan bara konfigurera ett Almond-konto.", "cannot_connect": "Det g\u00e5r inte att ansluta till Almond-servern.", "missing_configuration": "Kontrollera dokumentationen f\u00f6r hur du st\u00e4ller in Almond." }, diff --git a/homeassistant/components/almond/translations/zh-Hant.json b/homeassistant/components/almond/translations/zh-Hant.json index 329362fdbc3..a576b11e638 100644 --- a/homeassistant/components/almond/translations/zh-Hant.json +++ b/homeassistant/components/almond/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44 Almond \u5e33\u865f\u3002", "cannot_connect": "\u9023\u7dda\u5931\u6557", "missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002", "no_url_available": "\u6c92\u6709\u53ef\u7528\u7684\u7db2\u5740\u3002\u95dc\u65bc\u6b64\u932f\u8aa4\u66f4\u8a73\u7d30\u8a0a\u606f\uff0c[\u9ede\u9078\u5354\u52a9\u7ae0\u7bc0]({docs_url})", diff --git a/homeassistant/components/amazon_polly/tts.py b/homeassistant/components/amazon_polly/tts.py index ef3fe4e3ccb..3492518421d 100644 --- a/homeassistant/components/amazon_polly/tts.py +++ b/homeassistant/components/amazon_polly/tts.py @@ -94,8 +94,9 @@ SUPPORTED_VOICES = [ "Conchita", "Lucia", # Spanish European "Mia", # Spanish Mexican - "Miguel", + "Miguel", # Spanish US "Penelope", # Spanish US + "Lupe", # Spanish US "Astrid", # Swedish "Filiz", # Turkish "Gwyneth", # Welsh diff --git a/homeassistant/components/ambiclimate/translations/bg.json b/homeassistant/components/ambiclimate/translations/bg.json index 0472cfd33f1..627dd472018 100644 --- a/homeassistant/components/ambiclimate/translations/bg.json +++ b/homeassistant/components/ambiclimate/translations/bg.json @@ -1,9 +1,7 @@ { "config": { "abort": { - "access_token": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0434 \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f.", - "already_setup": "\u041f\u0440\u043e\u0444\u0438\u043b\u044a\u0442 \u043d\u0430 Ambiclimate \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d.", - "no_config": "\u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 Ambiclimate, \u043f\u0440\u0435\u0434\u0438 \u0434\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0433\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0438\u0440\u0430\u0442\u0435. [\u041c\u043e\u043b\u044f, \u043f\u0440\u043e\u0447\u0435\u0442\u0435\u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438\u0442\u0435](https://www.home-assistant.io/components/ambiclimate/)." + "access_token": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0434 \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f." }, "create_entry": { "default": "\u0423\u0441\u043f\u0435\u0448\u043d\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0438\u0440\u0430\u043d\u0435 \u0441 Ambiclimate." diff --git a/homeassistant/components/ambiclimate/translations/ca.json b/homeassistant/components/ambiclimate/translations/ca.json index 0740082cc05..b635d877ffe 100644 --- a/homeassistant/components/ambiclimate/translations/ca.json +++ b/homeassistant/components/ambiclimate/translations/ca.json @@ -3,11 +3,7 @@ "abort": { "access_token": "S'ha produ\u00eft un error desconegut al generat un token d'acc\u00e9s.", "already_configured": "El compte ja ha estat configurat", - "already_configured_account": "El compte ja ha estat configurat", - "already_setup": "El compte d'Ambi Climate est\u00e0 configurat.", - "missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3.", - "no_config": "Necessites configurar Ambiclimate abans de poder autenticar-t'hi. Llegeix les [instruccions](https://www.home-assistant.io/components/ambiclimate/).", - "oauth2_missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3." + "missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3." }, "create_entry": { "default": "Autenticaci\u00f3 exitosa" diff --git a/homeassistant/components/ambiclimate/translations/cs.json b/homeassistant/components/ambiclimate/translations/cs.json index a4ad6495510..258b250ab4f 100644 --- a/homeassistant/components/ambiclimate/translations/cs.json +++ b/homeassistant/components/ambiclimate/translations/cs.json @@ -3,10 +3,7 @@ "abort": { "access_token": "Nezn\u00e1m\u00e1 chyba p\u0159i generov\u00e1n\u00ed p\u0159\u00edstupov\u00e9ho tokenu.", "already_configured": "\u00da\u010det je ji\u017e nastaven", - "already_configured_account": "\u00da\u010det je ji\u017e nastaven", - "already_setup": "\u00da\u010det Ambiclimate je nastaven.", - "missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace.", - "oauth2_missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace." + "missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace." }, "create_entry": { "default": "\u00dasp\u011b\u0161n\u011b ov\u011b\u0159eno" diff --git a/homeassistant/components/ambiclimate/translations/da.json b/homeassistant/components/ambiclimate/translations/da.json index 3229e9f4127..c14016ca1d8 100644 --- a/homeassistant/components/ambiclimate/translations/da.json +++ b/homeassistant/components/ambiclimate/translations/da.json @@ -1,9 +1,7 @@ { "config": { "abort": { - "access_token": "Ukendt fejl ved generering af et adgangstoken.", - "already_setup": "Ambiclimate kontoen er konfigureret.", - "no_config": "Du skal konfigurere Ambiclimate f\u00f8r du kan godkende med det. [L\u00e6s venligst vejledningen](https://www.home-assistant.io/components/ambiclimate/)." + "access_token": "Ukendt fejl ved generering af et adgangstoken." }, "create_entry": { "default": "Godkendt med Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/de.json b/homeassistant/components/ambiclimate/translations/de.json index 43618a8ab99..e5988f76103 100644 --- a/homeassistant/components/ambiclimate/translations/de.json +++ b/homeassistant/components/ambiclimate/translations/de.json @@ -1,9 +1,7 @@ { "config": { "abort": { - "access_token": "Unbekannter Fehler beim Generieren eines Zugriffstokens.", - "already_setup": "Das Ambiclimate Konto ist konfiguriert.", - "no_config": "Ambiclimate muss konfiguriert sein, bevor die Authentifizierund durchgef\u00fchrt werden kann. [Bitte lies die Anleitung] (https://www.home-assistant.io/components/ambiclimate/)." + "access_token": "Unbekannter Fehler beim Generieren eines Zugriffstokens." }, "create_entry": { "default": "Erfolgreiche Authentifizierung mit Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/en.json b/homeassistant/components/ambiclimate/translations/en.json index 741c3de75b5..01c52875250 100644 --- a/homeassistant/components/ambiclimate/translations/en.json +++ b/homeassistant/components/ambiclimate/translations/en.json @@ -3,11 +3,7 @@ "abort": { "access_token": "Unknown error generating an access token.", "already_configured": "Account is already configured", - "already_configured_account": "Account is already configured", - "already_setup": "The Ambiclimate account is configured.", - "missing_configuration": "The component is not configured. Please follow the documentation.", - "no_config": "You need to configure Ambiclimate before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/components/ambiclimate/).", - "oauth2_missing_configuration": "The component is not configured. Please follow the documentation." + "missing_configuration": "The component is not configured. Please follow the documentation." }, "create_entry": { "default": "Successfully authenticated" diff --git a/homeassistant/components/ambiclimate/translations/es-419.json b/homeassistant/components/ambiclimate/translations/es-419.json index 55fb20ef45c..8f1d915c0b1 100644 --- a/homeassistant/components/ambiclimate/translations/es-419.json +++ b/homeassistant/components/ambiclimate/translations/es-419.json @@ -1,9 +1,7 @@ { "config": { "abort": { - "access_token": "Error desconocido al generar un token de acceso.", - "already_setup": "La cuenta de Ambiclimate est\u00e1 configurada.", - "no_config": "Es necesario configurar Ambiclimate antes de poder autenticarse con \u00e9l. Por favor, lea las instrucciones](https://www.home-assistant.io/components/ambiclimate/)." + "access_token": "Error desconocido al generar un token de acceso." }, "create_entry": { "default": "Autenticaci\u00f3n exitosa con Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/es.json b/homeassistant/components/ambiclimate/translations/es.json index ba5a53de2ae..521234c972a 100644 --- a/homeassistant/components/ambiclimate/translations/es.json +++ b/homeassistant/components/ambiclimate/translations/es.json @@ -2,10 +2,8 @@ "config": { "abort": { "access_token": "Error desconocido al generar un token de acceso.", - "already_configured_account": "La cuenta ya ha sido configurada", - "already_setup": "La cuenta de Ambiclimate est\u00e1 configurada.", - "no_config": "Es necesario configurar Ambiclimate antes de poder autenticarse con \u00e9l. [Por favor, lee las instrucciones](https://www.home-assistant.io/components/ambiclimate/).", - "oauth2_missing_configuration": "El componente no est\u00e1 configurado. Consulta la documentaci\u00f3n." + "already_configured": "La cuenta ya est\u00e1 configurada", + "missing_configuration": "El componente no est\u00e1 configurado. Siga la documentaci\u00f3n." }, "create_entry": { "default": "Autenticado correctamente con Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/et.json b/homeassistant/components/ambiclimate/translations/et.json index 1571a11e695..f9da8f8f7cd 100644 --- a/homeassistant/components/ambiclimate/translations/et.json +++ b/homeassistant/components/ambiclimate/translations/et.json @@ -3,11 +3,7 @@ "abort": { "access_token": "Tundmatu t\u00f5rge juurdep\u00e4\u00e4suloa loomisel.", "already_configured": "Konto on juba seadistatud", - "already_configured_account": "Kasutaja on juba lisatud", - "already_setup": "Ambiclimate'i konto on seadistatud.", - "missing_configuration": "Osis pole seadistatud. Palun vaata dokumentatsiooni.", - "no_config": "Enne autentimist pead konfigureerima Ambiclimate konto. [Palun loe juhiseid] (https://www.home-assistant.io/components/ambiclimate/) (https://www.home-assistant.io/components/ambiclimate/).", - "oauth2_missing_configuration": "Osis pole h\u00e4\u00e4lestatud. Lisainfot saad dokumentatsioonist." + "missing_configuration": "Osis pole seadistatud. Palun vaata dokumentatsiooni." }, "create_entry": { "default": "Ambiclimate autentimine \u00f5nnestus" diff --git a/homeassistant/components/ambiclimate/translations/fr.json b/homeassistant/components/ambiclimate/translations/fr.json index 879a02d38d0..bdbfaea20ef 100644 --- a/homeassistant/components/ambiclimate/translations/fr.json +++ b/homeassistant/components/ambiclimate/translations/fr.json @@ -2,10 +2,8 @@ "config": { "abort": { "access_token": "Erreur inconnue lors de la g\u00e9n\u00e9ration d'un jeton d'acc\u00e8s.", - "already_configured_account": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", - "already_setup": "Le compte Ambiclimate est configur\u00e9.", - "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." + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", + "missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation." }, "create_entry": { "default": "Authentifi\u00e9 avec succ\u00e8s avec Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/it.json b/homeassistant/components/ambiclimate/translations/it.json index b53ebaab648..618d4cbe7ca 100644 --- a/homeassistant/components/ambiclimate/translations/it.json +++ b/homeassistant/components/ambiclimate/translations/it.json @@ -2,13 +2,11 @@ "config": { "abort": { "access_token": "Errore sconosciuto durante la generazione di un token di accesso.", - "already_configured_account": "L'account \u00e8 gi\u00e0 configurato", - "already_setup": "L'account Ambiclimate \u00e8 configurato.", - "no_config": "\u00c8 necessario configurare Ambiclimate prima di poter eseguire l'autenticazione con esso. [Leggere le istruzioni](https://www.home-assistant.io/components/ambiclimate/).", - "oauth2_missing_configuration": "Il componente non \u00e8 configurato. Si prega di seguire la documentazione." + "already_configured": "L'account \u00e8 gi\u00e0 configurato", + "missing_configuration": "Il componente non \u00e8 configurato. Si prega di seguire la documentazione." }, "create_entry": { - "default": "Autenticato con successo con Ambiclimate" + "default": "Autenticazione riuscita" }, "error": { "follow_link": "Si prega di seguire il link e di autenticarsi prima di premere Invia", diff --git a/homeassistant/components/ambiclimate/translations/ko.json b/homeassistant/components/ambiclimate/translations/ko.json index fd55f75bf28..2a5e9280aa7 100644 --- a/homeassistant/components/ambiclimate/translations/ko.json +++ b/homeassistant/components/ambiclimate/translations/ko.json @@ -1,9 +1,7 @@ { "config": { "abort": { - "access_token": "\uc561\uc138\uc2a4 \ud1a0\ud070 \uc0dd\uc131\uc5d0 \uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.", - "already_setup": "Ambi Climate \uacc4\uc815\uc774 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "no_config": "Ambiclimate \ub97c \uc778\uc99d\ud558\ub824\uba74 \uba3c\uc800 Ambiclimate \ub97c \uad6c\uc131\ud574\uc57c \ud569\ub2c8\ub2e4. [\uc548\ub0b4](https://www.home-assistant.io/components/ambiclimate/) \ub97c \uc77d\uc5b4\ubcf4\uc138\uc694." + "access_token": "\uc561\uc138\uc2a4 \ud1a0\ud070 \uc0dd\uc131\uc5d0 \uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4." }, "create_entry": { "default": "Ambi Climate \ub85c \uc131\uacf5\uc801\uc73c\ub85c \uc778\uc99d\ub418\uc5c8\uc2b5\ub2c8\ub2e4." diff --git a/homeassistant/components/ambiclimate/translations/lb.json b/homeassistant/components/ambiclimate/translations/lb.json index dc663cbf42e..ddb170db5b7 100644 --- a/homeassistant/components/ambiclimate/translations/lb.json +++ b/homeassistant/components/ambiclimate/translations/lb.json @@ -2,11 +2,11 @@ "config": { "abort": { "access_token": "Onbekannte Feeler beim gener\u00e9ieren vum Acc\u00e8s Jeton.", - "already_setup": "Den Ambiclimate Kont ass konfigur\u00e9iert.", - "no_config": "Dir musst Ambiclimate konfigur\u00e9ieren, ier Dir d\u00ebs Authentifiz\u00e9ierung k\u00ebnnt benotzen.[Liest w.e.g. d'Instruktioune](https://www.home-assistant.io/components/ambiclimate/)." + "already_configured": "Kont ass scho konfigur\u00e9iert", + "missing_configuration": "Komponent net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun." }, "create_entry": { - "default": "Erfollegr\u00e4ich mat Ambiclimate authentifiz\u00e9iert." + "default": "Erfollegr\u00e4ich authentifiz\u00e9iert." }, "error": { "follow_link": "Follegt w.e.g. dem Link an authentifiz\u00e9iert de Kont ier dir op ofsch\u00e9cken dr\u00e9ckt.", diff --git a/homeassistant/components/ambiclimate/translations/nl.json b/homeassistant/components/ambiclimate/translations/nl.json index 573cd8fecde..52f8cfc40d3 100644 --- a/homeassistant/components/ambiclimate/translations/nl.json +++ b/homeassistant/components/ambiclimate/translations/nl.json @@ -2,9 +2,7 @@ "config": { "abort": { "access_token": "Onbekende fout bij het genereren van een toegangstoken.", - "already_configured_account": "Account is al geconfigureerd", - "already_setup": "Het Ambiclimate-account is geconfigureerd.", - "no_config": "U moet Ambiclimate configureren voordat u zich ermee kunt authenticeren. (Lees de instructies) (https://www.home-assistant.io/components/ambiclimate/)." + "already_configured": "Account is al geconfigureerd" }, "create_entry": { "default": "Succesvol geverifieerd met Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/no.json b/homeassistant/components/ambiclimate/translations/no.json index 70457f500bf..88a4a0bdbb2 100644 --- a/homeassistant/components/ambiclimate/translations/no.json +++ b/homeassistant/components/ambiclimate/translations/no.json @@ -3,11 +3,7 @@ "abort": { "access_token": "Ukjent feil ved oppretting av tilgangstoken.", "already_configured": "Kontoen er allerede konfigurert", - "already_configured_account": "Kontoen er allerede konfigurert", - "already_setup": "Ambiclimate-kontoen er konfigurert.", - "missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen.", - "no_config": "Du m\u00e5 konfigurere Ambiclimate f\u00f8r du kan godkjenne den. [Vennligst les instruksjonene](https://www.home-assistant.io/components/ambiclimate/).", - "oauth2_missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen." + "missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen." }, "create_entry": { "default": "Vellykket godkjenning" diff --git a/homeassistant/components/ambiclimate/translations/pl.json b/homeassistant/components/ambiclimate/translations/pl.json index 6c762de60b3..2f90f3b4401 100644 --- a/homeassistant/components/ambiclimate/translations/pl.json +++ b/homeassistant/components/ambiclimate/translations/pl.json @@ -3,11 +3,7 @@ "abort": { "access_token": "Nieznany b\u0142\u0105d podczas generowania tokena dost\u0119pu", "already_configured": "Konto jest ju\u017c skonfigurowane", - "already_configured_account": "Konto jest ju\u017c skonfigurowane", - "already_setup": "Konto Ambiclimate jest skonfigurowane", - "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105.", - "no_config": "Musisz skonfigurowa\u0107 Ambiclimate, aby m\u00f3c si\u0119 z nim uwierzytelni\u0107. Zapoznaj si\u0119 z [instrukcj\u0105](https://www.home-assistant.io/components/ambiclimate/)", - "oauth2_missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105." + "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105." }, "create_entry": { "default": "Pomy\u015blnie uwierzytelniono" diff --git a/homeassistant/components/ambiclimate/translations/pt-BR.json b/homeassistant/components/ambiclimate/translations/pt-BR.json index 1b0ae2a74df..466096416ae 100644 --- a/homeassistant/components/ambiclimate/translations/pt-BR.json +++ b/homeassistant/components/ambiclimate/translations/pt-BR.json @@ -1,9 +1,7 @@ { "config": { "abort": { - "access_token": "Erro desconhecido ao gerar um token de acesso.", - "already_setup": "A conta Ambiclimate est\u00e1 configurada.", - "no_config": "Voc\u00ea precisa configurar o Ambiclimate antes de poder autenticar com ele. [Por favor, leia as instru\u00e7\u00f5es] (https://www.home-assistant.io/components/ambiclimate/)." + "access_token": "Erro desconhecido ao gerar um token de acesso." }, "create_entry": { "default": "Autenticado com sucesso no Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/ru.json b/homeassistant/components/ambiclimate/translations/ru.json index e4558d11008..8c8863c0eec 100644 --- a/homeassistant/components/ambiclimate/translations/ru.json +++ b/homeassistant/components/ambiclimate/translations/ru.json @@ -3,11 +3,7 @@ "abort": { "access_token": "\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430.", "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.", - "already_setup": "\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.", - "missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438.", - "no_config": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 Ambiclimate \u043f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/ambiclimate/).", - "oauth2_missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438." + "missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438." }, "create_entry": { "default": "\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e." diff --git a/homeassistant/components/ambiclimate/translations/sl.json b/homeassistant/components/ambiclimate/translations/sl.json index e293b411226..8c923a7d213 100644 --- a/homeassistant/components/ambiclimate/translations/sl.json +++ b/homeassistant/components/ambiclimate/translations/sl.json @@ -1,9 +1,7 @@ { "config": { "abort": { - "access_token": "Neznana napaka pri ustvarjanju \u017eetona za dostop.", - "already_setup": "Ra\u010dun Ambiclimate je konfiguriran.", - "no_config": "Ambiclimate morate konfigurirati, preden lahko z njo preverjate pristnost. [Preberite navodila] (https://www.home-assistant.io/components/ambiclimate/)." + "access_token": "Neznana napaka pri ustvarjanju \u017eetona za dostop." }, "create_entry": { "default": "Uspe\u0161no overjeno z funkcijo Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/sv.json b/homeassistant/components/ambiclimate/translations/sv.json index 3ff8ed3da97..e6d06553d77 100644 --- a/homeassistant/components/ambiclimate/translations/sv.json +++ b/homeassistant/components/ambiclimate/translations/sv.json @@ -1,9 +1,7 @@ { "config": { "abort": { - "access_token": "Ok\u00e4nt fel vid generering av \u00e5tkomsttoken.", - "already_setup": "Ambiclientkontot \u00e4r konfigurerat", - "no_config": "Du m\u00e5ste konfigurera Ambiclimate innan du kan autentisera med den. [V\u00e4nligen l\u00e4s instruktionerna] (https://www.home-assistant.io/components/ambiclimate/)." + "access_token": "Ok\u00e4nt fel vid generering av \u00e5tkomsttoken." }, "create_entry": { "default": "Lyckad autentisering med Ambiclimate" diff --git a/homeassistant/components/ambiclimate/translations/zh-Hant.json b/homeassistant/components/ambiclimate/translations/zh-Hant.json index d596e5b30d0..f91c38dd36e 100644 --- a/homeassistant/components/ambiclimate/translations/zh-Hant.json +++ b/homeassistant/components/ambiclimate/translations/zh-Hant.json @@ -3,11 +3,7 @@ "abort": { "access_token": "\u7522\u751f\u5b58\u53d6\u8a8d\u8b49\u78bc\u672a\u77e5\u932f\u8aa4\u3002", "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "already_configured_account": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "already_setup": "Ambiclimate \u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002", - "no_config": "\u5fc5\u9808\u5148\u8a2d\u5b9a Ambiclimate \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15]\uff08https://www.home-assistant.io/components/ambiclimate/\uff09\u3002", - "oauth2_missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002" + "missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002" }, "create_entry": { "default": "\u5df2\u6210\u529f\u8a8d\u8b49" diff --git a/homeassistant/components/ambient_station/__init__.py b/homeassistant/components/ambient_station/__init__.py index 23c0ad6e3dd..9fabed7c30a 100644 --- a/homeassistant/components/ambient_station/__init__.py +++ b/homeassistant/components/ambient_station/__init__.py @@ -9,7 +9,6 @@ import voluptuous as vol from homeassistant.components.binary_sensor import DEVICE_CLASS_CONNECTIVITY from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import ( - AREA_SQUARE_METERS, ATTR_LOCATION, ATTR_NAME, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, @@ -17,9 +16,9 @@ from homeassistant.const import ( CONF_API_KEY, DEGREE, EVENT_HOMEASSISTANT_STOP, + IRRADIATION_WATTS_PER_SQUARE_METER, LIGHT_LUX, PERCENTAGE, - POWER_WATT, PRESSURE_INHG, SPEED_MILES_PER_HOUR, TEMP_FAHRENHEIT, @@ -211,7 +210,7 @@ SENSOR_TYPES = { TYPE_SOILTEMP9F: ("Soil Temp 9", TEMP_FAHRENHEIT, TYPE_SENSOR, "temperature"), TYPE_SOLARRADIATION: ( "Solar Rad", - f"{POWER_WATT}/{AREA_SQUARE_METERS}", + IRRADIATION_WATTS_PER_SQUARE_METER, TYPE_SENSOR, None, ), diff --git a/homeassistant/components/ambient_station/translations/lb.json b/homeassistant/components/ambient_station/translations/lb.json index c679b270e80..f565639ac7d 100644 --- a/homeassistant/components/ambient_station/translations/lb.json +++ b/homeassistant/components/ambient_station/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "D\u00ebsen App Schl\u00ebssel g\u00ebtt scho benotzt" + "already_configured": "Service ass scho konfigur\u00e9iert" }, "error": { - "invalid_key": "Ong\u00ebltegen API Schl\u00ebssel an/oder Applikatioun's Schl\u00ebssel", + "invalid_key": "Ong\u00ebltegen API Schl\u00ebssel", "no_devices": "Keng Apparater am Kont fonnt" }, "step": { diff --git a/homeassistant/components/ambient_station/translations/nl.json b/homeassistant/components/ambient_station/translations/nl.json index 53ad8c9094b..02c8f0727f8 100644 --- a/homeassistant/components/ambient_station/translations/nl.json +++ b/homeassistant/components/ambient_station/translations/nl.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Service is al geconfigureerd" + }, "error": { "invalid_key": "Ongeldige API-sleutel en/of applicatiesleutel", "no_devices": "Geen apparaten gevonden in account" diff --git a/homeassistant/components/androidtv/manifest.json b/homeassistant/components/androidtv/manifest.json index 902688742ba..eaa59f50db8 100644 --- a/homeassistant/components/androidtv/manifest.json +++ b/homeassistant/components/androidtv/manifest.json @@ -4,7 +4,7 @@ "documentation": "https://www.home-assistant.io/integrations/androidtv", "requirements": [ "adb-shell[async]==0.2.1", - "androidtv[async]==0.0.52", + "androidtv[async]==0.0.54", "pure-python-adb[async]==0.3.0.dev0" ], "codeowners": ["@JeffLIrion"] diff --git a/homeassistant/components/androidtv/media_player.py b/homeassistant/components/androidtv/media_player.py index b13a2000e5b..4d17b4ecdad 100644 --- a/homeassistant/components/androidtv/media_player.py +++ b/homeassistant/components/androidtv/media_player.py @@ -410,6 +410,12 @@ class ADBDevice(MediaPlayerEntity): self._app_name_to_id = { value: key for key, value in self._app_id_to_name.items() if value } + + # Make sure that apps overridden via the `apps` parameter are reflected + # in `self._app_name_to_id` + for key, value in apps.items(): + self._app_name_to_id[value] = key + self._get_sources = get_sources self._keys = KEYS @@ -445,6 +451,7 @@ class ADBDevice(MediaPlayerEntity): self._current_app = None self._sources = None self._state = None + self._hdmi_input = None @property def app_id(self): @@ -463,8 +470,11 @@ class ADBDevice(MediaPlayerEntity): @property def device_state_attributes(self): - """Provide the last ADB command's response as an attribute.""" - return {"adb_response": self._adb_response} + """Provide the last ADB command's response and the device's HDMI input as attributes.""" + return { + "adb_response": self._adb_response, + "hdmi_input": self._hdmi_input, + } @property def media_image_hash(self): @@ -670,6 +680,7 @@ class AndroidTVDevice(ADBDevice): _, self._is_volume_muted, self._volume_level, + self._hdmi_input, ) = await self.aftv.update(self._get_sources) self._state = ANDROIDTV_STATES.get(state) @@ -743,10 +754,13 @@ class FireTVDevice(ADBDevice): if not self._available: return - # Get the `state`, `current_app`, and `running_apps`. - state, self._current_app, running_apps = await self.aftv.update( - self._get_sources - ) + # Get the `state`, `current_app`, `running_apps` and `hdmi_input`. + ( + state, + self._current_app, + running_apps, + self._hdmi_input, + ) = await self.aftv.update(self._get_sources) self._state = ANDROIDTV_STATES.get(state) if self._state is None: diff --git a/homeassistant/components/apns/notify.py b/homeassistant/components/apns/notify.py index 24d666fa59b..6f8de7e9c84 100644 --- a/homeassistant/components/apns/notify.py +++ b/homeassistant/components/apns/notify.py @@ -186,7 +186,7 @@ class ApnsNotificationService(BaseNotificationService): def write_devices(self): """Write all known devices to file.""" with open(self.yaml_path, "w+") as out: - for _, device in self.devices.items(): + for device in self.devices.values(): _write_device(out, device) def register(self, call): diff --git a/homeassistant/components/arcam_fmj/translations/ca.json b/homeassistant/components/arcam_fmj/translations/ca.json index a7c03abc41d..6d30f32e16a 100644 --- a/homeassistant/components/arcam_fmj/translations/ca.json +++ b/homeassistant/components/arcam_fmj/translations/ca.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", "already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs", - "cannot_connect": "Ha fallat la connexi\u00f3", - "unable_to_connect": "No es pot connectar amb el dispositiu." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "flow_title": "Arcam FMJ a {host}", "step": { diff --git a/homeassistant/components/arcam_fmj/translations/cs.json b/homeassistant/components/arcam_fmj/translations/cs.json index e6aba520755..c5909f14e05 100644 --- a/homeassistant/components/arcam_fmj/translations/cs.json +++ b/homeassistant/components/arcam_fmj/translations/cs.json @@ -3,10 +3,13 @@ "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "unable_to_connect": "Nelze se p\u0159ipojit k za\u0159\u00edzen\u00ed." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, + "flow_title": "Arcam FMJ na {host}", "step": { + "confirm": { + "description": "Chcete p\u0159idat Arcam FMJ na `{host}` do Home Assistant?" + }, "user": { "data": { "host": "Hostitel", diff --git a/homeassistant/components/arcam_fmj/translations/de.json b/homeassistant/components/arcam_fmj/translations/de.json index 55a8df9d8f7..05f56150169 100644 --- a/homeassistant/components/arcam_fmj/translations/de.json +++ b/homeassistant/components/arcam_fmj/translations/de.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "unable_to_connect": "Es konnte keine Verbindung mit dem Ger\u00e4t hergestellt werden." + "already_configured": "Ger\u00e4t ist bereits konfiguriert" }, "step": { "user": { diff --git a/homeassistant/components/arcam_fmj/translations/en.json b/homeassistant/components/arcam_fmj/translations/en.json index 9ab35fd6ff7..c770bf89e2d 100644 --- a/homeassistant/components/arcam_fmj/translations/en.json +++ b/homeassistant/components/arcam_fmj/translations/en.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Device is already configured", "already_in_progress": "Configuration flow is already in progress", - "cannot_connect": "Failed to connect", - "unable_to_connect": "Unable to connect to device." + "cannot_connect": "Failed to connect" }, "flow_title": "Arcam FMJ on {host}", "step": { diff --git a/homeassistant/components/arcam_fmj/translations/es.json b/homeassistant/components/arcam_fmj/translations/es.json index fab0457331f..6959ee85ab1 100644 --- a/homeassistant/components/arcam_fmj/translations/es.json +++ b/homeassistant/components/arcam_fmj/translations/es.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado", "already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en proceso", - "cannot_connect": "No se pudo conectar", - "unable_to_connect": "No se puede conectar con el dispositivo." + "cannot_connect": "No se pudo conectar" }, "flow_title": "Arcam FMJ en {host}", "step": { diff --git a/homeassistant/components/arcam_fmj/translations/et.json b/homeassistant/components/arcam_fmj/translations/et.json index 2f6c6eb46db..84735beefab 100644 --- a/homeassistant/components/arcam_fmj/translations/et.json +++ b/homeassistant/components/arcam_fmj/translations/et.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", "already_in_progress": "Seadistamine on juba k\u00e4imas", - "cannot_connect": "\u00dchendamine nurjus", - "unable_to_connect": "Seadmega ei saa \u00fchendust luua." + "cannot_connect": "\u00dchendamine nurjus" }, "flow_title": "Arcam FMJ saidil {host}", "step": { diff --git a/homeassistant/components/arcam_fmj/translations/fr.json b/homeassistant/components/arcam_fmj/translations/fr.json index 6e191c204d8..511d9e98a50 100644 --- a/homeassistant/components/arcam_fmj/translations/fr.json +++ b/homeassistant/components/arcam_fmj/translations/fr.json @@ -3,7 +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.", - "unable_to_connect": "Impossible de se connecter au p\u00e9riph\u00e9rique." + "cannot_connect": "\u00c9chec de connexion" }, "error": { "one": "Vide", diff --git a/homeassistant/components/arcam_fmj/translations/it.json b/homeassistant/components/arcam_fmj/translations/it.json index fdfabdf9c19..649bc0f2b39 100644 --- a/homeassistant/components/arcam_fmj/translations/it.json +++ b/homeassistant/components/arcam_fmj/translations/it.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso", - "cannot_connect": "Impossibile connettersi", - "unable_to_connect": "Impossibile connettersi al dispositivo." + "cannot_connect": "Impossibile connettersi" }, "error": { "one": "uno", diff --git a/homeassistant/components/arcam_fmj/translations/ko.json b/homeassistant/components/arcam_fmj/translations/ko.json index 3ff4c6d3811..62b5a54928e 100644 --- a/homeassistant/components/arcam_fmj/translations/ko.json +++ b/homeassistant/components/arcam_fmj/translations/ko.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "already_in_progress": "\uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4.", - "unable_to_connect": "\uae30\uae30\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." + "already_in_progress": "\uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4." }, "flow_title": "Arcam FMJ: {host}", "step": { diff --git a/homeassistant/components/arcam_fmj/translations/lb.json b/homeassistant/components/arcam_fmj/translations/lb.json index 36a834867c0..45b9e6fd8a6 100644 --- a/homeassistant/components/arcam_fmj/translations/lb.json +++ b/homeassistant/components/arcam_fmj/translations/lb.json @@ -2,9 +2,8 @@ "config": { "abort": { "already_configured": "Apparat ass scho konfigur\u00e9iert", - "already_in_progress": "Konfiguratioun's Oflaf fir den Apparat ass schonn am gaangen.", - "cannot_connect": "Feeler beim verbannen", - "unable_to_connect": "Keng Verbindung mam Apparat m\u00e9iglech." + "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaangen.", + "cannot_connect": "Feeler beim verbannen" }, "flow_title": "Arcam FMJ um {host}", "step": { diff --git a/homeassistant/components/arcam_fmj/translations/nl.json b/homeassistant/components/arcam_fmj/translations/nl.json index 1f1fa864700..5607b426cc9 100644 --- a/homeassistant/components/arcam_fmj/translations/nl.json +++ b/homeassistant/components/arcam_fmj/translations/nl.json @@ -4,11 +4,21 @@ "already_configured": "Apparaat is al geconfigureerd", "cannot_connect": "Kan geen verbinding maken" }, + "error": { + "one": "Leeg", + "other": "Leeg" + }, + "flow_title": "Arcam FMJ op {host}", "step": { + "confirm": { + "description": "Wil je Arcam FMJ op `{host}` toevoegen aan Home Assistant?" + }, "user": { "data": { + "host": "Host", "port": "Poort" - } + }, + "description": "Voer de hostnaam of het IP-adres van het apparaat in." } } }, diff --git a/homeassistant/components/arcam_fmj/translations/no.json b/homeassistant/components/arcam_fmj/translations/no.json index 715691d7f4e..e98f943f565 100644 --- a/homeassistant/components/arcam_fmj/translations/no.json +++ b/homeassistant/components/arcam_fmj/translations/no.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Enheten er allerede konfigurert", "already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede", - "cannot_connect": "Tilkobling mislyktes", - "unable_to_connect": "Kan ikke koble til enheten." + "cannot_connect": "Tilkobling mislyktes" }, "flow_title": "Arcam FMJ p\u00e5 {host}", "step": { diff --git a/homeassistant/components/arcam_fmj/translations/pl.json b/homeassistant/components/arcam_fmj/translations/pl.json index 16607259eb5..8cf2bb5b4eb 100644 --- a/homeassistant/components/arcam_fmj/translations/pl.json +++ b/homeassistant/components/arcam_fmj/translations/pl.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "already_in_progress": "Konfiguracja jest ju\u017c w toku", - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "unable_to_connect": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z urz\u0105dzeniem" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "error": { "few": "kilka", diff --git a/homeassistant/components/arcam_fmj/translations/ru.json b/homeassistant/components/arcam_fmj/translations/ru.json index 00040a14e78..bdd59b39067 100644 --- a/homeassistant/components/arcam_fmj/translations/ru.json +++ b/homeassistant/components/arcam_fmj/translations/ru.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.", - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "unable_to_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "flow_title": "Arcam FMJ {host}", "step": { 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 00000000000..6e842e66fab --- /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/arcam_fmj/translations/zh-Hant.json b/homeassistant/components/arcam_fmj/translations/zh-Hant.json index ff2e38c8ba3..fd2cb2181ac 100644 --- a/homeassistant/components/arcam_fmj/translations/zh-Hant.json +++ b/homeassistant/components/arcam_fmj/translations/zh-Hant.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d", - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "unable_to_connect": "\u7121\u6cd5\u9023\u7dda\u81f3\u8a2d\u5099\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "flow_title": "Arcam FMJ \uff08{host}\uff09", "step": { diff --git a/homeassistant/components/arwn/sensor.py b/homeassistant/components/arwn/sensor.py index 3db1283279e..18186e8b871 100644 --- a/homeassistant/components/arwn/sensor.py +++ b/homeassistant/components/arwn/sensor.py @@ -30,26 +30,30 @@ def discover_sensors(topic, payload): unit = TEMP_FAHRENHEIT else: unit = TEMP_CELSIUS - return ArwnSensor(name, "temp", unit) + return ArwnSensor(topic, name, "temp", unit) if domain == "moisture": name = f"{parts[2]} Moisture" - return ArwnSensor(name, "moisture", unit, "mdi:water-percent") + return ArwnSensor(topic, name, "moisture", unit, "mdi:water-percent") if domain == "rain": if len(parts) >= 3 and parts[2] == "today": return ArwnSensor( - "Rain Since Midnight", "since_midnight", "in", "mdi:water" + topic, "Rain Since Midnight", "since_midnight", "in", "mdi:water" ) return ( - ArwnSensor("Total Rainfall", "total", unit, "mdi:water"), - ArwnSensor("Rainfall Rate", "rate", unit, "mdi:water"), + ArwnSensor(topic + "/total", "Total Rainfall", "total", unit, "mdi:water"), + ArwnSensor(topic + "/rate", "Rainfall Rate", "rate", unit, "mdi:water"), ) if domain == "barometer": - return ArwnSensor("Barometer", "pressure", unit, "mdi:thermometer-lines") + return ArwnSensor(topic, "Barometer", "pressure", unit, "mdi:thermometer-lines") if domain == "wind": return ( - ArwnSensor("Wind Speed", "speed", unit, "mdi:speedometer"), - ArwnSensor("Wind Gust", "gust", unit, "mdi:speedometer"), - ArwnSensor("Wind Direction", "direction", DEGREE, "mdi:compass"), + ArwnSensor( + topic + "/speed", "Wind Speed", "speed", unit, "mdi:speedometer" + ), + ArwnSensor(topic + "/gust", "Wind Gust", "gust", unit, "mdi:speedometer"), + ArwnSensor( + topic + "/dir", "Wind Direction", "direction", DEGREE, "mdi:compass" + ), ) @@ -95,11 +99,15 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= sensor.set_event(event) store[sensor.name] = sensor _LOGGER.debug( - "Registering new sensor %(name)s => %(event)s", + "Registering sensor %(name)s => %(event)s", {"name": sensor.name, "event": event}, ) async_add_entities((sensor,), True) else: + _LOGGER.debug( + "Recording sensor %(name)s => %(event)s", + {"name": sensor.name, "event": event}, + ) store[sensor.name].set_event(event) await mqtt.async_subscribe(hass, TOPIC, async_sensor_event_received, 0) @@ -109,11 +117,13 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= class ArwnSensor(Entity): """Representation of an ARWN sensor.""" - def __init__(self, name, state_key, units, icon=None): + def __init__(self, topic, name, state_key, units, icon=None): """Initialize the sensor.""" self.hass = None self.entity_id = _slug(name) self._name = name + # This mqtt topic for the sensor which is its uid + self._uid = topic self._state_key = state_key self.event = {} self._unit_of_measurement = units @@ -135,6 +145,14 @@ class ArwnSensor(Entity): """Get the name of the sensor.""" return self._name + @property + def unique_id(self): + """Return a unique ID. + + This is based on the topic that comes from mqtt + """ + return self._uid + @property def state_attributes(self): """Return all the state attributes.""" diff --git a/homeassistant/components/asuswrt/device_tracker.py b/homeassistant/components/asuswrt/device_tracker.py index a7c4f9a7a7c..a3545183d2e 100644 --- a/homeassistant/components/asuswrt/device_tracker.py +++ b/homeassistant/components/asuswrt/device_tracker.py @@ -35,7 +35,7 @@ class AsusWrtDeviceScanner(DeviceScanner): 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/asuswrt/manifest.json b/homeassistant/components/asuswrt/manifest.json index 97514c4da7f..26b8d49ddb1 100644 --- a/homeassistant/components/asuswrt/manifest.json +++ b/homeassistant/components/asuswrt/manifest.json @@ -2,6 +2,6 @@ "domain": "asuswrt", "name": "ASUSWRT", "documentation": "https://www.home-assistant.io/integrations/asuswrt", - "requirements": ["aioasuswrt==1.2.8"], + "requirements": ["aioasuswrt==1.3.0"], "codeowners": ["@kennedyshead"] } diff --git a/homeassistant/components/atag/strings.json b/homeassistant/components/atag/strings.json index 756ab491ba2..b06e9188b5b 100644 --- a/homeassistant/components/atag/strings.json +++ b/homeassistant/components/atag/strings.json @@ -1,5 +1,4 @@ { - "title": "Atag", "config": { "step": { "user": { diff --git a/homeassistant/components/atag/translations/ca.json b/homeassistant/components/atag/translations/ca.json index 9c1dc1a5fb6..dbd73d0bf43 100644 --- a/homeassistant/components/atag/translations/ca.json +++ b/homeassistant/components/atag/translations/ca.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "Ha fallat la connexi\u00f3", "unauthorized": "La vinculaci\u00f3 s'ha denegat, comprova si hi ha una sol\u00b7licitud d'autenticaci\u00f3 al dispositiu" }, "step": { @@ -18,6 +17,5 @@ "title": "Connexi\u00f3 amb el dispositiu" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/cs.json b/homeassistant/components/atag/translations/cs.json index bb802758772..105c53e9a46 100644 --- a/homeassistant/components/atag/translations/cs.json +++ b/homeassistant/components/atag/translations/cs.json @@ -5,7 +5,7 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit" + "unauthorized": "P\u00e1rov\u00e1n\u00ed bylo odm\u00edtnuto, zkontrolujte po\u017eadavek na autorizaci na za\u0159\u00edzen\u00ed" }, "step": { "user": { @@ -17,6 +17,5 @@ "title": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/de.json b/homeassistant/components/atag/translations/de.json index e87be7f4e0a..2b96bdfa5b8 100644 --- a/homeassistant/components/atag/translations/de.json +++ b/homeassistant/components/atag/translations/de.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Dieses Ger\u00e4t wurde bereits zu HomeAssistant hinzugef\u00fcgt" }, - "error": { - "connection_error": "Verbindung fehlgeschlagen, versuchen Sie es erneut" - }, "step": { "user": { "data": { @@ -16,6 +13,5 @@ "title": "Stellen Sie eine Verbindung zum Ger\u00e4t her" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/en.json b/homeassistant/components/atag/translations/en.json index 5b6226e13eb..ea354acffde 100644 --- a/homeassistant/components/atag/translations/en.json +++ b/homeassistant/components/atag/translations/en.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect", "unauthorized": "Pairing denied, check device for auth request" }, "step": { @@ -18,6 +17,5 @@ "title": "Connect to the device" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/es-419.json b/homeassistant/components/atag/translations/es-419.json index f837491b330..68da80cbb7e 100644 --- a/homeassistant/components/atag/translations/es-419.json +++ b/homeassistant/components/atag/translations/es-419.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Solo se puede agregar un dispositivo Atag a Home Assistant" }, - "error": { - "connection_error": "No se pudo conectar, intente nuevamente" - }, "step": { "user": { "data": { @@ -16,6 +13,5 @@ "title": "Conectarse al dispositivo" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/es.json b/homeassistant/components/atag/translations/es.json index 2cfcd4746c2..b71c91693d1 100644 --- a/homeassistant/components/atag/translations/es.json +++ b/homeassistant/components/atag/translations/es.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "connection_error": "No se pudo conectar, por favor, int\u00e9ntalo de nuevo", "unauthorized": "Emparejamiento denegado, comprobar el dispositivo para la solicitud de autorizaci\u00f3n" }, "step": { @@ -18,6 +17,5 @@ "title": "Conectarse al dispositivo" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/et.json b/homeassistant/components/atag/translations/et.json index 5376b60c3fd..2a4094806ed 100644 --- a/homeassistant/components/atag/translations/et.json +++ b/homeassistant/components/atag/translations/et.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "\u00dchendamine nurjus", "unauthorized": "Sidumine on keelatud, kontrollige seadme tuvastamistaotlust" }, "step": { @@ -18,6 +17,5 @@ "title": "\u00dchendu seadmega" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/fi.json b/homeassistant/components/atag/translations/fi.json index 60a920588b0..0bf4c236a9b 100644 --- a/homeassistant/components/atag/translations/fi.json +++ b/homeassistant/components/atag/translations/fi.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "connection_error": "Yhteyden muodostaminen ep\u00e4onnistui. Yrit\u00e4 uudelleen" - }, "step": { "user": { "data": { @@ -12,6 +9,5 @@ "title": "Yhdist\u00e4 laitteeseen" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/fr.json b/homeassistant/components/atag/translations/fr.json index 6652d1508a7..c8a19a44eb4 100644 --- a/homeassistant/components/atag/translations/fr.json +++ b/homeassistant/components/atag/translations/fr.json @@ -4,7 +4,7 @@ "already_configured": "Un seul appareil Atag peut \u00eatre ajout\u00e9 \u00e0 Home Assistant" }, "error": { - "connection_error": "Impossible de se connecter, veuillez r\u00e9essayer", + "cannot_connect": "\u00c9chec de connexion", "unauthorized": "Pairage refus\u00e9, v\u00e9rifiez la demande d'authentification de l'appareil" }, "step": { @@ -17,6 +17,5 @@ "title": "Se connecter \u00e0 l'appareil" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/hi.json b/homeassistant/components/atag/translations/hi.json index e2b57f18e79..ad2657e96a2 100644 --- a/homeassistant/components/atag/translations/hi.json +++ b/homeassistant/components/atag/translations/hi.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "connection_error": "\u0915\u0928\u0947\u0915\u094d\u091f \u0915\u0930\u0928\u0947 \u092e\u0947\u0902 \u0935\u093f\u092b\u0932, \u0915\u0943\u092a\u092f\u093e \u092a\u0941\u0928\u0903 \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902" - }, "step": { "user": { "data": { @@ -12,6 +9,5 @@ "title": "\u0921\u093f\u0935\u093e\u0907\u0938 \u0938\u0947 \u0915\u0928\u0947\u0915\u094d\u091f \u0915\u0930\u0947\u0902" } } - }, - "title": "A\u091f\u0948\u0917" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/it.json b/homeassistant/components/atag/translations/it.json index bdeeac8e60e..060f9d21b20 100644 --- a/homeassistant/components/atag/translations/it.json +++ b/homeassistant/components/atag/translations/it.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi", "unauthorized": "Associazione negata, controllare il dispositivo per la richiesta di autenticazione" }, "step": { @@ -18,6 +17,5 @@ "title": "Connettersi al dispositivo" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/ko.json b/homeassistant/components/atag/translations/ko.json index 064770fac5f..c09b4f7b249 100644 --- a/homeassistant/components/atag/translations/ko.json +++ b/homeassistant/components/atag/translations/ko.json @@ -4,7 +4,6 @@ "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 HomeAssistant \uc5d0 \ucd94\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "error": { - "connection_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694.", "unauthorized": "\ud398\uc5b4\ub9c1\uc774 \uac70\ubd80\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uc778\uc99d \uc694\uccad \uae30\uae30\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694" }, "step": { @@ -17,6 +16,5 @@ "title": "\uae30\uae30\uc5d0 \uc5f0\uacb0\ud558\uae30" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/lb.json b/homeassistant/components/atag/translations/lb.json index bd928aa81e1..afb8aea1697 100644 --- a/homeassistant/components/atag/translations/lb.json +++ b/homeassistant/components/atag/translations/lb.json @@ -1,22 +1,21 @@ { "config": { "abort": { - "already_configured": "D\u00ebsen Apparat ass schonn am Home Assistant dob\u00e4igesat ginn" + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "connection_error": "Feeler beim verbannen", + "cannot_connect": "Feeler beim verbannen", "unauthorized": "Kopplung verweigert, iwwerpr\u00e9if den Apparat fir auth request" }, "step": { "user": { "data": { - "email": "E-Mail (Optionell)", + "email": "E-Mail", "host": "Apparat", "port": "Port" }, "title": "Mam Apparat verbannen" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/nl.json b/homeassistant/components/atag/translations/nl.json index 5e4a4dd8d8c..96f135848e1 100644 --- a/homeassistant/components/atag/translations/nl.json +++ b/homeassistant/components/atag/translations/nl.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Verbinding mislukt, probeer het opnieuw", "unauthorized": "Koppelen geweigerd, controleer apparaat op autorisatieverzoek" }, "step": { @@ -18,6 +17,5 @@ "title": "Verbinding maken met het apparaat" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/no.json b/homeassistant/components/atag/translations/no.json index 44d3fb8a96e..650605c270f 100644 --- a/homeassistant/components/atag/translations/no.json +++ b/homeassistant/components/atag/translations/no.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes", "unauthorized": "Parring nektet, sjekk enheten for autorisasjonsforesp\u00f8rsel" }, "step": { @@ -18,6 +17,5 @@ "title": "Koble til enheten" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/pl.json b/homeassistant/components/atag/translations/pl.json index 1858eb8bf80..4c690ba057e 100644 --- a/homeassistant/components/atag/translations/pl.json +++ b/homeassistant/components/atag/translations/pl.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "unauthorized": "Odmowa parowania, sprawd\u017a urz\u0105dzenie pod k\u0105tem \u017c\u0105dania autoryzacji" }, "step": { @@ -18,6 +17,5 @@ "title": "Po\u0142\u0105czenie z urz\u0105dzeniem" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/pt-BR.json b/homeassistant/components/atag/translations/pt-BR.json index b4bba5ea4d1..a98060320fc 100644 --- a/homeassistant/components/atag/translations/pt-BR.json +++ b/homeassistant/components/atag/translations/pt-BR.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Este dispositivo j\u00e1 foi adicionado ao Home Assistant" }, - "error": { - "connection_error": "Falha ao conectar, tente novamente" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/atag/translations/ru.json b/homeassistant/components/atag/translations/ru.json index 181f6c8092b..beb0ee904cd 100644 --- a/homeassistant/components/atag/translations/ru.json +++ b/homeassistant/components/atag/translations/ru.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "unauthorized": "\u0421\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d\u043e, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438." }, "step": { @@ -18,6 +17,5 @@ "title": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/sl.json b/homeassistant/components/atag/translations/sl.json index 6f9b1e23759..8c939f153d6 100644 --- a/homeassistant/components/atag/translations/sl.json +++ b/homeassistant/components/atag/translations/sl.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Home Assistant-u lahko dodate samo eno napravo Atag" }, - "error": { - "connection_error": "Povezava ni uspela, poskusite znova" - }, "step": { "user": { "data": { @@ -15,6 +12,5 @@ "title": "Pove\u017eite se z napravo" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/atag/translations/sv.json b/homeassistant/components/atag/translations/sv.json index 938a0191ee3..ae07cfa6221 100644 --- a/homeassistant/components/atag/translations/sv.json +++ b/homeassistant/components/atag/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "connection_error": "Det gick inte att ansluta, f\u00f6rs\u00f6k igen" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/atag/translations/zh-Hant.json b/homeassistant/components/atag/translations/zh-Hant.json index fe507272b4a..164e87a9642 100644 --- a/homeassistant/components/atag/translations/zh-Hant.json +++ b/homeassistant/components/atag/translations/zh-Hant.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557", "unauthorized": "\u914d\u5c0d\u906d\u62d2\uff0c\u8acb\u6aa2\u67e5\u8a2d\u5099\u8a8d\u8b49\u8acb\u6c42" }, "step": { @@ -18,6 +17,5 @@ "title": "\u9023\u7dda\u81f3\u8a2d\u5099" } } - }, - "title": "Atag" + } } \ No newline at end of file diff --git a/homeassistant/components/august/entity.py b/homeassistant/components/august/entity.py index 0d259778796..b6c677a63b6 100644 --- a/homeassistant/components/august/entity.py +++ b/homeassistant/components/august/entity.py @@ -46,18 +46,13 @@ class AugustEntityMixin(Entity): async def async_added_to_hass(self): """Subscribe to updates.""" - self._data.async_subscribe_device_id( - self._device_id, self._update_from_data_and_write_state + self.async_on_remove( + self._data.async_subscribe_device_id( + self._device_id, self._update_from_data_and_write_state + ) ) - self._data.activity_stream.async_subscribe_device_id( - self._device_id, self._update_from_data_and_write_state - ) - - async def async_will_remove_from_hass(self): - """Undo subscription.""" - self._data.async_unsubscribe_device_id( - self._device_id, self._update_from_data_and_write_state - ) - self._data.activity_stream.async_unsubscribe_device_id( - self._device_id, self._update_from_data_and_write_state + self.async_on_remove( + self._data.activity_stream.async_subscribe_device_id( + self._device_id, self._update_from_data_and_write_state + ) ) diff --git a/homeassistant/components/august/subscriber.py b/homeassistant/components/august/subscriber.py index 81538fa011e..3a7edd8a342 100644 --- a/homeassistant/components/august/subscriber.py +++ b/homeassistant/components/august/subscriber.py @@ -18,13 +18,21 @@ class AugustSubscriberMixin: @callback def async_subscribe_device_id(self, device_id, update_callback): - """Add an callback subscriber.""" + """Add an callback subscriber. + + Returns a callable that can be used to unsubscribe. + """ if not self._subscriptions: self._unsub_interval = async_track_time_interval( self._hass, self._async_refresh, self._update_interval ) self._subscriptions.setdefault(device_id, []).append(update_callback) + def _unsubscribe(): + self.async_unsubscribe_device_id(device_id, update_callback) + + return _unsubscribe + @callback def async_unsubscribe_device_id(self, device_id, update_callback): """Remove a callback subscriber.""" diff --git a/homeassistant/components/august/translations/cs.json b/homeassistant/components/august/translations/cs.json index f1db40b0beb..4100014abb6 100644 --- a/homeassistant/components/august/translations/cs.json +++ b/homeassistant/components/august/translations/cs.json @@ -17,12 +17,14 @@ "timeout": "\u010casov\u00fd limit (v sekund\u00e1ch)", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" }, + "description": "Pokud je metoda p\u0159ihl\u00e1\u0161en\u00ed \"e-mail\", je e-mailovou adresou u\u017eivatelsk\u00e9 jm\u00e9no. Pokud je p\u0159ihla\u0161ovac\u00ed metoda \"telefon\", u\u017eivatelsk\u00e9 jm\u00e9no je telefonn\u00ed \u010d\u00edslo ve form\u00e1tu \"+NNNNNNNNN\".", "title": "Nastavte \u00fa\u010det August" }, "validation": { "data": { "code": "Ov\u011b\u0159ovac\u00ed k\u00f3d" }, + "description": "Zkontrolujte pros\u00edm {login_method} ({username}) a n\u00ed\u017ee zadejte ov\u011b\u0159ovac\u00ed k\u00f3d", "title": "Dvoufaktorov\u00e9 ov\u011b\u0159ov\u00e1n\u00ed" } } diff --git a/homeassistant/components/august/translations/fr.json b/homeassistant/components/august/translations/fr.json index 752b7dc3712..82568b681fd 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/august/translations/lb.json b/homeassistant/components/august/translations/lb.json index 501af05c2df..87fef5f521b 100644 --- a/homeassistant/components/august/translations/lb.json +++ b/homeassistant/components/august/translations/lb.json @@ -1,10 +1,11 @@ { "config": { "abort": { - "already_configured": "Kont ass scho konfigur\u00e9iert" + "already_configured": "Kont ass scho konfigur\u00e9iert", + "reauth_successful": "Re-authentifikatioun war erfollegr\u00e4ich" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9iert w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, diff --git a/homeassistant/components/aurora/translations/ca.json b/homeassistant/components/aurora/translations/ca.json new file mode 100644 index 00000000000..99db9855e74 --- /dev/null +++ b/homeassistant/components/aurora/translations/ca.json @@ -0,0 +1,26 @@ +{ + "config": { + "error": { + "cannot_connect": "Ha fallat la connexi\u00f3" + }, + "step": { + "user": { + "data": { + "latitude": "Latitud", + "longitude": "Longitud", + "name": "Nom" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "threshold": "Llindar (%)" + } + } + } + }, + "title": "Sensor Aurora NOAA" +} \ No newline at end of file diff --git a/homeassistant/components/aurora/translations/cs.json b/homeassistant/components/aurora/translations/cs.json new file mode 100644 index 00000000000..e7a10c94241 --- /dev/null +++ b/homeassistant/components/aurora/translations/cs.json @@ -0,0 +1,26 @@ +{ + "config": { + "error": { + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" + }, + "step": { + "user": { + "data": { + "latitude": "Zem\u011bpisn\u00e1 \u0161\u00ed\u0159ka", + "longitude": "Zem\u011bpisn\u00e1 d\u00e9lka", + "name": "Jm\u00e9no" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "threshold": "Pr\u00e1h (%)" + } + } + } + }, + "title": "Senzor NOAA Aurora" +} \ No newline at end of file diff --git a/homeassistant/components/aurora/translations/es.json b/homeassistant/components/aurora/translations/es.json new file mode 100644 index 00000000000..c722c95ef6f --- /dev/null +++ b/homeassistant/components/aurora/translations/es.json @@ -0,0 +1,26 @@ +{ + "config": { + "error": { + "cannot_connect": "No se pudo conectar" + }, + "step": { + "user": { + "data": { + "latitude": "Latitud", + "longitude": "Longitud", + "name": "Nombre" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "threshold": "Umbral (%)" + } + } + } + }, + "title": "Sensor Aurora NOAA" +} \ No newline at end of file diff --git a/homeassistant/components/aurora/translations/et.json b/homeassistant/components/aurora/translations/et.json new file mode 100644 index 00000000000..80fb6b21736 --- /dev/null +++ b/homeassistant/components/aurora/translations/et.json @@ -0,0 +1,26 @@ +{ + "config": { + "error": { + "cannot_connect": "\u00dchendus nurjus" + }, + "step": { + "user": { + "data": { + "latitude": "Laiuskraad", + "longitude": "Pikkuskraad", + "name": "Nimi" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "threshold": "L\u00e4vi (%)" + } + } + } + }, + "title": "NOAA Aurora andur" +} \ No newline at end of file diff --git a/homeassistant/components/aurora/translations/no.json b/homeassistant/components/aurora/translations/no.json new file mode 100644 index 00000000000..1d22d6cd08b --- /dev/null +++ b/homeassistant/components/aurora/translations/no.json @@ -0,0 +1,26 @@ +{ + "config": { + "error": { + "cannot_connect": "Tilkobling mislyktes" + }, + "step": { + "user": { + "data": { + "latitude": "Breddegrad", + "longitude": "Lengdegrad", + "name": "Navn" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "threshold": "Terskel (%)" + } + } + } + }, + "title": "NOAA Aurora-sensor" +} \ No newline at end of file diff --git a/homeassistant/components/aurora/translations/pl.json b/homeassistant/components/aurora/translations/pl.json new file mode 100644 index 00000000000..f8786290458 --- /dev/null +++ b/homeassistant/components/aurora/translations/pl.json @@ -0,0 +1,26 @@ +{ + "config": { + "error": { + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" + }, + "step": { + "user": { + "data": { + "latitude": "Szeroko\u015b\u0107 geograficzna", + "longitude": "D\u0142ugo\u015b\u0107 geograficzna", + "name": "Nazwa" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "threshold": "Pr\u00f3g prawdopodobie\u0144stwa (%)" + } + } + } + }, + "title": "Sensor NOAA Aurora" +} \ No newline at end of file diff --git a/homeassistant/components/aurora/translations/ru.json b/homeassistant/components/aurora/translations/ru.json new file mode 100644 index 00000000000..20e8f4a184b --- /dev/null +++ b/homeassistant/components/aurora/translations/ru.json @@ -0,0 +1,26 @@ +{ + "config": { + "error": { + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." + }, + "step": { + "user": { + "data": { + "latitude": "\u0428\u0438\u0440\u043e\u0442\u0430", + "longitude": "\u0414\u043e\u043b\u0433\u043e\u0442\u0430", + "name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "threshold": "\u041f\u043e\u0440\u043e\u0433 (%)" + } + } + } + }, + "title": "NOAA Aurora Sensor" +} \ No newline at end of file diff --git a/homeassistant/components/auth/translations/cs.json b/homeassistant/components/auth/translations/cs.json index d3f077d87e7..f6ca546ef5a 100644 --- a/homeassistant/components/auth/translations/cs.json +++ b/homeassistant/components/auth/translations/cs.json @@ -24,7 +24,7 @@ }, "step": { "init": { - "description": "Chcete-li aktivovat dvoufaktorovou autentizaci pomoc\u00ed jednor\u00e1zov\u00fdch hesel zalo\u017een\u00fdch na \u010dase, na\u010dt\u011bte k\u00f3d QR pomoc\u00ed va\u0161\u00ed autentiza\u010dn\u00ed aplikace. Pokud ji nem\u00e1te, doporu\u010dujeme bu\u010f [Google Authenticator](https://support.google.com/accounts/answer/1066447) nebo [Authy](https://authy.com/). \n\n {qr_code} \n \n Po skenov\u00e1n\u00ed k\u00f3du zadejte \u0161estcifern\u00fd k\u00f3d z aplikace a ov\u011b\u0159te nastaven\u00ed. Pokud m\u00e1te probl\u00e9my se skenov\u00e1n\u00edm k\u00f3du QR, prove\u010fte ru\u010dn\u00ed nastaven\u00ed s k\u00f3dem **`{code}`**.", + "description": "Chcete-li aktivovat dvoufaktorovou autentizaci pomoc\u00ed jednor\u00e1zov\u00fdch hesel zalo\u017een\u00fdch na \u010dase, na\u010dt\u011bte k\u00f3d QR pomoc\u00ed va\u0161\u00ed autentiza\u010dn\u00ed aplikace. Pokud ji nem\u00e1te, doporu\u010dujeme bu\u010f [Google Authenticator](https://support.google.com/accounts/answer/1066447) nebo [Authy](https://authy.com/). \n\n{qr_code} \n \nPo skenov\u00e1n\u00ed k\u00f3du zadejte \u0161estcifern\u00fd k\u00f3d z aplikace a ov\u011b\u0159te nastaven\u00ed. Pokud m\u00e1te probl\u00e9my se skenov\u00e1n\u00edm k\u00f3du QR, prove\u010fte ru\u010dn\u00ed nastaven\u00ed s k\u00f3dem **`{code}`**.", "title": "Nastavte dvoufaktorovou ov\u011b\u0159ov\u00e1n\u00ed pomoc\u00ed TOTP" } }, diff --git a/homeassistant/components/auth/translations/pl.json b/homeassistant/components/auth/translations/pl.json index 954c6d6c009..e0d4db0e171 100644 --- a/homeassistant/components/auth/translations/pl.json +++ b/homeassistant/components/auth/translations/pl.json @@ -10,7 +10,7 @@ "step": { "init": { "description": "Prosz\u0119 wybra\u0107 jedn\u0105 us\u0142ug\u0119 powiadamiania:", - "title": "Skonfiguruj has\u0142o jednorazowe dostarczone przez komponent powiadomie\u0144" + "title": "Konfiguracja jednorazowego has\u0142a dostarczonego przez komponent powiadomie\u0144" }, "setup": { "description": "Has\u0142o jednorazowe zosta\u0142o wys\u0142ane przez **notify.{notify_service}**. Wprowad\u017a je poni\u017cej:", @@ -26,7 +26,7 @@ "step": { "init": { "description": "Aby aktywowa\u0107 uwierzytelnianie dwusk\u0142adnikowe przy u\u017cyciu jednorazowych hase\u0142 opartych na czasie, zeskanuj kod QR za pomoc\u0105 aplikacji uwierzytelniaj\u0105cej. Je\u015bli jej nie masz, polecamy [Google Authenticator](https://support.google.com/accounts/answer/1066447) lub [Authy](https://authy.com/).\n\n{qr_code} \n \nPo zeskanowaniu kodu wprowad\u017a sze\u015bciocyfrowy kod z aplikacji, aby zweryfikowa\u0107 konfiguracj\u0119. Je\u015bli masz problemy z zeskanowaniem kodu QR, wykonaj r\u0119czn\u0105 konfiguracj\u0119 z kodem **`{code}`**.", - "title": "Skonfiguruj uwierzytelnianie dwusk\u0142adnikowe za pomoc\u0105 hase\u0142 jednorazowych opartych na czasie" + "title": "Konfiguracja uwierzytelniania dwusk\u0142adnikowego za pomoc\u0105 hase\u0142 jednorazowych opartych na czasie (TOTP)" } }, "title": "Has\u0142a jednorazowe oparte na czasie" diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index dff751956a7..0989ed43495 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -1,9 +1,11 @@ """Allow to set up simple automation rules via the config file.""" import logging -from typing import Any, Awaitable, Callable, List, Optional, Set, cast +from typing import Any, Awaitable, Callable, Dict, List, Optional, Set, Union, cast import voluptuous as vol +from voluptuous.humanize import humanize_error +from homeassistant.components import blueprint from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_NAME, @@ -47,6 +49,7 @@ from homeassistant.helpers.script import ( ) from homeassistant.helpers.script_variables import ScriptVariables from homeassistant.helpers.service import async_register_admin_service +from homeassistant.helpers.singleton import singleton from homeassistant.helpers.trigger import async_initialize_triggers from homeassistant.helpers.typing import TemplateVarsType from homeassistant.loader import bind_hass @@ -58,7 +61,7 @@ from homeassistant.util.dt import parse_datetime DOMAIN = "automation" ENTITY_ID_FORMAT = DOMAIN + ".{}" -GROUP_NAME_ALL_AUTOMATIONS = "all automations" +DATA_BLUEPRINTS = "automation_blueprints" CONF_DESCRIPTION = "description" CONF_HIDE_ENTITY = "hide_entity" @@ -70,13 +73,9 @@ CONF_CONDITION_TYPE = "condition_type" CONF_INITIAL_STATE = "initial_state" CONF_SKIP_CONDITION = "skip_condition" CONF_STOP_ACTIONS = "stop_actions" +CONF_BLUEPRINT = "blueprint" +CONF_INPUT = "input" -CONDITION_USE_TRIGGER_VALUES = "use_trigger_values" -CONDITION_TYPE_AND = "and" -CONDITION_TYPE_NOT = "not" -CONDITION_TYPE_OR = "or" - -DEFAULT_CONDITION_TYPE = CONDITION_TYPE_AND DEFAULT_INITIAL_STATE = True DEFAULT_STOP_ACTIONS = True @@ -114,6 +113,13 @@ PLATFORM_SCHEMA = vol.All( ) +@singleton(DATA_BLUEPRINTS) +@callback +def async_get_blueprints(hass: HomeAssistant) -> blueprint.DomainBlueprints: # type: ignore + """Get automation blueprints.""" + return blueprint.DomainBlueprints(hass, DOMAIN, _LOGGER) # type: ignore + + @bind_hass def is_on(hass, entity_id): """ @@ -221,6 +227,7 @@ async def async_setup(hass, config): conf = await component.async_prepare_reload() if conf is None: return + async_get_blueprints(hass).async_reset_cache() await _async_process_config(hass, conf, component) hass.bus.async_fire(EVENT_AUTOMATION_RELOADED, context=service_call.context) @@ -506,7 +513,11 @@ class AutomationEntity(ToggleEntity, RestoreEntity): return {CONF_ID: self._id} -async def _async_process_config(hass, config, component): +async def _async_process_config( + hass: HomeAssistant, + config: Dict[str, Any], + component: EntityComponent, +) -> None: """Process config and add automations. This method is a coroutine. @@ -514,9 +525,28 @@ async def _async_process_config(hass, config, component): entities = [] for config_key in extract_domain_configs(config, DOMAIN): - conf = config[config_key] + conf: List[Union[Dict[str, Any], blueprint.BlueprintInputs]] = config[ # type: ignore + config_key + ] for list_no, config_block in enumerate(conf): + if isinstance(config_block, blueprint.BlueprintInputs): # type: ignore + blueprint_inputs = config_block + + try: + config_block = cast( + Dict[str, Any], + PLATFORM_SCHEMA(blueprint_inputs.async_substitute()), + ) + except vol.Invalid as err: + _LOGGER.error( + "Blueprint %s generated invalid automation with inputs %s: %s", + blueprint_inputs.blueprint.name, + blueprint_inputs.inputs, + humanize_error(config_block, err), + ) + continue + automation_id = config_block.get(CONF_ID) name = config_block.get(CONF_ALIAS) or f"{config_key} {list_no}" diff --git a/homeassistant/components/automation/config.py b/homeassistant/components/automation/config.py index 3a296178aeb..c5aa8a62a15 100644 --- a/homeassistant/components/automation/config.py +++ b/homeassistant/components/automation/config.py @@ -3,6 +3,7 @@ import asyncio import voluptuous as vol +from homeassistant.components import blueprint from homeassistant.components.device_automation.exceptions import ( InvalidDeviceAutomationConfig, ) @@ -14,7 +15,14 @@ from homeassistant.helpers.script import async_validate_actions_config from homeassistant.helpers.trigger import async_validate_trigger_config from homeassistant.loader import IntegrationNotFound -from . import CONF_ACTION, CONF_CONDITION, CONF_TRIGGER, DOMAIN, PLATFORM_SCHEMA +from . import ( + CONF_ACTION, + CONF_CONDITION, + CONF_TRIGGER, + DOMAIN, + PLATFORM_SCHEMA, + async_get_blueprints, +) # mypy: allow-untyped-calls, allow-untyped-defs # mypy: no-check-untyped-defs, no-warn-return-any @@ -22,6 +30,10 @@ from . import CONF_ACTION, CONF_CONDITION, CONF_TRIGGER, DOMAIN, PLATFORM_SCHEMA async def async_validate_config_item(hass, config, full_config=None): """Validate config item.""" + if blueprint.is_blueprint_instance_config(config): + blueprints = async_get_blueprints(hass) + return await blueprints.async_inputs_from_config(config) + config = PLATFORM_SCHEMA(config) config[CONF_TRIGGER] = await async_validate_trigger_config( diff --git a/homeassistant/components/automation/manifest.json b/homeassistant/components/automation/manifest.json index a8dc43844e0..2db56eb597f 100644 --- a/homeassistant/components/automation/manifest.json +++ b/homeassistant/components/automation/manifest.json @@ -2,6 +2,7 @@ "domain": "automation", "name": "Automation", "documentation": "https://www.home-assistant.io/integrations/automation", + "dependencies": ["blueprint"], "after_dependencies": [ "device_automation", "webhook" diff --git a/homeassistant/components/automation/translations/no.json b/homeassistant/components/automation/translations/no.json index 13f5ad1c642..64e00db42ca 100644 --- a/homeassistant/components/automation/translations/no.json +++ b/homeassistant/components/automation/translations/no.json @@ -5,5 +5,5 @@ "on": "P\u00e5" } }, - "title": "Automatisering" + "title": "Automasjon" } \ No newline at end of file diff --git a/homeassistant/components/avea/manifest.json b/homeassistant/components/avea/manifest.json index 729219d8f1d..8d39600ed46 100644 --- a/homeassistant/components/avea/manifest.json +++ b/homeassistant/components/avea/manifest.json @@ -3,5 +3,5 @@ "name": "Elgato Avea", "documentation": "https://www.home-assistant.io/integrations/avea", "codeowners": ["@pattyland"], - "requirements": ["avea==1.4"] + "requirements": ["avea==1.5"] } diff --git a/homeassistant/components/avri/strings.json b/homeassistant/components/avri/strings.json index 4bc2556f700..e00409ffa26 100644 --- a/homeassistant/components/avri/strings.json +++ b/homeassistant/components/avri/strings.json @@ -1,5 +1,4 @@ { - "title": "Avri", "config": { "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_location%]" diff --git a/homeassistant/components/avri/translations/ca.json b/homeassistant/components/avri/translations/ca.json index 46c7387a2ae..77edbd49901 100644 --- a/homeassistant/components/avri/translations/ca.json +++ b/homeassistant/components/avri/translations/ca.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/cs.json b/homeassistant/components/avri/translations/cs.json index fc62440d48c..e46abc942c9 100644 --- a/homeassistant/components/avri/translations/cs.json +++ b/homeassistant/components/avri/translations/cs.json @@ -4,6 +4,7 @@ "already_configured": "Um\u00edst\u011bn\u00ed je ji\u017e nastaveno" }, "error": { + "invalid_country_code": "Nezn\u00e1m\u00fd dvoup\u00edsmenn\u00fd k\u00f3d zem\u011b.", "invalid_house_number": "Neplatn\u00e9 \u010d\u00edslo domu." }, "step": { @@ -14,9 +15,9 @@ "house_number_extension": "Roz\u0161\u00ed\u0159en\u00ed \u010d\u00edsla domu", "zip_code": "PS\u010c" }, + "description": "Zadejte svou adresu", "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/de.json b/homeassistant/components/avri/translations/de.json index 94a3034adad..fc0ece086a7 100644 --- a/homeassistant/components/avri/translations/de.json +++ b/homeassistant/components/avri/translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Position ist bereits konfiguriert" + }, "error": { "invalid_house_number": "Ung\u00fcltige Hausnummer" }, @@ -13,6 +16,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/en.json b/homeassistant/components/avri/translations/en.json index 2965d7c86a9..832849a7060 100644 --- a/homeassistant/components/avri/translations/en.json +++ b/homeassistant/components/avri/translations/en.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/es.json b/homeassistant/components/avri/translations/es.json index 72babfb71a0..11539723fab 100644 --- a/homeassistant/components/avri/translations/es.json +++ b/homeassistant/components/avri/translations/es.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/et.json b/homeassistant/components/avri/translations/et.json index 2cee4be1d36..0e83b893642 100644 --- a/homeassistant/components/avri/translations/et.json +++ b/homeassistant/components/avri/translations/et.json @@ -19,6 +19,5 @@ "title": "" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/fr.json b/homeassistant/components/avri/translations/fr.json index 6d272aaa51e..188f82beae9 100644 --- a/homeassistant/components/avri/translations/fr.json +++ b/homeassistant/components/avri/translations/fr.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/it.json b/homeassistant/components/avri/translations/it.json index c29b78c5e13..50c92e0678a 100644 --- a/homeassistant/components/avri/translations/it.json +++ b/homeassistant/components/avri/translations/it.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/ko.json b/homeassistant/components/avri/translations/ko.json index db2cec3fb16..ab6504519d4 100644 --- a/homeassistant/components/avri/translations/ko.json +++ b/homeassistant/components/avri/translations/ko.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/lb.json b/homeassistant/components/avri/translations/lb.json index 7bbafbce010..657640c2beb 100644 --- a/homeassistant/components/avri/translations/lb.json +++ b/homeassistant/components/avri/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "D\u00ebs Adress ass scho konfigur\u00e9iert." + "already_configured": "Standuert ass scho konfigur\u00e9iert." }, "error": { "invalid_country_code": "Onbekannte Zweestellege L\u00e4nner Code", @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/nl.json b/homeassistant/components/avri/translations/nl.json new file mode 100644 index 00000000000..a5be62bfc13 --- /dev/null +++ b/homeassistant/components/avri/translations/nl.json @@ -0,0 +1,10 @@ +{ + "config": { + "abort": { + "already_configured": "Locatie is al geconfigureerd" + }, + "error": { + "invalid_country_code": "Onbekende 2-letterige landcode." + } + } +} \ No newline at end of file diff --git a/homeassistant/components/avri/translations/no.json b/homeassistant/components/avri/translations/no.json index 87e1e583f1e..3f1edaf4c7d 100644 --- a/homeassistant/components/avri/translations/no.json +++ b/homeassistant/components/avri/translations/no.json @@ -19,6 +19,5 @@ "title": "" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/pl.json b/homeassistant/components/avri/translations/pl.json index b092134fcdc..dfe3f85a38d 100644 --- a/homeassistant/components/avri/translations/pl.json +++ b/homeassistant/components/avri/translations/pl.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/ru.json b/homeassistant/components/avri/translations/ru.json index e0fd8dc1a17..01003d0e9d0 100644 --- a/homeassistant/components/avri/translations/ru.json +++ b/homeassistant/components/avri/translations/ru.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/avri/translations/zh-Hant.json b/homeassistant/components/avri/translations/zh-Hant.json index f127418c2d8..566a9e43dc0 100644 --- a/homeassistant/components/avri/translations/zh-Hant.json +++ b/homeassistant/components/avri/translations/zh-Hant.json @@ -19,6 +19,5 @@ "title": "Avri" } } - }, - "title": "Avri" + } } \ No newline at end of file diff --git a/homeassistant/components/awair/translations/ca.json b/homeassistant/components/awair/translations/ca.json index 43e76eecb93..2e75af9e744 100644 --- a/homeassistant/components/awair/translations/ca.json +++ b/homeassistant/components/awair/translations/ca.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "El compte ja ha estat configurat", - "no_devices": "No s'han trobat dispositius a la xarxa", "no_devices_found": "No s'han trobat dispositius a la xarxa", "reauth_successful": "Re-autenticaci\u00f3 realitzada correctament" }, "error": { - "auth": "Token d'acc\u00e9s no v\u00e0lid", "invalid_access_token": "Token d'acc\u00e9s no v\u00e0lid", "unknown": "Error inesperat" }, diff --git a/homeassistant/components/awair/translations/cs.json b/homeassistant/components/awair/translations/cs.json index 8ad3bde6239..dfc83778bf9 100644 --- a/homeassistant/components/awair/translations/cs.json +++ b/homeassistant/components/awair/translations/cs.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "\u00da\u010det je ji\u017e nastaven", - "no_devices": "V s\u00edti nebyla nalezena \u017e\u00e1dn\u00e1 za\u0159\u00edzen\u00ed", "no_devices_found": "V s\u00edti nebyla nalezena \u017e\u00e1dn\u00e1 za\u0159\u00edzen\u00ed", "reauth_successful": "Op\u011btovn\u00e9 ov\u011b\u0159en\u00ed bylo \u00fasp\u011b\u0161n\u00e9" }, "error": { - "auth": "Neplatn\u00fd p\u0159\u00edstupov\u00fd token", "invalid_access_token": "Neplatn\u00fd p\u0159\u00edstupov\u00fd token", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, @@ -22,7 +20,8 @@ "data": { "access_token": "P\u0159\u00edstupov\u00fd token", "email": "E-mail" - } + }, + "description": "Pro p\u0159\u00edstupov\u00fd token v\u00fdvoj\u00e1\u0159e Awair se mus\u00edte zaregistrovat na: https://developer.getawair.com/onboard/login" } } } diff --git a/homeassistant/components/awair/translations/en.json b/homeassistant/components/awair/translations/en.json index 9dbf003bb43..0e5a1e62bb5 100644 --- a/homeassistant/components/awair/translations/en.json +++ b/homeassistant/components/awair/translations/en.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Account is already configured", - "no_devices": "No devices found on the network", "no_devices_found": "No devices found on the network", "reauth_successful": "Re-authentication was successful" }, "error": { - "auth": "Invalid access token", "invalid_access_token": "Invalid access token", "unknown": "Unexpected error" }, diff --git a/homeassistant/components/awair/translations/es.json b/homeassistant/components/awair/translations/es.json index 272b042bd9d..e87ce031b95 100644 --- a/homeassistant/components/awair/translations/es.json +++ b/homeassistant/components/awair/translations/es.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "La cuenta ya ha sido configurada", - "no_devices": "No se encontraron dispositivos en la red", "no_devices_found": "No se encontraron dispositivos en la red", "reauth_successful": "La reautenticaci\u00f3n se realiz\u00f3 correctamente" }, "error": { - "auth": "Token de acceso no v\u00e1lido", "invalid_access_token": "Token de acceso no v\u00e1lido", "unknown": "Error inesperado" }, diff --git a/homeassistant/components/awair/translations/et.json b/homeassistant/components/awair/translations/et.json index 9035f154362..ad96a767f2a 100644 --- a/homeassistant/components/awair/translations/et.json +++ b/homeassistant/components/awair/translations/et.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Konto on juba seadistatud", - "no_devices": "V\u00f5rgust ei leitud seadmeid", "no_devices_found": "V\u00f5rgust ei leitud Awair seadmeid", "reauth_successful": "Taasautentimine \u00f5nnestus" }, "error": { - "auth": "Vigane juurdep\u00e4\u00e4sut\u00f5end", "invalid_access_token": "Vigane juurdep\u00e4\u00e4sut\u00f5end", "unknown": "Tundmatu viga" }, diff --git a/homeassistant/components/awair/translations/fr.json b/homeassistant/components/awair/translations/fr.json index e5d7a277b77..dd90f940977 100644 --- a/homeassistant/components/awair/translations/fr.json +++ b/homeassistant/components/awair/translations/fr.json @@ -2,11 +2,11 @@ "config": { "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/awair/translations/it.json b/homeassistant/components/awair/translations/it.json index 92f1efa153a..085796f9263 100644 --- a/homeassistant/components/awair/translations/it.json +++ b/homeassistant/components/awair/translations/it.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "L'account \u00e8 gi\u00e0 configurato", - "no_devices": "Nessun dispositivo trovato sulla rete", "no_devices_found": "Nessun dispositivo trovato sulla rete", "reauth_successful": "La riautenticazione ha avuto successo" }, "error": { - "auth": "Token di accesso non valido", "invalid_access_token": "Token di accesso non valido", "unknown": "Errore imprevisto" }, diff --git a/homeassistant/components/awair/translations/ko.json b/homeassistant/components/awair/translations/ko.json index fcdf04e8b8a..977532de45d 100644 --- a/homeassistant/components/awair/translations/ko.json +++ b/homeassistant/components/awair/translations/ko.json @@ -2,11 +2,9 @@ "config": { "abort": { "already_configured": "\uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "no_devices": "\ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \uae30\uae30\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", "reauth_successful": "\uc561\uc138\uc2a4 \ud1a0\ud070\uc774 \uc131\uacf5\uc801\uc73c\ub85c \uc5c5\ub370\uc774\ud2b8\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "error": { - "auth": "\uc561\uc138\uc2a4 \ud1a0\ud070\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "unknown": "\uc54c \uc218 \uc5c6\ub294 Awair API \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4." }, "step": { diff --git a/homeassistant/components/awair/translations/lb.json b/homeassistant/components/awair/translations/lb.json index e11640adcca..cb2f758113a 100644 --- a/homeassistant/components/awair/translations/lb.json +++ b/homeassistant/components/awair/translations/lb.json @@ -2,12 +2,12 @@ "config": { "abort": { "already_configured": "Kont ass", - "no_devices": "Keng Apparater am Netzwierk fonnt", + "no_devices_found": "Keng Apparater am Netzwierk fonnt", "reauth_successful": "Erfollegr\u00e4ich aktualis\u00e9iert" }, "error": { - "auth": "Ong\u00ebltege Acc\u00e8s Jeton", - "unknown": "Onbekannten Awair API Feeler" + "invalid_access_token": "Ong\u00ebltegen Acc\u00e8s jeton", + "unknown": "Onerwaarte Feeler" }, "step": { "reauth": { diff --git a/homeassistant/components/awair/translations/nl.json b/homeassistant/components/awair/translations/nl.json index a11016f8d42..08a30a52250 100644 --- a/homeassistant/components/awair/translations/nl.json +++ b/homeassistant/components/awair/translations/nl.json @@ -3,6 +3,14 @@ "abort": { "already_configured": "Account is al geconfigureerd", "no_devices_found": "Geen apparaten op het netwerk gevonden" + }, + "error": { + "unknown": "Onverwachte fout" + }, + "step": { + "reauth": { + "description": "Voer uw Awair-ontwikkelaarstoegangstoken opnieuw in." + } } } } \ No newline at end of file diff --git a/homeassistant/components/awair/translations/no.json b/homeassistant/components/awair/translations/no.json index f715950a4b4..43ffe5960c7 100644 --- a/homeassistant/components/awair/translations/no.json +++ b/homeassistant/components/awair/translations/no.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Kontoen er allerede konfigurert", - "no_devices": "Ingen enheter funnet p\u00e5 nettverket", "no_devices_found": "Ingen enheter funnet p\u00e5 nettverket", "reauth_successful": "Reautentisering var vellykket" }, "error": { - "auth": "Ugyldig tilgangstoken", "invalid_access_token": "Ugyldig tilgangstoken", "unknown": "Uventet feil" }, diff --git a/homeassistant/components/awair/translations/pl.json b/homeassistant/components/awair/translations/pl.json index ad741308943..38bd24f714b 100644 --- a/homeassistant/components/awair/translations/pl.json +++ b/homeassistant/components/awair/translations/pl.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Konto jest ju\u017c skonfigurowane", - "no_devices": "Nie znaleziono urz\u0105dze\u0144 w sieci", "no_devices_found": "Nie znaleziono urz\u0105dze\u0144 w sieci", "reauth_successful": "Ponowne uwierzytelnienie powiod\u0142o si\u0119" }, "error": { - "auth": "Token dost\u0119pu", "invalid_access_token": "Niepoprawny token dost\u0119pu", "unknown": "Nieoczekiwany b\u0142\u0105d" }, diff --git a/homeassistant/components/awair/translations/pt.json b/homeassistant/components/awair/translations/pt.json index 59d5e90ef15..a637b68b0ba 100644 --- a/homeassistant/components/awair/translations/pt.json +++ b/homeassistant/components/awair/translations/pt.json @@ -2,12 +2,8 @@ "config": { "abort": { "already_configured": "Conta j\u00e1 configurada", - "no_devices": "Nenhum dispositivo encontrado na rede", "reauth_successful": "Token de Acesso actualizado com sucesso" }, - "error": { - "auth": "Token de acesso inv\u00e1lido" - }, "step": { "reauth": { "data": { diff --git a/homeassistant/components/awair/translations/ru.json b/homeassistant/components/awair/translations/ru.json index d1831164587..05a14ce7857 100644 --- a/homeassistant/components/awair/translations/ru.json +++ b/homeassistant/components/awair/translations/ru.json @@ -2,12 +2,10 @@ "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.", - "no_devices": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u0441\u0435\u0442\u0438.", "no_devices_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u0441\u0435\u0442\u0438.", "reauth_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e." }, "error": { - "auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430.", "invalid_access_token": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, diff --git a/homeassistant/components/awair/translations/zh-Hant.json b/homeassistant/components/awair/translations/zh-Hant.json index bc2a9d36b16..8b40a8edefc 100644 --- a/homeassistant/components/awair/translations/zh-Hant.json +++ b/homeassistant/components/awair/translations/zh-Hant.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "no_devices": "\u7db2\u8def\u4e0a\u627e\u4e0d\u5230\u8a2d\u5099", "no_devices_found": "\u7db2\u8def\u4e0a\u627e\u4e0d\u5230\u8a2d\u5099", "reauth_successful": "\u91cd\u65b0\u8a8d\u8b49\u6210\u529f" }, "error": { - "auth": "\u5b58\u53d6\u5bc6\u9470\u7121\u6548", "invalid_access_token": "\u5b58\u53d6\u5bc6\u9470\u7121\u6548", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, diff --git a/homeassistant/components/axis/translations/bg.json b/homeassistant/components/axis/translations/bg.json index d5bf9373112..2cbf383cea8 100644 --- a/homeassistant/components/axis/translations/bg.json +++ b/homeassistant/components/axis/translations/bg.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u043e", - "bad_config_file": "\u041b\u043e\u0448\u0438 \u0434\u0430\u043d\u043d\u0438 \u043e\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0438\u044f \u0444\u0430\u0439\u043b", "link_local_address": "\u041b\u043e\u043a\u0430\u043b\u043d\u0438 \u0430\u0434\u0440\u0435\u0441\u0438 \u043d\u0435 \u0441\u0435 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430\u0442", "not_axis_device": "\u041e\u0442\u043a\u0440\u0438\u0442\u043e\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435 \u0435 Axis" }, "error": { "already_configured": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u043e", - "already_in_progress": "\u0412 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0442\u0435\u0447\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e.", - "device_unavailable": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u043d\u0435 \u0435 \u043d\u0430\u043b\u0438\u0447\u043d\u043e", - "faulty_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438" + "already_in_progress": "\u0412 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0442\u0435\u0447\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e." }, "flow_title": "Axis \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/ca.json b/homeassistant/components/axis/translations/ca.json index 209e9713bae..26da6057dc1 100644 --- a/homeassistant/components/axis/translations/ca.json +++ b/homeassistant/components/axis/translations/ca.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", - "bad_config_file": "Dades del fitxer de configuraci\u00f3 incorrectes", "link_local_address": "L'enlla\u00e7 d'adreces locals no est\u00e0 disponible", "not_axis_device": "El dispositiu descobert no \u00e9s un dispositiu Axis" }, @@ -10,8 +9,6 @@ "already_configured": "El dispositiu ja est\u00e0 configurat", "already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs", "cannot_connect": "Ha fallat la connexi\u00f3", - "device_unavailable": "El dispositiu no est\u00e0 disponible", - "faulty_credentials": "Credencials d'usuari incorrectes", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "flow_title": "Dispositiu d'eix: {name} ({host})", diff --git a/homeassistant/components/axis/translations/cs.json b/homeassistant/components/axis/translations/cs.json index e6fc40692b2..fd99c68ab35 100644 --- a/homeassistant/components/axis/translations/cs.json +++ b/homeassistant/components/axis/translations/cs.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "bad_config_file": "Chybn\u00e1 data z konfigura\u010dn\u00edho souboru", "link_local_address": "Propojen\u00ed m\u00edstn\u00edch adres nen\u00ed podporov\u00e1no", "not_axis_device": "Objeven\u00e9 za\u0159\u00edzen\u00ed nen\u00ed za\u0159\u00edzen\u00ed Axis" }, @@ -10,8 +9,6 @@ "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "device_unavailable": "Za\u0159\u00edzen\u00ed nen\u00ed k dispozici", - "faulty_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "flow_title": "Za\u0159\u00edzen\u00ed Axis: {name} ({host})", @@ -26,5 +23,15 @@ "title": "Nastaven\u00ed za\u0159\u00edzen\u00ed Axis" } } + }, + "options": { + "step": { + "configure_stream": { + "data": { + "stream_profile": "Vyberte profil streamu, kter\u00fd chcete pou\u017e\u00edt" + }, + "title": "Mo\u017enosti video streamu za\u0159\u00edzen\u00ed Axis" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/axis/translations/da.json b/homeassistant/components/axis/translations/da.json index 3f2130238a2..e449ac98053 100644 --- a/homeassistant/components/axis/translations/da.json +++ b/homeassistant/components/axis/translations/da.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "Enheden er allerede konfigureret", - "bad_config_file": "Forkerte data fra konfigurationsfilen", "link_local_address": "Link lokale adresser underst\u00f8ttes ikke", "not_axis_device": "Fundet enhed ikke en Axis enhed" }, "error": { "already_configured": "Enheden er allerede konfigureret", - "already_in_progress": "Enhedskonfiguration er allerede i gang.", - "device_unavailable": "Enheden er ikke tilg\u00e6ngelig", - "faulty_credentials": "Ugyldige legitimationsoplysninger" + "already_in_progress": "Enhedskonfiguration er allerede i gang." }, "flow_title": "Axis-enhed: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/de.json b/homeassistant/components/axis/translations/de.json index 7753e5ad1e8..d0309140903 100644 --- a/homeassistant/components/axis/translations/de.json +++ b/homeassistant/components/axis/translations/de.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "Ger\u00e4t ist bereits konfiguriert", - "bad_config_file": "Fehlerhafte Daten aus der Konfigurationsdatei", "link_local_address": "Link-local Adressen werden nicht unterst\u00fctzt", "not_axis_device": "Erkanntes Ger\u00e4t ist kein Axis-Ger\u00e4t" }, "error": { "already_configured": "Ger\u00e4t ist bereits konfiguriert", - "already_in_progress": "Der Konfigurationsablauf f\u00fcr das Ger\u00e4t wird bereits ausgef\u00fchrt.", - "device_unavailable": "Ger\u00e4t ist nicht verf\u00fcgbar", - "faulty_credentials": "Ung\u00fcltige Anmeldeinformationen" + "already_in_progress": "Der Konfigurationsablauf f\u00fcr das Ger\u00e4t wird bereits ausgef\u00fchrt." }, "flow_title": "Achsenger\u00e4t: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/en.json b/homeassistant/components/axis/translations/en.json index f1eb6f3eaf8..6b01533aefa 100644 --- a/homeassistant/components/axis/translations/en.json +++ b/homeassistant/components/axis/translations/en.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Device is already configured", - "bad_config_file": "Bad data from configuration file", "link_local_address": "Link local addresses are not supported", "not_axis_device": "Discovered device not an Axis device" }, @@ -10,8 +9,6 @@ "already_configured": "Device is already configured", "already_in_progress": "Configuration flow is already in progress", "cannot_connect": "Failed to connect", - "device_unavailable": "Device is not available", - "faulty_credentials": "Bad user credentials", "invalid_auth": "Invalid authentication" }, "flow_title": "Axis device: {name} ({host})", diff --git a/homeassistant/components/axis/translations/es-419.json b/homeassistant/components/axis/translations/es-419.json index 151ef346be2..0e1c1e99b36 100644 --- a/homeassistant/components/axis/translations/es-419.json +++ b/homeassistant/components/axis/translations/es-419.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado", - "bad_config_file": "Datos err\u00f3neos del archivo de configuraci\u00f3n", "link_local_address": "Las direcciones locales de enlace no son compatibles", "not_axis_device": "El dispositivo descubierto no es un dispositivo de Axis" }, "error": { "already_configured": "El dispositivo ya est\u00e1 configurado", - "already_in_progress": "El flujo de configuraci\u00f3n para el dispositivo ya est\u00e1 en progreso.", - "device_unavailable": "El dispositivo no est\u00e1 disponible", - "faulty_credentials": "Credenciales de usuario incorrectas" + "already_in_progress": "El flujo de configuraci\u00f3n para el dispositivo ya est\u00e1 en progreso." }, "flow_title": "Dispositivo Axis: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/es.json b/homeassistant/components/axis/translations/es.json index 7118cbfb094..4a47b17c528 100644 --- a/homeassistant/components/axis/translations/es.json +++ b/homeassistant/components/axis/translations/es.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado", - "bad_config_file": "Datos err\u00f3neos en el archivo de configuraci\u00f3n", "link_local_address": "Las direcciones de enlace locales no son compatibles", "not_axis_device": "El dispositivo descubierto no es un dispositivo de Axis" }, @@ -10,8 +9,6 @@ "already_configured": "El dispositivo ya est\u00e1 configurado", "already_in_progress": "El flujo de configuraci\u00f3n del dispositivo ya est\u00e1 en marcha.", "cannot_connect": "No se pudo conectar", - "device_unavailable": "El dispositivo no est\u00e1 disponible", - "faulty_credentials": "Credenciales de usuario incorrectas", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "flow_title": "Dispositivo Axis: {name} ({host})", diff --git a/homeassistant/components/axis/translations/et.json b/homeassistant/components/axis/translations/et.json index ef293713144..6a27e74b287 100644 --- a/homeassistant/components/axis/translations/et.json +++ b/homeassistant/components/axis/translations/et.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "bad_config_file": "Vigane konfiguratsioonikirje", "link_local_address": "Kohtv\u00f5rgu linke ei toetata", "not_axis_device": "Avastatud seade pole Axise seade" }, @@ -10,8 +9,6 @@ "already_configured": "Seade on juba h\u00e4\u00e4lestatud", "already_in_progress": "Seadistamine on juba k\u00e4imas", "cannot_connect": "\u00dchendamine nurjus", - "device_unavailable": "Seade pole saadaval", - "faulty_credentials": "Sobimatu mandaat.", "invalid_auth": "Tuvastamise viga" }, "flow_title": "Axise seade: {name} ({host})", diff --git a/homeassistant/components/axis/translations/fr.json b/homeassistant/components/axis/translations/fr.json index 7ffa3d9dbcf..ed4113d02e2 100644 --- a/homeassistant/components/axis/translations/fr.json +++ b/homeassistant/components/axis/translations/fr.json @@ -2,15 +2,14 @@ "config": { "abort": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", - "bad_config_file": "Mauvaises donn\u00e9es du fichier de configuration", "link_local_address": "Les adresses locales ne sont pas prises en charge", "not_axis_device": "L'appareil d\u00e9couvert n'est pas un appareil Axis" }, "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.", - "device_unavailable": "L'appareil n'est pas disponible", - "faulty_credentials": "Mauvaises informations d'identification de l'utilisateur" + "cannot_connect": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide" }, "flow_title": "Appareil Axis: {name} ( {host} )", "step": { diff --git a/homeassistant/components/axis/translations/hu.json b/homeassistant/components/axis/translations/hu.json index d749df6a783..bb33a36195d 100644 --- a/homeassistant/components/axis/translations/hu.json +++ b/homeassistant/components/axis/translations/hu.json @@ -1,9 +1,7 @@ { "config": { "error": { - "already_configured": "Az eszk\u00f6zt m\u00e1r konfigur\u00e1ltuk", - "device_unavailable": "Az eszk\u00f6z nem \u00e9rhet\u0151 el", - "faulty_credentials": "Rossz felhaszn\u00e1l\u00f3i hiteles\u00edt\u0151 adatok" + "already_configured": "Az eszk\u00f6zt m\u00e1r konfigur\u00e1ltuk" }, "flow_title": "Axis eszk\u00f6z: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/it.json b/homeassistant/components/axis/translations/it.json index bae91d3e511..6461b2a6619 100644 --- a/homeassistant/components/axis/translations/it.json +++ b/homeassistant/components/axis/translations/it.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "bad_config_file": "Dati errati dal file di configurazione", "link_local_address": "Gli indirizzi locali di collegamento non sono supportati", "not_axis_device": "Il dispositivo rilevato non \u00e8 un dispositivo Axis" }, @@ -10,8 +9,6 @@ "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso", "cannot_connect": "Impossibile connettersi", - "device_unavailable": "Il dispositivo non \u00e8 disponibile", - "faulty_credentials": "Credenziali utente non valide", "invalid_auth": "Autenticazione non valida" }, "flow_title": "Dispositivo Axis: {name} ({host})", diff --git a/homeassistant/components/axis/translations/ko.json b/homeassistant/components/axis/translations/ko.json index cb6920b4ae0..f73d467fbf7 100644 --- a/homeassistant/components/axis/translations/ko.json +++ b/homeassistant/components/axis/translations/ko.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "bad_config_file": "\uad6c\uc131 \ud30c\uc77c\uc5d0 \uc798\ubabb\ub41c \ub370\uc774\ud130\uac00 \uc788\uc2b5\ub2c8\ub2e4", "link_local_address": "\ub85c\uceec \uc8fc\uc18c \uc5f0\uacb0\uc740 \uc9c0\uc6d0\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4", "not_axis_device": "\ubc1c\uacac\ub41c \uae30\uae30\ub294 Axis \uae30\uae30\uac00 \uc544\ub2d9\ub2c8\ub2e4" }, "error": { "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "already_in_progress": "\uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4.", - "device_unavailable": "\uae30\uae30\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", - "faulty_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ud639\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" + "already_in_progress": "\uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4." }, "flow_title": "Axis \uae30\uae30: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/lb.json b/homeassistant/components/axis/translations/lb.json index 7299fa76b33..ae5bd8dc7a0 100644 --- a/homeassistant/components/axis/translations/lb.json +++ b/homeassistant/components/axis/translations/lb.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "Apparat ass scho konfigur\u00e9iert", - "bad_config_file": "Feelerhaft Donn\u00e9e\u00eb aus der Konfiguratioun's Datei", "link_local_address": "Lokal Link Adressen ginn net \u00ebnnerst\u00ebtzt", "not_axis_device": "Entdeckten Apparat ass keen Axis Apparat" }, "error": { "already_configured": "Apparat ass scho konfigur\u00e9iert", - "already_in_progress": "Konfiguratioun fir d\u00ebsen Apparat ass schonn am gaang.", + "already_in_progress": "Konfiguratioun's Oflas ass schon am gaang", "cannot_connect": "Feeler beim verbannen", - "device_unavailable": "Apparat ass net erreechbar", - "faulty_credentials": "Ong\u00eblteg Login Informatioune", "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "flow_title": "Axis Apparat: {name} ({host})", diff --git a/homeassistant/components/axis/translations/nl.json b/homeassistant/components/axis/translations/nl.json index 82347254900..483acefec15 100644 --- a/homeassistant/components/axis/translations/nl.json +++ b/homeassistant/components/axis/translations/nl.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "Apparaat is al geconfigureerd", - "bad_config_file": "Slechte gegevens van het configuratiebestand", "link_local_address": "Link-lokale adressen worden niet ondersteund", "not_axis_device": "Ontdekte apparaat, is geen Axis-apparaat" }, "error": { "already_configured": "Apparaat is al geconfigureerd", "already_in_progress": "De configuratiestroom voor het apparaat is al in volle gang.", - "cannot_connect": "Kan geen verbinding maken", - "device_unavailable": "Apparaat is niet beschikbaar", - "faulty_credentials": "Ongeldige gebruikersreferenties" + "cannot_connect": "Kan geen verbinding maken" }, "flow_title": "Axis apparaat: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/no.json b/homeassistant/components/axis/translations/no.json index 771ecc06b02..984d522eba9 100644 --- a/homeassistant/components/axis/translations/no.json +++ b/homeassistant/components/axis/translations/no.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Enheten er allerede konfigurert", - "bad_config_file": "D\u00e5rlige data fra konfigurasjonsfilen", "link_local_address": "Linking av lokale adresser st\u00f8ttes ikke", "not_axis_device": "Oppdaget enhet ikke en Axis enhet" }, @@ -10,8 +9,6 @@ "already_configured": "Enheten er allerede konfigurert", "already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede", "cannot_connect": "Tilkobling mislyktes", - "device_unavailable": "Enheten er ikke tilgjengelig", - "faulty_credentials": "Ugyldig brukerlegitimasjon", "invalid_auth": "Ugyldig godkjenning" }, "flow_title": "Axis enhet: {name} ({host})", diff --git a/homeassistant/components/axis/translations/pl.json b/homeassistant/components/axis/translations/pl.json index 68e7093c7e7..84af845ab31 100644 --- a/homeassistant/components/axis/translations/pl.json +++ b/homeassistant/components/axis/translations/pl.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "bad_config_file": "B\u0142\u0119dne dane z pliku konfiguracyjnego", "link_local_address": "Po\u0142\u0105czenie lokalnego adresu nie jest obs\u0142ugiwane", "not_axis_device": "Wykryte urz\u0105dzenie nie jest urz\u0105dzeniem Axis" }, @@ -10,8 +9,6 @@ "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "already_in_progress": "Konfiguracja jest ju\u017c w toku", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "device_unavailable": "Urz\u0105dzenie jest niedost\u0119pne", - "faulty_credentials": "B\u0142\u0119dne dane uwierzytelniaj\u0105ce", "invalid_auth": "Niepoprawne uwierzytelnienie" }, "flow_title": "Urz\u0105dzenie Axis: {name} ({host})", diff --git a/homeassistant/components/axis/translations/pt-BR.json b/homeassistant/components/axis/translations/pt-BR.json index 0c6ab9249df..86b6d408baa 100644 --- a/homeassistant/components/axis/translations/pt-BR.json +++ b/homeassistant/components/axis/translations/pt-BR.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "O dispositivo j\u00e1 est\u00e1 configurado", - "bad_config_file": "Dados incorretos do arquivo de configura\u00e7\u00e3o", "link_local_address": "Link de endere\u00e7os locais n\u00e3o s\u00e3o suportados", "not_axis_device": "Dispositivo descoberto n\u00e3o \u00e9 um dispositivo Axis" }, "error": { "already_configured": "O dispositivo j\u00e1 est\u00e1 configurado", - "already_in_progress": "O fluxo de configura\u00e7\u00e3o para o dispositivo j\u00e1 est\u00e1 em andamento.", - "device_unavailable": "O dispositivo n\u00e3o est\u00e1 dispon\u00edvel", - "faulty_credentials": "Credenciais do usu\u00e1rio inv\u00e1lidas" + "already_in_progress": "O fluxo de configura\u00e7\u00e3o para o dispositivo j\u00e1 est\u00e1 em andamento." }, "flow_title": "Eixos do dispositivo: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/pt.json b/homeassistant/components/axis/translations/pt.json index 7db65625895..b7cbb547b0f 100644 --- a/homeassistant/components/axis/translations/pt.json +++ b/homeassistant/components/axis/translations/pt.json @@ -2,13 +2,10 @@ "config": { "abort": { "already_configured": "O dispositivo j\u00e1 est\u00e1 configurado", - "bad_config_file": "Dados incorretos do arquivo de configura\u00e7\u00e3o", "link_local_address": "Eendere\u00e7os de liga\u00e7\u00e3o local n\u00e3o s\u00e3o suportados" }, "error": { - "already_configured": "O dispositivo j\u00e1 est\u00e1 configurado", - "device_unavailable": "Dispositivo n\u00e3o est\u00e1 dispon\u00edvel", - "faulty_credentials": "Credenciais do utilizador erradas" + "already_configured": "O dispositivo j\u00e1 est\u00e1 configurado" }, "step": { "user": { diff --git a/homeassistant/components/axis/translations/ru.json b/homeassistant/components/axis/translations/ru.json index e9138a13045..ee1dc8494f3 100644 --- a/homeassistant/components/axis/translations/ru.json +++ b/homeassistant/components/axis/translations/ru.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "bad_config_file": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438.", "link_local_address": "\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0430\u0434\u0440\u0435\u0441\u0430 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f.", "not_axis_device": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c Axis." }, @@ -10,8 +9,6 @@ "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "device_unavailable": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e.", - "faulty_credentials": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "flow_title": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e Axis {name} ({host})", diff --git a/homeassistant/components/axis/translations/sl.json b/homeassistant/components/axis/translations/sl.json index ac7b359b19e..fb7198b2f32 100644 --- a/homeassistant/components/axis/translations/sl.json +++ b/homeassistant/components/axis/translations/sl.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "Naprava je \u017ee konfigurirana", - "bad_config_file": "Slabi podatki iz konfiguracijske datoteke", "link_local_address": "Lokalni naslovi povezave niso podprti", "not_axis_device": "Odkrita naprava ni naprava Axis" }, "error": { "already_configured": "Naprava je \u017ee konfigurirana", - "already_in_progress": "Konfiguracijski tok za to napravo je \u017ee v teku.", - "device_unavailable": "Naprava ni na voljo", - "faulty_credentials": "Napa\u010dni uporabni\u0161ki podatki" + "already_in_progress": "Konfiguracijski tok za to napravo je \u017ee v teku." }, "flow_title": "OS naprava: {Name} ({Host})", "step": { diff --git a/homeassistant/components/axis/translations/sv.json b/homeassistant/components/axis/translations/sv.json index f7c2e8902f7..22e9344b64d 100644 --- a/homeassistant/components/axis/translations/sv.json +++ b/homeassistant/components/axis/translations/sv.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "Enheten \u00e4r redan konfigurerad", - "bad_config_file": "Felaktig data fr\u00e5n konfigurationsfilen", "link_local_address": "Link local addresses are not supported", "not_axis_device": "Uppt\u00e4ckte enhet som inte \u00e4r en Axis enhet" }, "error": { "already_configured": "Enheten \u00e4r redan konfigurerad", - "already_in_progress": "Konfigurations fl\u00f6det f\u00f6r enheten p\u00e5g\u00e5r redan.", - "device_unavailable": "Enheten \u00e4r inte tillg\u00e4nglig", - "faulty_credentials": "Felaktiga anv\u00e4ndaruppgifter" + "already_in_progress": "Konfigurations fl\u00f6det f\u00f6r enheten p\u00e5g\u00e5r redan." }, "flow_title": "Axisenhet: {name} ({host})", "step": { diff --git a/homeassistant/components/axis/translations/zh-Hans.json b/homeassistant/components/axis/translations/zh-Hans.json index f7f6c8259ce..32d738d838d 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/axis/translations/zh-Hant.json b/homeassistant/components/axis/translations/zh-Hant.json index fc81b43c2be..07cc81cc0fd 100644 --- a/homeassistant/components/axis/translations/zh-Hant.json +++ b/homeassistant/components/axis/translations/zh-Hant.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "bad_config_file": "\u8a2d\u5b9a\u6a94\u6848\u8cc7\u6599\u7121\u6548\u932f\u8aa4", "link_local_address": "\u4e0d\u652f\u63f4\u9023\u7d50\u672c\u5730\u7aef\u4f4d\u5740", "not_axis_device": "\u6240\u767c\u73fe\u7684\u8a2d\u5099\u4e26\u975e Axis \u8a2d\u5099" }, @@ -10,8 +9,6 @@ "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "device_unavailable": "\u8a2d\u5099\u7121\u6cd5\u4f7f\u7528", - "faulty_credentials": "\u4f7f\u7528\u8005\u6191\u8b49\u7121\u6548", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "flow_title": "Axis \u8a2d\u5099\uff1a{name} ({host})", diff --git a/homeassistant/components/azure_devops/strings.json b/homeassistant/components/azure_devops/strings.json index 6c274404612..a0e2bbf864a 100644 --- a/homeassistant/components/azure_devops/strings.json +++ b/homeassistant/components/azure_devops/strings.json @@ -28,6 +28,5 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_account%]", "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" } - }, - "title": "Azure DevOps" + } } diff --git a/homeassistant/components/azure_devops/translations/ca.json b/homeassistant/components/azure_devops/translations/ca.json index 6622fb4f954..92dbd2e3e40 100644 --- a/homeassistant/components/azure_devops/translations/ca.json +++ b/homeassistant/components/azure_devops/translations/ca.json @@ -5,9 +5,7 @@ "reauth_successful": "Re-autenticaci\u00f3 realitzada correctament" }, "error": { - "authorization_error": "Error d'autoritzaci\u00f3. Comprova que tens acc\u00e9s al projecte i tens les credencials correctes.", "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar a Azure DevOps.", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", "project_error": "No s'ha pogut obtenir la informaci\u00f3 del projecte." }, @@ -30,6 +28,5 @@ "title": "Afegeix un projecte Azure DevOps" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/cs.json b/homeassistant/components/azure_devops/translations/cs.json index 938fee05510..8ad9968e157 100644 --- a/homeassistant/components/azure_devops/translations/cs.json +++ b/homeassistant/components/azure_devops/translations/cs.json @@ -5,9 +5,7 @@ "reauth_successful": "Op\u011btovn\u00e9 ov\u011b\u0159en\u00ed bylo \u00fasp\u011b\u0161n\u00e9" }, "error": { - "authorization_error": "Chyba autorizace. Zkontrolujte, zda m\u00e1te p\u0159\u00edstup k projektu a zda m\u00e1te spr\u00e1vn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje.", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nelze se p\u0159ipojit k Azure DevOps.", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "project_error": "Nelze z\u00edskat informace o projektu." }, @@ -17,6 +15,7 @@ "data": { "personal_access_token": "Osobn\u00ed p\u0159\u00edstupov\u00fd token (PAT)" }, + "description": "Ov\u011b\u0159en\u00ed pro {project_url} se nezda\u0159ilo. Zadejte sv\u00e9 aktu\u00e1ln\u00ed p\u0159ihla\u0161ovac\u00ed \u00fadaje.", "title": "Op\u011btovn\u00e9 ov\u011b\u0159en\u00ed" }, "user": { @@ -28,6 +27,5 @@ "title": "P\u0159idejte projekt Azure DevOps" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/en.json b/homeassistant/components/azure_devops/translations/en.json index 58d1dca7c76..b0f803778f8 100644 --- a/homeassistant/components/azure_devops/translations/en.json +++ b/homeassistant/components/azure_devops/translations/en.json @@ -5,9 +5,7 @@ "reauth_successful": "Re-authentication was successful" }, "error": { - "authorization_error": "Authorization error. Check you have access to the project and have the correct credentials.", "cannot_connect": "Failed to connect", - "connection_error": "Could not connect to Azure DevOps.", "invalid_auth": "Invalid authentication", "project_error": "Could not get project info." }, @@ -30,6 +28,5 @@ "title": "Add Azure DevOps Project" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/es.json b/homeassistant/components/azure_devops/translations/es.json index ccf4658d727..1055fdebf41 100644 --- a/homeassistant/components/azure_devops/translations/es.json +++ b/homeassistant/components/azure_devops/translations/es.json @@ -5,8 +5,8 @@ "reauth_successful": "Token de acceso actualizado correctamente " }, "error": { - "authorization_error": "Error de autorizaci\u00f3n. Comprueba que tienes acceso al proyecto y las credenciales son correctas.", - "connection_error": "No se pudo conectar con Azure DevOps", + "cannot_connect": "No se pudo conectar", + "invalid_auth": "Autenticaci\u00f3n inv\u00e1lida", "project_error": "No se pudo obtener informaci\u00f3n del proyecto." }, "flow_title": "Azure DevOps: {project_url}", @@ -28,6 +28,5 @@ "title": "A\u00f1adir Proyecto Azure DevOps" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/et.json b/homeassistant/components/azure_devops/translations/et.json index 1329b02c32a..f9f9334ec5c 100644 --- a/homeassistant/components/azure_devops/translations/et.json +++ b/homeassistant/components/azure_devops/translations/et.json @@ -5,9 +5,7 @@ "reauth_successful": "Taasautentimine \u00f5nnestus" }, "error": { - "authorization_error": "Tuvastusviga. Kontrolli kas sul on juurdep\u00e4\u00e4s projektile ja kas sul on \u00f5iged volitused.", "cannot_connect": "\u00dchendus nurjus", - "connection_error": "Azure DevOpsiga ei saanud \u00fchendust luua.", "invalid_auth": "Tuvastamise viga", "project_error": "Projekti teavet ei \u00f5nnestunud hankida." }, @@ -30,6 +28,5 @@ "title": "Lisa Azure DevOps Project" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/fr.json b/homeassistant/components/azure_devops/translations/fr.json index 528c76767ea..edcf3dda517 100644 --- a/homeassistant/components/azure_devops/translations/fr.json +++ b/homeassistant/components/azure_devops/translations/fr.json @@ -5,8 +5,8 @@ "reauth_successful": "Jeton d'acc\u00e8s mis \u00e0 jour avec succ\u00e8s" }, "error": { - "authorization_error": "Erreur d'autorisation. V\u00e9rifiez que vous avez acc\u00e8s au projet et que vous disposez des informations d'identification correctes.", - "connection_error": "Impossible de se connecter \u00e0 Azure DevOps.", + "cannot_connect": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide", "project_error": "Impossible d'obtenir les informations sur le projet." }, "flow_title": "Azure DevOps: {project_url}", @@ -28,6 +28,5 @@ "title": "Ajouter un projet Azure DevOps" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/it.json b/homeassistant/components/azure_devops/translations/it.json index d3a2b2dae6e..849e65b933f 100644 --- a/homeassistant/components/azure_devops/translations/it.json +++ b/homeassistant/components/azure_devops/translations/it.json @@ -5,8 +5,8 @@ "reauth_successful": "La riautenticazione ha avuto successo" }, "error": { - "authorization_error": "Errore di autorizzazione. Verificare di avere accesso al progetto e disporre delle credenziali corrette.", - "connection_error": "Impossibile connettersi ad Azure DevOps.", + "cannot_connect": "Impossibile connettersi", + "invalid_auth": "Autenticazione non valida", "project_error": "Non \u00e8 stato possibile ottenere informazioni sul progetto." }, "flow_title": "Azure DevOps: {project_url}", @@ -28,6 +28,5 @@ "title": "Aggiungere un progetto Azure DevOps" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/lb.json b/homeassistant/components/azure_devops/translations/lb.json index ae6df660cff..d7b7864e7e3 100644 --- a/homeassistant/components/azure_devops/translations/lb.json +++ b/homeassistant/components/azure_devops/translations/lb.json @@ -2,11 +2,11 @@ "config": { "abort": { "already_configured": "Kont ass scho konfigur\u00e9iert", - "reauth_successful": "Acc\u00e8s Jeton erfollegr\u00e4ich aktualis\u00e9iert" + "reauth_successful": "Re-authentifikatioun war erfollegr\u00e4ich" }, "error": { - "authorization_error": "Feeler bei der Authorisatioun. Iwwerpr\u00e9if ob d\u00e4in Kont den acc\u00e8s zum Projet souw\u00e9i d\u00e9i richteg Umeldungsinformatioune huet", - "connection_error": "Konnt sech net mat Azure DevOps verbannen", + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", "project_error": "Konnt keng Projet Informatiounen ausliesen." }, "flow_title": "Azure DevOps: {project_url}", @@ -28,6 +28,5 @@ "title": "Azure DevOps Project dob\u00e4isetzen" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/nl.json b/homeassistant/components/azure_devops/translations/nl.json index 42978a06b37..9abecd187fe 100644 --- a/homeassistant/components/azure_devops/translations/nl.json +++ b/homeassistant/components/azure_devops/translations/nl.json @@ -2,6 +2,9 @@ "config": { "abort": { "already_configured": "Account is al geconfigureerd" + }, + "error": { + "invalid_auth": "Ongeldige authenticatie" } } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/no.json b/homeassistant/components/azure_devops/translations/no.json index a5b9cc34191..bc649dcadf0 100644 --- a/homeassistant/components/azure_devops/translations/no.json +++ b/homeassistant/components/azure_devops/translations/no.json @@ -5,9 +5,7 @@ "reauth_successful": "Reautentisering var vellykket" }, "error": { - "authorization_error": "Autoriseringsfeil. Sjekk at du har tilgang til prosjektet og har riktig legitimasjon.", "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kunne ikke koble til Azure DevOps.", "invalid_auth": "Ugyldig godkjenning", "project_error": "Kunne ikke f\u00e5 prosjektinformasjon." }, @@ -30,6 +28,5 @@ "title": "Legg til Azure DevOps Project" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/pl.json b/homeassistant/components/azure_devops/translations/pl.json index 5dd93f73a5c..18c4080a696 100644 --- a/homeassistant/components/azure_devops/translations/pl.json +++ b/homeassistant/components/azure_devops/translations/pl.json @@ -5,9 +5,7 @@ "reauth_successful": "Ponowne uwierzytelnienie powiod\u0142o si\u0119" }, "error": { - "authorization_error": "B\u0142\u0105d autoryzacji. Sprawd\u017a, czy masz dost\u0119p do projektu i masz prawid\u0142owe po\u015bwiadczenia.", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z us\u0142ug\u0105 Azure DevOps", "invalid_auth": "Niepoprawne uwierzytelnienie", "project_error": "Nie mo\u017cna uzyska\u0107 informacji o projekcie" }, @@ -30,6 +28,5 @@ "title": "Dodaj projekt Azure DevOps" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/ru.json b/homeassistant/components/azure_devops/translations/ru.json index d7ea5cde1a0..84e0fc93b46 100644 --- a/homeassistant/components/azure_devops/translations/ru.json +++ b/homeassistant/components/azure_devops/translations/ru.json @@ -5,9 +5,7 @@ "reauth_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e." }, "error": { - "authorization_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443 \u0412\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a Azure DevOps.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "project_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0435." }, @@ -30,6 +28,5 @@ "title": "Azure DevOps" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/azure_devops/translations/uk.json b/homeassistant/components/azure_devops/translations/uk.json index f447cfb1a81..4a42fd17fc3 100644 --- a/homeassistant/components/azure_devops/translations/uk.json +++ b/homeassistant/components/azure_devops/translations/uk.json @@ -14,6 +14,5 @@ "title": "\u0414\u043e\u0434\u0430\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442 Azure DevOps" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file 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 00000000000..b0c629646e2 --- /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/azure_devops/translations/zh-Hant.json b/homeassistant/components/azure_devops/translations/zh-Hant.json index 8a4340901fb..b77ce8c54a7 100644 --- a/homeassistant/components/azure_devops/translations/zh-Hant.json +++ b/homeassistant/components/azure_devops/translations/zh-Hant.json @@ -5,9 +5,7 @@ "reauth_successful": "\u91cd\u65b0\u8a8d\u8b49\u6210\u529f" }, "error": { - "authorization_error": "\u8a8d\u8b49\u932f\u8aa4\u3002\u8acb\u78ba\u8a8d\u64c1\u6709\u5c08\u6848\u5b58\u53d6\u6b0a\u8207\u6b63\u78ba\u7684\u8b49\u66f8\u3002", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u7121\u6cd5\u9023\u7dda\u81f3 Azure DevOps\u3002", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", "project_error": "\u7121\u6cd5\u53d6\u5f97\u5c08\u6848\u8cc7\u8a0a\u3002" }, @@ -30,6 +28,5 @@ "title": "\u65b0\u589e Azure DevOps \u5c08\u6848" } } - }, - "title": "Azure DevOps" + } } \ No newline at end of file diff --git a/homeassistant/components/binary_sensor/strings.json b/homeassistant/components/binary_sensor/strings.json index 045fcdae707..7380d1be576 100644 --- a/homeassistant/components/binary_sensor/strings.json +++ b/homeassistant/components/binary_sensor/strings.json @@ -95,6 +95,10 @@ "off": "Normal", "on": "Low" }, + "battery_charging": { + "off": "Not charging", + "on": "Charging" + }, "cold": { "off": "[%key:component::binary_sensor::state::battery::off%]", "on": "Cold" @@ -119,6 +123,10 @@ "off": "[%key:component::binary_sensor::state::battery::off%]", "on": "Hot" }, + "light": { + "off": "No light", + "on": "Light detected" + }, "lock": { "off": "[%key:common::state::locked%]", "on": "[%key:common::state::unlocked%]" @@ -131,6 +139,10 @@ "off": "[%key:component::binary_sensor::state::gas::off%]", "on": "[%key:component::binary_sensor::state::gas::on%]" }, + "moving": { + "off": "Not moving", + "on": "Moving" + }, "occupancy": { "off": "[%key:component::binary_sensor::state::gas::off%]", "on": "[%key:component::binary_sensor::state::gas::on%]" @@ -139,6 +151,10 @@ "off": "[%key:common::state::closed%]", "on": "[%key:common::state::open%]" }, + "plug": { + "off": "Unplugged", + "on": "Plugged in" + }, "presence": { "off": "[%key:component::device_tracker::state::_::not_home%]", "on": "[%key:component::device_tracker::state::_::home%]" diff --git a/homeassistant/components/binary_sensor/translations/ca.json b/homeassistant/components/binary_sensor/translations/ca.json index ee06ef9d87f..8eaa35284c2 100644 --- a/homeassistant/components/binary_sensor/translations/ca.json +++ b/homeassistant/components/binary_sensor/translations/ca.json @@ -98,6 +98,10 @@ "off": "Normal", "on": "Baixa" }, + "battery_charging": { + "off": "No carregant", + "on": "Carregant" + }, "cold": { "off": "Normal", "on": "Fred" @@ -122,6 +126,10 @@ "off": "Normal", "on": "Calent" }, + "light": { + "off": "Sense llum", + "on": "Llum detectada" + }, "lock": { "off": "Bloquejat", "on": "Desbloquejat" @@ -134,6 +142,10 @@ "off": "Lliure", "on": "Detectat" }, + "moving": { + "off": "Parat", + "on": "En moviment" + }, "occupancy": { "off": "Lliure", "on": "Detectat" @@ -142,6 +154,10 @@ "off": "Tancat/ada", "on": "Obert/a" }, + "plug": { + "off": "Desendollat", + "on": "Endollat" + }, "presence": { "off": "Fora", "on": "A casa" diff --git a/homeassistant/components/binary_sensor/translations/cs.json b/homeassistant/components/binary_sensor/translations/cs.json index be54f0192d7..90f25332bdb 100644 --- a/homeassistant/components/binary_sensor/translations/cs.json +++ b/homeassistant/components/binary_sensor/translations/cs.json @@ -98,6 +98,10 @@ "off": "Norm\u00e1ln\u00ed", "on": "N\u00edzk\u00fd stav" }, + "battery_charging": { + "off": "Nenab\u00edj\u00ed se", + "on": "Nab\u00edjen\u00ed" + }, "cold": { "off": "Norm\u00e1ln\u00ed", "on": "Studen\u00e9" @@ -122,6 +126,10 @@ "off": "Norm\u00e1ln\u00ed", "on": "Hork\u00e9" }, + "light": { + "off": "\u017d\u00e1dn\u00e9 sv\u011btlo", + "on": "Zji\u0161t\u011bno sv\u011btlo" + }, "lock": { "off": "Zam\u010deno", "on": "Odem\u010deno" @@ -134,6 +142,10 @@ "off": "\u017d\u00e1dn\u00fd pohyb", "on": "Zaznamen\u00e1n pohyb" }, + "moving": { + "off": "Neh\u00fdbe se", + "on": "V pohybu" + }, "occupancy": { "off": "Volno", "on": "Obsazeno" @@ -142,6 +154,10 @@ "off": "Zav\u0159eno", "on": "Otev\u0159eno" }, + "plug": { + "off": "Odpojeno", + "on": "Zapojeno" + }, "presence": { "off": "Pry\u010d", "on": "Doma" diff --git a/homeassistant/components/binary_sensor/translations/en.json b/homeassistant/components/binary_sensor/translations/en.json index c9a1ad15a8b..98c8a3a220a 100644 --- a/homeassistant/components/binary_sensor/translations/en.json +++ b/homeassistant/components/binary_sensor/translations/en.json @@ -98,6 +98,10 @@ "off": "Normal", "on": "Low" }, + "battery_charging": { + "off": "Not charging", + "on": "Charging" + }, "cold": { "off": "Normal", "on": "Cold" @@ -122,6 +126,10 @@ "off": "Normal", "on": "Hot" }, + "light": { + "off": "No light", + "on": "Light detected" + }, "lock": { "off": "Locked", "on": "Unlocked" @@ -134,6 +142,10 @@ "off": "Clear", "on": "Detected" }, + "moving": { + "off": "Not moving", + "on": "Moving" + }, "occupancy": { "off": "Clear", "on": "Detected" @@ -142,6 +154,10 @@ "off": "Closed", "on": "Open" }, + "plug": { + "off": "Unplugged", + "on": "Plugged in" + }, "presence": { "off": "Away", "on": "Home" diff --git a/homeassistant/components/binary_sensor/translations/es.json b/homeassistant/components/binary_sensor/translations/es.json index 013d587539a..05fc002ecb0 100644 --- a/homeassistant/components/binary_sensor/translations/es.json +++ b/homeassistant/components/binary_sensor/translations/es.json @@ -98,6 +98,10 @@ "off": "Normal", "on": "Baja" }, + "battery_charging": { + "off": "No est\u00e1 cargando", + "on": "Cargando" + }, "cold": { "off": "Normal", "on": "Fr\u00edo" @@ -122,6 +126,10 @@ "off": "Normal", "on": "Caliente" }, + "light": { + "off": "Sin luz", + "on": "Luz detectada" + }, "lock": { "off": "Bloqueado", "on": "Desbloqueado" @@ -134,6 +142,10 @@ "off": "No detectado", "on": "Detectado" }, + "moving": { + "off": "No se mueve", + "on": "En movimiento" + }, "occupancy": { "off": "No detectado", "on": "Detectado" @@ -142,6 +154,10 @@ "off": "Cerrado", "on": "Abierto" }, + "plug": { + "off": "Desenchufado", + "on": "Enchufado" + }, "presence": { "off": "Fuera de casa", "on": "En casa" diff --git a/homeassistant/components/binary_sensor/translations/et.json b/homeassistant/components/binary_sensor/translations/et.json index c074c56675a..99fbec0b89e 100644 --- a/homeassistant/components/binary_sensor/translations/et.json +++ b/homeassistant/components/binary_sensor/translations/et.json @@ -98,6 +98,10 @@ "off": "Tavaline", "on": "Madal" }, + "battery_charging": { + "off": "Ei lae", + "on": "Laeb" + }, "cold": { "off": "Normaalne", "on": "Jahe" @@ -122,6 +126,10 @@ "off": "Normaalne", "on": "Palav" }, + "light": { + "off": "Valgus puudub", + "on": "Valgus tuvastatud" + }, "lock": { "off": "Lukus", "on": "Lukustamata" @@ -134,6 +142,10 @@ "off": "Liikumine puudub", "on": "Liikumine tuvastatud" }, + "moving": { + "off": "Ei liigu", + "on": "Liigub" + }, "occupancy": { "off": "Puudub", "on": "Tuvastatud" @@ -142,6 +154,10 @@ "off": "Suletud", "on": "Avatud" }, + "plug": { + "off": "Lahti \u00fchendatud", + "on": "\u00dchendatud" + }, "presence": { "off": "Eemal", "on": "Kodus" diff --git a/homeassistant/components/binary_sensor/translations/fr.json b/homeassistant/components/binary_sensor/translations/fr.json index fe7b0e19754..ede13a68dc9 100644 --- a/homeassistant/components/binary_sensor/translations/fr.json +++ b/homeassistant/components/binary_sensor/translations/fr.json @@ -98,6 +98,10 @@ "off": "Normal", "on": "Faible" }, + "battery_charging": { + "off": "Pas en charge", + "on": "En charge" + }, "cold": { "off": "Normale", "on": "Froid" @@ -122,6 +126,10 @@ "off": "Normale", "on": "Chaud" }, + "light": { + "off": "Pas de lumi\u00e8re", + "on": "Lumi\u00e8re d\u00e9tect\u00e9e" + }, "lock": { "off": "Verrouill\u00e9", "on": "D\u00e9verrouill\u00e9" @@ -134,6 +142,10 @@ "off": "RAS", "on": "D\u00e9tect\u00e9" }, + "moving": { + "off": "Immobile", + "on": "En mouvement" + }, "occupancy": { "off": "RAS", "on": "D\u00e9tect\u00e9" @@ -142,6 +154,10 @@ "off": "Ferm\u00e9", "on": "Ouvert" }, + "plug": { + "off": "D\u00e9branch\u00e9", + "on": "Branch\u00e9" + }, "presence": { "off": "Absent", "on": "Pr\u00e9sent" diff --git a/homeassistant/components/binary_sensor/translations/it.json b/homeassistant/components/binary_sensor/translations/it.json index 590ab87f142..68c427cbc04 100644 --- a/homeassistant/components/binary_sensor/translations/it.json +++ b/homeassistant/components/binary_sensor/translations/it.json @@ -98,6 +98,10 @@ "off": "Normale", "on": "Basso" }, + "battery_charging": { + "off": "Non in carica", + "on": "In carica" + }, "cold": { "off": "Normale", "on": "Freddo" @@ -115,13 +119,17 @@ "on": "Aperta" }, "gas": { - "off": "Assenza", - "on": "Presenza" + "off": "Assente", + "on": "Rilevato" }, "heat": { "off": "Normale", "on": "Caldo" }, + "light": { + "off": "Nessuna luce", + "on": "Luce rilevata" + }, "lock": { "off": "Bloccato", "on": "Sbloccato" @@ -131,17 +139,25 @@ "on": "Umido" }, "motion": { - "off": "Assenza", - "on": "Presenza" + "off": "Assente", + "on": "Rilevato" + }, + "moving": { + "off": "Non in movimento", + "on": "In movimento" }, "occupancy": { - "off": "Assenza", - "on": "Presenza" + "off": "Assente", + "on": "Rilevato" }, "opening": { "off": "Chiuso", "on": "Aperto" }, + "plug": { + "off": "Scollegato", + "on": "Connesso" + }, "presence": { "off": "Fuori casa", "on": "A casa" @@ -155,15 +171,15 @@ "on": "Non Sicuro" }, "smoke": { - "off": "Assenza", - "on": "Presenza" + "off": "Assente", + "on": "Rilevato" }, "sound": { - "off": "Assenza", - "on": "Presenza" + "off": "Assente", + "on": "Rilevato" }, "vibration": { - "off": "Assenza", + "off": "Assente", "on": "Rilevata" }, "window": { diff --git a/homeassistant/components/binary_sensor/translations/lb.json b/homeassistant/components/binary_sensor/translations/lb.json index 4c816d6424a..fc186bee447 100644 --- a/homeassistant/components/binary_sensor/translations/lb.json +++ b/homeassistant/components/binary_sensor/translations/lb.json @@ -98,6 +98,10 @@ "off": "Normal", "on": "Niddreg" }, + "battery_charging": { + "off": "Lued net", + "on": "Lued" + }, "cold": { "off": "Normal", "on": "Kal" @@ -122,6 +126,10 @@ "off": "Normal", "on": "Waarm" }, + "light": { + "off": "Keng Luucht", + "on": "Luucht detekt\u00e9iert" + }, "lock": { "off": "Gespaart", "on": "Net gespaart" @@ -134,6 +142,10 @@ "off": "Roueg", "on": "Detekt\u00e9iert" }, + "moving": { + "off": "Keng Beweegung", + "on": "Beweegung" + }, "occupancy": { "off": "Roueg", "on": "Detekt\u00e9iert" @@ -142,6 +154,10 @@ "off": "Zou", "on": "Op" }, + "plug": { + "off": "Net ugeschloss", + "on": "Ugeschloss" + }, "problem": { "off": "OK", "on": "Problem" diff --git a/homeassistant/components/binary_sensor/translations/no.json b/homeassistant/components/binary_sensor/translations/no.json index ed85b1ab26d..023fec6cc39 100644 --- a/homeassistant/components/binary_sensor/translations/no.json +++ b/homeassistant/components/binary_sensor/translations/no.json @@ -98,6 +98,10 @@ "off": "Normal", "on": "Lavt" }, + "battery_charging": { + "off": "Lader ikke", + "on": "Lader" + }, "cold": { "off": "Normal", "on": "Kald" @@ -122,6 +126,10 @@ "off": "Normal", "on": "Varm" }, + "light": { + "off": "Ingen lys", + "on": "Lys oppdaget" + }, "lock": { "off": "L\u00e5st", "on": "Ul\u00e5st" @@ -134,6 +142,10 @@ "off": "Klart", "on": "Oppdaget" }, + "moving": { + "off": "Beveger seg ikke", + "on": "Flytter" + }, "occupancy": { "off": "Klart", "on": "Oppdaget" @@ -142,6 +154,10 @@ "off": "Lukket", "on": "\u00c5pen" }, + "plug": { + "off": "Frakoblet", + "on": "Koblet til" + }, "presence": { "off": "Borte", "on": "Hjemme" diff --git a/homeassistant/components/binary_sensor/translations/pl.json b/homeassistant/components/binary_sensor/translations/pl.json index a3f578f1cef..7d6e8eab4ba 100644 --- a/homeassistant/components/binary_sensor/translations/pl.json +++ b/homeassistant/components/binary_sensor/translations/pl.json @@ -30,7 +30,7 @@ "is_not_plugged_in": "sensor {entity_name} wykrywa od\u0142\u0105czenie", "is_not_powered": "sensor {entity_name} nie wykrywa zasilania", "is_not_present": "sensor {entity_name} nie wykrywa obecno\u015bci", - "is_not_unsafe": "sensor {entity_name} nie wykrywa niebezpiecze\u0144stwa", + "is_not_unsafe": "sensor {entity_name} nie wykrywa zagro\u017cenia", "is_occupied": "sensor {entity_name} jest zaj\u0119ty", "is_off": "sensor {entity_name} jest wy\u0142\u0105czony", "is_on": "sensor {entity_name} jest w\u0142\u0105czony", @@ -41,7 +41,7 @@ "is_problem": "sensor {entity_name} wykrywa problem", "is_smoke": "sensor {entity_name} wykrywa dym", "is_sound": "sensor {entity_name} wykrywa d\u017awi\u0119k", - "is_unsafe": "sensor {entity_name} wykrywa niebezpiecze\u0144stwo", + "is_unsafe": "sensor {entity_name} wykrywa zagro\u017cenie", "is_vibration": "sensor {entity_name} wykrywa wibracje" }, "trigger_type": { @@ -74,7 +74,7 @@ "not_plugged_in": "nast\u0105pi od\u0142\u0105czenie {entity_name}", "not_powered": "nast\u0105pi od\u0142\u0105czenie zasilania {entity_name}", "not_present": "sensor {entity_name} przestanie wykrywa\u0107 obecno\u015b\u0107", - "not_unsafe": "sensor {entity_name} przestanie wykrywa\u0107 niebezpiecze\u0144stwo", + "not_unsafe": "sensor {entity_name} przestanie wykrywa\u0107 zagro\u017cenie", "occupied": "sensor {entity_name} stanie si\u0119 zaj\u0119ty", "opened": "nast\u0105pi otwarcie {entity_name}", "plugged_in": "nast\u0105pi pod\u0142\u0105czenie {entity_name}", @@ -85,7 +85,7 @@ "sound": "sensor {entity_name} wykryje d\u017awi\u0119k", "turned_off": "nast\u0105pi wy\u0142\u0105czenie {entity_name}", "turned_on": "nast\u0105pi w\u0142\u0105czenie {entity_name}", - "unsafe": "sensor {entity_name} wykryje niebezpiecze\u0144stwo", + "unsafe": "sensor {entity_name} wykryje zagro\u017cenie", "vibration": "sensor {entity_name} wykryje wibracje" } }, @@ -98,6 +98,10 @@ "off": "na\u0142adowana", "on": "roz\u0142adowana" }, + "battery_charging": { + "off": "nie \u0142aduje", + "on": "\u0142adowanie" + }, "cold": { "off": "normalnie", "on": "zimno" @@ -122,6 +126,10 @@ "off": "normalnie", "on": "gor\u0105co" }, + "light": { + "off": "brak", + "on": "wykryto" + }, "lock": { "off": "zamkni\u0119ty", "on": "otwarty" @@ -134,6 +142,10 @@ "off": "brak", "on": "wykryto" }, + "moving": { + "off": "brak ruchu", + "on": "w ruchu" + }, "occupancy": { "off": "brak", "on": "wykryto" @@ -142,6 +154,10 @@ "off": "zamkni\u0119te", "on": "otwarte" }, + "plug": { + "off": "od\u0142\u0105czony", + "on": "pod\u0142\u0105czony" + }, "presence": { "off": "poza domem", "on": "w domu" diff --git a/homeassistant/components/binary_sensor/translations/ru.json b/homeassistant/components/binary_sensor/translations/ru.json index c3906cdc88c..6b80fafe5dd 100644 --- a/homeassistant/components/binary_sensor/translations/ru.json +++ b/homeassistant/components/binary_sensor/translations/ru.json @@ -98,6 +98,10 @@ "off": "\u041d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0439", "on": "\u041d\u0438\u0437\u043a\u0438\u0439" }, + "battery_charging": { + "off": "\u041d\u0435 \u0437\u0430\u0440\u044f\u0436\u0430\u0435\u0442\u0441\u044f", + "on": "\u0417\u0430\u0440\u044f\u0436\u0430\u0435\u0442\u0441\u044f" + }, "cold": { "off": "\u041d\u043e\u0440\u043c\u0430", "on": "\u041e\u0445\u043b\u0430\u0436\u0434\u0435\u043d\u0438\u0435" diff --git a/homeassistant/components/binary_sensor/translations/tr.json b/homeassistant/components/binary_sensor/translations/tr.json index 582668c179d..3c5cfaeeacf 100644 --- a/homeassistant/components/binary_sensor/translations/tr.json +++ b/homeassistant/components/binary_sensor/translations/tr.json @@ -53,8 +53,8 @@ "on": "A\u00e7\u0131k" }, "presence": { - "off": "D\u0131\u015farda", - "on": "Evde" + "off": "[%key:common::state::evde_degil%]", + "on": "[%key:common::state::evde%]" }, "problem": { "off": "Tamam", diff --git a/homeassistant/components/binary_sensor/translations/zh-Hans.json b/homeassistant/components/binary_sensor/translations/zh-Hans.json index b13a3622aca..fe16bd685ca 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/binary_sensor/translations/zh-Hant.json b/homeassistant/components/binary_sensor/translations/zh-Hant.json index a78ecdcf8ef..bf50782743e 100644 --- a/homeassistant/components/binary_sensor/translations/zh-Hant.json +++ b/homeassistant/components/binary_sensor/translations/zh-Hant.json @@ -98,6 +98,10 @@ "off": "\u96fb\u91cf\u6b63\u5e38", "on": "\u96fb\u91cf\u4f4e" }, + "battery_charging": { + "off": "\u672a\u5728\u5145\u96fb", + "on": "\u5145\u96fb\u4e2d" + }, "cold": { "off": "\u6b63\u5e38", "on": "\u51b7" @@ -122,6 +126,10 @@ "off": "\u6b63\u5e38", "on": "\u71b1" }, + "light": { + "off": "\u6c92\u6709\u5149\u7dda", + "on": "\u5075\u6e2c\u5230\u5149\u7dda" + }, "lock": { "off": "\u5df2\u4e0a\u9396", "on": "\u5df2\u89e3\u9396" @@ -134,6 +142,10 @@ "off": "\u7121\u4eba", "on": "\u6709\u4eba" }, + "moving": { + "off": "\u672a\u5728\u79fb\u52d5", + "on": "\u79fb\u52d5\u4e2d" + }, "occupancy": { "off": "\u672a\u89f8\u767c", "on": "\u5df2\u89f8\u767c" @@ -142,6 +154,10 @@ "off": "\u95dc\u9589", "on": "\u958b\u555f" }, + "plug": { + "off": "\u5df2\u62d4\u9664", + "on": "\u5df2\u63d2\u4e0a" + }, "presence": { "off": "\u96e2\u5bb6", "on": "\u5728\u5bb6" diff --git a/homeassistant/components/blebox/translations/lb.json b/homeassistant/components/blebox/translations/lb.json index ffe37b1f907..19602c9f6fd 100644 --- a/homeassistant/components/blebox/translations/lb.json +++ b/homeassistant/components/blebox/translations/lb.json @@ -2,11 +2,11 @@ "config": { "abort": { "address_already_configured": "Ee BleBox Apparat ass scho konfigur\u00e9iert op {adress}.", - "already_configured": "D\u00ebse BleBox Apparat ass scho konfigur\u00e9iert" + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Keng Verbindung mam BleBox Apparat m\u00e9iglech. (Kuck Logs fir Feeler.)", - "unknown": "Onbekannte Feeler beim verbannen mam BleBox Apparat. (Kuck Logs fir Feeler.)", + "cannot_connect": "Feeler beim verbannen", + "unknown": "Onerwaarte Feeler", "unsupported_version": "BleBox Apparat huet eng aal Firmware. Maach fir d'\u00e9ischt d'Mise \u00e0 jour." }, "flow_title": "BleBox Apparat: {name} ({host})", diff --git a/homeassistant/components/blebox/translations/nl.json b/homeassistant/components/blebox/translations/nl.json index c7156a5f553..0fad3e9264f 100644 --- a/homeassistant/components/blebox/translations/nl.json +++ b/homeassistant/components/blebox/translations/nl.json @@ -1,11 +1,23 @@ { "config": { + "abort": { + "address_already_configured": "Er is al een BleBox-apparaat geconfigureerd op {address} .", + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "unknown": "Onverwachte fout", + "unsupported_version": "BleBox-apparaat heeft verouderde firmware. Upgrade het eerst." + }, + "flow_title": "BleBox-apparaat: {name} ( {host} )", "step": { "user": { "data": { "host": "IP-adres", "port": "Poort" - } + }, + "description": "Stel uw BleBox in om te integreren met Home Assistant.", + "title": "Stel uw BleBox-apparaat in" } } } diff --git a/homeassistant/components/blebox/translations/pl.json b/homeassistant/components/blebox/translations/pl.json index 775d74aa5d7..4cdd35f4ac3 100644 --- a/homeassistant/components/blebox/translations/pl.json +++ b/homeassistant/components/blebox/translations/pl.json @@ -17,7 +17,7 @@ "port": "Port" }, "description": "Skonfiguruj BleBox, aby zintegrowa\u0107 si\u0119 z Home Assistant.", - "title": "Skonfiguruj urz\u0105dzenie BleBox" + "title": "Konfiguracja urz\u0105dzenia BleBox" } } } diff --git a/homeassistant/components/blink/alarm_control_panel.py b/homeassistant/components/blink/alarm_control_panel.py index 1ca4c4beac9..dbcb6d30143 100644 --- a/homeassistant/components/blink/alarm_control_panel.py +++ b/homeassistant/components/blink/alarm_control_panel.py @@ -66,7 +66,7 @@ class BlinkSyncModule(AlarmControlPanelEntity): """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/blink/translations/nl.json b/homeassistant/components/blink/translations/nl.json index 2af76f4f414..c1ab971dbf0 100644 --- a/homeassistant/components/blink/translations/nl.json +++ b/homeassistant/components/blink/translations/nl.json @@ -1,6 +1,10 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, "error": { + "invalid_auth": "Ongeldige authenticatie", "unknown": "Onverwachte fout" }, "step": { diff --git a/homeassistant/components/blink/translations/no.json b/homeassistant/components/blink/translations/no.json index 938bf7b85aa..e2be7cf4097 100644 --- a/homeassistant/components/blink/translations/no.json +++ b/homeassistant/components/blink/translations/no.json @@ -14,7 +14,7 @@ "data": { "2fa": "To-faktorskode" }, - "description": "Skriv inn pin-koden som sendes til e-posten din", + "description": "Skriv inn pin-koden som ble sendt til din e-posten", "title": "Totrinnsverifisering" }, "user": { diff --git a/homeassistant/components/blink/translations/pl.json b/homeassistant/components/blink/translations/pl.json index 50436c77e82..13fe2f1fc93 100644 --- a/homeassistant/components/blink/translations/pl.json +++ b/homeassistant/components/blink/translations/pl.json @@ -22,7 +22,7 @@ "password": "Has\u0142o", "username": "Nazwa u\u017cytkownika" }, - "title": "Zaloguj si\u0119 za pomoc\u0105 konta Blink" + "title": "Logowanie za pomoc\u0105 konta Blink" } } }, diff --git a/homeassistant/components/blueprint/__init__.py b/homeassistant/components/blueprint/__init__.py new file mode 100644 index 00000000000..12a6782065b --- /dev/null +++ b/homeassistant/components/blueprint/__init__.py @@ -0,0 +1,19 @@ +"""The blueprint integration.""" +from . import websocket_api +from .const import DOMAIN # noqa +from .errors import ( # noqa + BlueprintException, + BlueprintWithNameException, + FailedToLoad, + InvalidBlueprint, + InvalidBlueprintInputs, + MissingPlaceholder, +) +from .models import Blueprint, BlueprintInputs, DomainBlueprints # noqa +from .schemas import is_blueprint_instance_config # noqa + + +async def async_setup(hass, config): + """Set up the blueprint integration.""" + websocket_api.async_setup(hass) + return True diff --git a/homeassistant/components/blueprint/const.py b/homeassistant/components/blueprint/const.py new file mode 100644 index 00000000000..fe4ee5b7ce6 --- /dev/null +++ b/homeassistant/components/blueprint/const.py @@ -0,0 +1,9 @@ +"""Constants for the blueprint integration.""" +BLUEPRINT_FOLDER = "blueprints" + +CONF_BLUEPRINT = "blueprint" +CONF_USE_BLUEPRINT = "use_blueprint" +CONF_INPUT = "input" +CONF_SOURCE_URL = "source_url" + +DOMAIN = "blueprint" diff --git a/homeassistant/components/blueprint/errors.py b/homeassistant/components/blueprint/errors.py new file mode 100644 index 00000000000..dff65b5263d --- /dev/null +++ b/homeassistant/components/blueprint/errors.py @@ -0,0 +1,80 @@ +"""Blueprint errors.""" +from typing import Any, Iterable + +import voluptuous as vol +from voluptuous.humanize import humanize_error + +from homeassistant.exceptions import HomeAssistantError + + +class BlueprintException(HomeAssistantError): + """Base exception for blueprint errors.""" + + def __init__(self, domain: str, msg: str) -> None: + """Initialize a blueprint exception.""" + super().__init__(msg) + self.domain = domain + + +class BlueprintWithNameException(BlueprintException): + """Base exception for blueprint errors.""" + + def __init__(self, domain: str, blueprint_name: str, msg: str) -> None: + """Initialize blueprint exception.""" + super().__init__(domain, msg) + self.blueprint_name = blueprint_name + + +class FailedToLoad(BlueprintWithNameException): + """When we failed to load the blueprint.""" + + def __init__(self, domain: str, blueprint_name: str, exc: Exception) -> None: + """Initialize blueprint exception.""" + super().__init__(domain, blueprint_name, f"Failed to load blueprint: {exc}") + + +class InvalidBlueprint(BlueprintWithNameException): + """When we encountered an invalid blueprint.""" + + def __init__( + self, + domain: str, + blueprint_name: str, + blueprint_data: Any, + msg_or_exc: vol.Invalid, + ): + """Initialize an invalid blueprint error.""" + if isinstance(msg_or_exc, vol.Invalid): + msg_or_exc = humanize_error(blueprint_data, msg_or_exc) + + super().__init__( + domain, + blueprint_name, + f"Invalid blueprint: {msg_or_exc}", + ) + self.blueprint_data = blueprint_data + + +class InvalidBlueprintInputs(BlueprintException): + """When we encountered invalid blueprint inputs.""" + + def __init__(self, domain: str, msg: str): + """Initialize an invalid blueprint inputs error.""" + super().__init__( + domain, + f"Invalid blueprint inputs: {msg}", + ) + + +class MissingPlaceholder(BlueprintWithNameException): + """When we miss a placeholder.""" + + def __init__( + self, domain: str, blueprint_name: str, placeholder_names: Iterable[str] + ) -> None: + """Initialize blueprint exception.""" + super().__init__( + domain, + blueprint_name, + f"Missing placeholder {', '.join(sorted(placeholder_names))}", + ) diff --git a/homeassistant/components/blueprint/importer.py b/homeassistant/components/blueprint/importer.py new file mode 100644 index 00000000000..0f229ec8a07 --- /dev/null +++ b/homeassistant/components/blueprint/importer.py @@ -0,0 +1,177 @@ +"""Import logic for blueprint.""" +from dataclasses import dataclass +import re +from typing import Optional + +import voluptuous as vol +import yarl + +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import aiohttp_client, config_validation as cv +from homeassistant.util import yaml + +from .models import Blueprint +from .schemas import is_blueprint_config + +COMMUNITY_TOPIC_PATTERN = re.compile( + r"^https://community.home-assistant.io/t/[a-z0-9-]+/(?P\d+)(?:/(?P\d+)|)$" +) + +COMMUNITY_CODE_BLOCK = re.compile( + r'(?P(?:.|\n)*)', re.MULTILINE +) + +GITHUB_FILE_PATTERN = re.compile( + r"^https://github.com/(?P.+)/blob/(?P.+)$" +) +GITHUB_RAW_FILE_PATTERN = re.compile(r"^https://raw.githubusercontent.com/") + +COMMUNITY_TOPIC_SCHEMA = vol.Schema( + { + "slug": str, + "title": str, + "post_stream": {"posts": [{"updated_at": cv.datetime, "cooked": str}]}, + }, + extra=vol.ALLOW_EXTRA, +) + + +@dataclass(frozen=True) +class ImportedBlueprint: + """Imported blueprint.""" + + url: str + suggested_filename: str + raw_data: str + blueprint: Blueprint + + +def _get_github_import_url(url: str) -> str: + """Convert a GitHub url to the raw content. + + Async friendly. + """ + match = GITHUB_RAW_FILE_PATTERN.match(url) + if match is not None: + return url + + match = GITHUB_FILE_PATTERN.match(url) + + if match is None: + raise ValueError("Not a GitHub file url") + + repo, path = match.groups() + + return f"https://raw.githubusercontent.com/{repo}/{path}" + + +def _get_community_post_import_url(url: str) -> str: + """Convert a forum post url to an import url. + + Async friendly. + """ + match = COMMUNITY_TOPIC_PATTERN.match(url) + if match is None: + raise ValueError("Not a topic url") + + _topic, post = match.groups() + + json_url = url + + if post is not None: + # Chop off post part, ie /2 + json_url = json_url[: -len(post) - 1] + + json_url += ".json" + + return json_url + + +def _extract_blueprint_from_community_topic( + url: str, + topic: dict, +) -> Optional[ImportedBlueprint]: + """Extract a blueprint from a community post JSON. + + Async friendly. + """ + block_content = None + blueprint = None + post = topic["post_stream"]["posts"][0] + + for match in COMMUNITY_CODE_BLOCK.finditer(post["cooked"]): + block_syntax, block_content = match.groups() + + if block_syntax not in ("auto", "yaml"): + continue + + block_content = block_content.strip() + + try: + data = yaml.parse_yaml(block_content) + except HomeAssistantError: + if block_syntax == "yaml": + raise + + continue + + if not is_blueprint_config(data): + continue + + blueprint = Blueprint(data) + break + + if blueprint is None: + return None + + return ImportedBlueprint(url, topic["slug"], block_content, blueprint) + + +async def fetch_blueprint_from_community_post( + hass: HomeAssistant, url: str +) -> Optional[ImportedBlueprint]: + """Get blueprints from a community post url. + + Method can raise aiohttp client exceptions, vol.Invalid. + + Caller needs to implement own timeout. + """ + import_url = _get_community_post_import_url(url) + session = aiohttp_client.async_get_clientsession(hass) + + resp = await session.get(import_url, raise_for_status=True) + json_resp = await resp.json() + json_resp = COMMUNITY_TOPIC_SCHEMA(json_resp) + return _extract_blueprint_from_community_topic(url, json_resp) + + +async def fetch_blueprint_from_github_url( + hass: HomeAssistant, url: str +) -> ImportedBlueprint: + """Get a blueprint from a github url.""" + import_url = _get_github_import_url(url) + session = aiohttp_client.async_get_clientsession(hass) + + resp = await session.get(import_url, raise_for_status=True) + raw_yaml = await resp.text() + data = yaml.parse_yaml(raw_yaml) + blueprint = Blueprint(data) + + parsed_import_url = yarl.URL(import_url) + suggested_filename = f"{parsed_import_url.parts[1]}-{parsed_import_url.parts[-1]}" + if suggested_filename.endswith(".yaml"): + suggested_filename = suggested_filename[:-5] + + return ImportedBlueprint(url, suggested_filename, raw_yaml, blueprint) + + +async def fetch_blueprint_from_url(hass: HomeAssistant, url: str) -> ImportedBlueprint: + """Get a blueprint from a url.""" + for func in (fetch_blueprint_from_community_post, fetch_blueprint_from_github_url): + try: + return await func(hass, url) + except ValueError: + pass + + raise HomeAssistantError("Unsupported url") diff --git a/homeassistant/components/blueprint/manifest.json b/homeassistant/components/blueprint/manifest.json new file mode 100644 index 00000000000..215d788ee6b --- /dev/null +++ b/homeassistant/components/blueprint/manifest.json @@ -0,0 +1,9 @@ +{ + "domain": "blueprint", + "name": "Blueprint", + "documentation": "https://www.home-assistant.io/integrations/blueprint", + "codeowners": [ + "@home-assistant/core" + ], + "quality_scale": "internal" +} diff --git a/homeassistant/components/blueprint/models.py b/homeassistant/components/blueprint/models.py new file mode 100644 index 00000000000..06401a34d7d --- /dev/null +++ b/homeassistant/components/blueprint/models.py @@ -0,0 +1,231 @@ +"""Blueprint models.""" +import asyncio +import logging +import pathlib +from typing import Any, Dict, Optional, Union + +import voluptuous as vol +from voluptuous.humanize import humanize_error + +from homeassistant.const import CONF_DOMAIN, CONF_NAME, CONF_PATH +from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import placeholder +from homeassistant.util import yaml + +from .const import ( + BLUEPRINT_FOLDER, + CONF_BLUEPRINT, + CONF_INPUT, + CONF_SOURCE_URL, + CONF_USE_BLUEPRINT, + DOMAIN, +) +from .errors import ( + BlueprintException, + FailedToLoad, + InvalidBlueprint, + InvalidBlueprintInputs, + MissingPlaceholder, +) +from .schemas import BLUEPRINT_INSTANCE_FIELDS, BLUEPRINT_SCHEMA + + +class Blueprint: + """Blueprint of a configuration structure.""" + + def __init__( + self, + data: dict, + *, + path: Optional[str] = None, + expected_domain: Optional[str] = None, + ) -> None: + """Initialize a blueprint.""" + try: + data = self.data = BLUEPRINT_SCHEMA(data) + except vol.Invalid as err: + raise InvalidBlueprint(expected_domain, path, data, err) from err + + self.placeholders = placeholder.extract_placeholders(data) + + # In future, we will treat this as "incorrect" and allow to recover from this + data_domain = data[CONF_BLUEPRINT][CONF_DOMAIN] + if expected_domain is not None and data_domain != expected_domain: + raise InvalidBlueprint( + expected_domain, + path or self.name, + data, + f"Found incorrect blueprint type {data_domain}, expected {expected_domain}", + ) + + self.domain = data_domain + + missing = self.placeholders - set(data[CONF_BLUEPRINT].get(CONF_INPUT, {})) + + if missing: + raise InvalidBlueprint( + data_domain, + path or self.name, + data, + f"Missing input definition for {', '.join(missing)}", + ) + + @property + def name(self) -> str: + """Return blueprint name.""" + return self.data[CONF_BLUEPRINT][CONF_NAME] + + @property + def metadata(self) -> dict: + """Return blueprint metadata.""" + return self.data[CONF_BLUEPRINT] + + def update_metadata(self, *, source_url: Optional[str] = None) -> None: + """Update metadata.""" + if source_url is not None: + self.data[CONF_BLUEPRINT][CONF_SOURCE_URL] = source_url + + +class BlueprintInputs: + """Inputs for a blueprint.""" + + def __init__( + self, blueprint: Blueprint, config_with_inputs: Dict[str, Any] + ) -> None: + """Instantiate a blueprint inputs object.""" + self.blueprint = blueprint + self.config_with_inputs = config_with_inputs + + @property + def inputs(self): + """Return the inputs.""" + return self.config_with_inputs[CONF_USE_BLUEPRINT][CONF_INPUT] + + def validate(self) -> None: + """Validate the inputs.""" + missing = self.blueprint.placeholders - set(self.inputs) + + if missing: + raise MissingPlaceholder( + self.blueprint.domain, self.blueprint.name, missing + ) + + # In future we can see if entities are correct domain, areas exist etc + # using the new selector helper. + + @callback + def async_substitute(self) -> dict: + """Get the blueprint value with the inputs substituted.""" + processed = placeholder.substitute(self.blueprint.data, self.inputs) + combined = {**self.config_with_inputs, **processed} + # From config_with_inputs + combined.pop(CONF_USE_BLUEPRINT) + # From blueprint + combined.pop(CONF_BLUEPRINT) + return combined + + +class DomainBlueprints: + """Blueprints for a specific domain.""" + + def __init__( + self, + hass: HomeAssistant, + domain: str, + logger: logging.Logger, + ) -> None: + """Initialize a domain blueprints instance.""" + self.hass = hass + self.domain = domain + self.logger = logger + self._blueprints = {} + self._load_lock = asyncio.Lock() + + hass.data.setdefault(DOMAIN, {})[domain] = self + + @callback + def async_reset_cache(self) -> None: + """Reset the blueprint cache.""" + self._blueprints = {} + + def _load_blueprint(self, blueprint_path) -> Blueprint: + """Load a blueprint.""" + try: + blueprint_data = yaml.load_yaml( + self.hass.config.path(BLUEPRINT_FOLDER, self.domain, blueprint_path) + ) + except (HomeAssistantError, FileNotFoundError) as err: + raise FailedToLoad(self.domain, blueprint_path, err) from err + + return Blueprint( + blueprint_data, expected_domain=self.domain, path=blueprint_path + ) + + def _load_blueprints(self) -> Dict[str, Union[Blueprint, BlueprintException]]: + """Load all the blueprints.""" + blueprint_folder = pathlib.Path( + self.hass.config.path(BLUEPRINT_FOLDER, self.domain) + ) + results = {} + + for blueprint_path in blueprint_folder.glob("**/*.yaml"): + blueprint_path = str(blueprint_path.relative_to(blueprint_folder)) + if self._blueprints.get(blueprint_path) is None: + try: + self._blueprints[blueprint_path] = self._load_blueprint( + blueprint_path + ) + except BlueprintException as err: + self._blueprints[blueprint_path] = None + results[blueprint_path] = err + continue + + results[blueprint_path] = self._blueprints[blueprint_path] + + return results + + async def async_get_blueprints( + self, + ) -> Dict[str, Union[Blueprint, BlueprintException]]: + """Get all the blueprints.""" + async with self._load_lock: + return await self.hass.async_add_executor_job(self._load_blueprints) + + async def async_get_blueprint(self, blueprint_path: str) -> Blueprint: + """Get a blueprint.""" + if blueprint_path in self._blueprints: + return self._blueprints[blueprint_path] + + async with self._load_lock: + # Check it again + if blueprint_path in self._blueprints: + return self._blueprints[blueprint_path] + + try: + blueprint = await self.hass.async_add_executor_job( + self._load_blueprint, blueprint_path + ) + except Exception: + self._blueprints[blueprint_path] = None + raise + + self._blueprints[blueprint_path] = blueprint + return blueprint + + async def async_inputs_from_config( + self, config_with_blueprint: dict + ) -> BlueprintInputs: + """Process a blueprint config.""" + try: + config_with_blueprint = BLUEPRINT_INSTANCE_FIELDS(config_with_blueprint) + except vol.Invalid as err: + raise InvalidBlueprintInputs( + self.domain, humanize_error(config_with_blueprint, err) + ) from err + + bp_conf = config_with_blueprint[CONF_USE_BLUEPRINT] + blueprint = await self.async_get_blueprint(bp_conf[CONF_PATH]) + inputs = BlueprintInputs(blueprint, config_with_blueprint) + inputs.validate() + return inputs diff --git a/homeassistant/components/blueprint/schemas.py b/homeassistant/components/blueprint/schemas.py new file mode 100644 index 00000000000..275a2cf242a --- /dev/null +++ b/homeassistant/components/blueprint/schemas.py @@ -0,0 +1,57 @@ +"""Schemas for the blueprint integration.""" +from typing import Any + +import voluptuous as vol + +from homeassistant.const import CONF_DOMAIN, CONF_NAME, CONF_PATH +from homeassistant.core import callback +from homeassistant.helpers import config_validation as cv + +from .const import CONF_BLUEPRINT, CONF_INPUT, CONF_USE_BLUEPRINT + + +@callback +def is_blueprint_config(config: Any) -> bool: + """Return if it is a blueprint config.""" + return isinstance(config, dict) and CONF_BLUEPRINT in config + + +@callback +def is_blueprint_instance_config(config: Any) -> bool: + """Return if it is a blueprint instance config.""" + return isinstance(config, dict) and CONF_USE_BLUEPRINT in config + + +BLUEPRINT_SCHEMA = vol.Schema( + { + # No definition yet for the inputs. + vol.Required(CONF_BLUEPRINT): vol.Schema( + { + vol.Required(CONF_NAME): str, + vol.Required(CONF_DOMAIN): str, + vol.Optional(CONF_INPUT, default=dict): {str: None}, + } + ), + }, + extra=vol.ALLOW_EXTRA, +) + + +def validate_yaml_suffix(value: str) -> str: + """Validate value has a YAML suffix.""" + if not value.endswith(".yaml"): + raise vol.Invalid("Path needs to end in .yaml") + return value + + +BLUEPRINT_INSTANCE_FIELDS = vol.Schema( + { + vol.Required(CONF_USE_BLUEPRINT): vol.Schema( + { + vol.Required(CONF_PATH): vol.All(cv.path, validate_yaml_suffix), + vol.Required(CONF_INPUT): {str: cv.match_all}, + } + ) + }, + extra=vol.ALLOW_EXTRA, +) diff --git a/homeassistant/components/blueprint/websocket_api.py b/homeassistant/components/blueprint/websocket_api.py new file mode 100644 index 00000000000..51bec0eb2a0 --- /dev/null +++ b/homeassistant/components/blueprint/websocket_api.py @@ -0,0 +1,86 @@ +"""Websocket API for blueprint.""" +import asyncio +import logging +from typing import Dict, Optional + +import async_timeout +import voluptuous as vol + +from homeassistant.components import websocket_api +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import config_validation as cv + +from . import importer, models +from .const import DOMAIN + +_LOGGER = logging.getLogger(__package__) + + +@callback +def async_setup(hass: HomeAssistant): + """Set up the websocket API.""" + websocket_api.async_register_command(hass, ws_list_blueprints) + websocket_api.async_register_command(hass, ws_import_blueprint) + + +@websocket_api.async_response +@websocket_api.websocket_command( + { + vol.Required("type"): "blueprint/list", + } +) +async def ws_list_blueprints(hass, connection, msg): + """List available blueprints.""" + domain_blueprints: Optional[Dict[str, models.DomainBlueprints]] = hass.data.get( + DOMAIN, {} + ) + results = {} + + for domain, domain_results in zip( + domain_blueprints, + await asyncio.gather( + *[db.async_get_blueprints() for db in domain_blueprints.values()] + ), + ): + for path, value in domain_results.items(): + if isinstance(value, models.Blueprint): + domain_results[path] = { + "metadata": value.metadata, + } + else: + domain_results[path] = {"error": str(value)} + + results[domain] = domain_results + + connection.send_result(msg["id"], results) + + +@websocket_api.async_response +@websocket_api.websocket_command( + { + vol.Required("type"): "blueprint/import", + vol.Required("url"): cv.url, + } +) +async def ws_import_blueprint(hass, connection, msg): + """Import a blueprint.""" + async with async_timeout.timeout(10): + imported_blueprint = await importer.fetch_blueprint_from_url(hass, msg["url"]) + + if imported_blueprint is None: + connection.send_error( + msg["id"], websocket_api.ERR_NOT_SUPPORTED, "This url is not supported" + ) + return + + connection.send_result( + msg["id"], + { + "url": imported_blueprint.url, + "suggested_filename": imported_blueprint.suggested_filename, + "raw_data": imported_blueprint.raw_data, + "blueprint": { + "metadata": imported_blueprint.blueprint.metadata, + }, + }, + ) diff --git a/homeassistant/components/bmw_connected_drive/manifest.json b/homeassistant/components/bmw_connected_drive/manifest.json index 85b521caa39..cb17459e105 100644 --- a/homeassistant/components/bmw_connected_drive/manifest.json +++ b/homeassistant/components/bmw_connected_drive/manifest.json @@ -2,7 +2,6 @@ "domain": "bmw_connected_drive", "name": "BMW Connected Drive", "documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive", - "requirements": ["bimmer_connected==0.7.12"], - "dependencies": [], + "requirements": ["bimmer_connected==0.7.13"], "codeowners": ["@gerard33", "@rikroe"] } diff --git a/homeassistant/components/bond/light.py b/homeassistant/components/bond/light.py index 82187bf6fab..77771167e14 100644 --- a/homeassistant/components/bond/light.py +++ b/homeassistant/components/bond/light.py @@ -68,11 +68,9 @@ class BondLight(BondEntity, LightEntity): @property def supported_features(self) -> Optional[int]: """Flag supported features.""" - features = 0 if self._device.supports_set_brightness(): - features |= SUPPORT_BRIGHTNESS - - return features + return SUPPORT_BRIGHTNESS + return 0 @property def is_on(self) -> bool: diff --git a/homeassistant/components/bond/translations/nl.json b/homeassistant/components/bond/translations/nl.json index 8b2702b6708..8010dfc2e78 100644 --- a/homeassistant/components/bond/translations/nl.json +++ b/homeassistant/components/bond/translations/nl.json @@ -2,6 +2,19 @@ "config": { "abort": { "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, + "flow_title": "Bond: {bond_id} ({host})", + "step": { + "user": { + "data": { + "host": "Host" + } + } } } } \ No newline at end of file diff --git a/homeassistant/components/braviatv/manifest.json b/homeassistant/components/braviatv/manifest.json index 079da14ca87..bdc4822d1d0 100644 --- a/homeassistant/components/braviatv/manifest.json +++ b/homeassistant/components/braviatv/manifest.json @@ -2,7 +2,7 @@ "domain": "braviatv", "name": "Sony Bravia TV", "documentation": "https://www.home-assistant.io/integrations/braviatv", - "requirements": ["bravia-tv==1.0.6"], + "requirements": ["bravia-tv==1.0.8"], "codeowners": ["@bieniu"], "config_flow": true } diff --git a/homeassistant/components/braviatv/translations/fr.json b/homeassistant/components/braviatv/translations/fr.json index b0bb45d9654..68988b1fbfe 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/braviatv/translations/lb.json b/homeassistant/components/braviatv/translations/lb.json index 9eb3bc0aa22..3bcf8702c4f 100644 --- a/homeassistant/components/braviatv/translations/lb.json +++ b/homeassistant/components/braviatv/translations/lb.json @@ -1,11 +1,11 @@ { "config": { "abort": { - "already_configured": "D\u00ebse Fernseh ass scho konfigur\u00e9iert.", + "already_configured": "Apparat ass scho konfigur\u00e9iert.", "no_ip_control": "IP Kontroll ass d\u00e9aktiv\u00e9iert um TV oder den TV g\u00ebtt net \u00ebnnerst\u00ebtzt." }, "error": { - "cannot_connect": "Feeler beim verbannen, ong\u00ebltege Numm oder PIN code.", + "cannot_connect": "Feeler beim verbannen", "invalid_host": "Ong\u00ebltege Numm oder IP Adresse.", "unsupported_model": "D\u00e4in TV Modell g\u00ebtt net \u00ebnnerst\u00ebtzt." }, diff --git a/homeassistant/components/braviatv/translations/zh-Hans.json b/homeassistant/components/braviatv/translations/zh-Hans.json index c60c3f800ef..c839a271614 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/broadlink/config_flow.py b/homeassistant/components/broadlink/config_flow.py index 179fac79dd7..e1a294d746d 100644 --- a/homeassistant/components/broadlink/config_flow.py +++ b/homeassistant/components/broadlink/config_flow.py @@ -94,23 +94,21 @@ class BroadlinkFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): else: device.timeout = timeout - if self.unique_id is None: + if self.source != "reauth": await self.async_set_device(device) self._abort_if_unique_id_configured( updates={CONF_HOST: device.host[0], CONF_TIMEOUT: timeout} ) return await self.async_step_auth() - # The user came from a factory reset. - # We need to check whether the host is correct. if device.mac == self.device.mac: await self.async_set_device(device, raise_on_progress=False) return await self.async_step_auth() errors["base"] = "invalid_host" err_msg = ( - "Invalid host for this configuration flow. The MAC address should be " - f"{format_mac(self.device.mac)}, but {format_mac(device.mac)} was given" + "This is not the device you are looking for. The MAC " + f"address must be {format_mac(self.device.mac)}" ) _LOGGER.error("Failed to connect to the device at %s: %s", host, err_msg) @@ -161,10 +159,10 @@ class BroadlinkFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): await self.async_set_unique_id(device.mac.hex()) if self.source == config_entries.SOURCE_IMPORT: _LOGGER.warning( - "The %s at %s is ready to be configured. Please " - "click Configuration in the sidebar and click " - "Integrations. Then find the device there and click " - "Configure to finish the setup", + "%s (%s at %s) is ready to be configured. Click " + "Configuration in the sidebar, click Integrations and " + "click Configure on the device to complete the setup", + device.name, device.model, device.host[0], ) @@ -183,14 +181,23 @@ class BroadlinkFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Guide the user to unlock the device manually. We are unable to authenticate because the device is locked. - The user needs to factory reset the device to make it work - with Home Assistant. + The user needs to open the Broadlink app and unlock the device. """ + device = self.device + if user_input is None: - return self.async_show_form(step_id="reset", errors=errors) + return self.async_show_form( + step_id="reset", + errors=errors, + description_placeholders={ + "name": device.name, + "model": device.model, + "host": device.host[0], + }, + ) return await self.async_step_user( - {CONF_HOST: self.device.host[0], CONF_TIMEOUT: self.device.timeout} + {CONF_HOST: device.host[0], CONF_TIMEOUT: device.timeout} ) async def async_step_unlock(self, user_input=None): @@ -237,7 +244,14 @@ class BroadlinkFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): data_schema = {vol.Required("unlock", default=False): bool} return self.async_show_form( - step_id="unlock", data_schema=vol.Schema(data_schema), errors=errors + step_id="unlock", + errors=errors, + data_schema=vol.Schema(data_schema), + description_placeholders={ + "name": device.name, + "model": device.model, + "host": device.host[0], + }, ) async def async_step_finish(self, user_input=None): diff --git a/homeassistant/components/broadlink/const.py b/homeassistant/components/broadlink/const.py index 09a667b0969..adb5a437ae5 100644 --- a/homeassistant/components/broadlink/const.py +++ b/homeassistant/components/broadlink/const.py @@ -8,7 +8,7 @@ DOMAIN = "broadlink" DOMAINS_AND_TYPES = ( (REMOTE_DOMAIN, ("RM2", "RM4")), (SENSOR_DOMAIN, ("A1", "RM2", "RM4")), - (SWITCH_DOMAIN, ("MP1", "RM2", "RM4", "SP1", "SP2")), + (SWITCH_DOMAIN, ("MP1", "RM2", "RM4", "SP1", "SP2", "SP4", "SP4B")), ) DEFAULT_PORT = 80 diff --git a/homeassistant/components/broadlink/device.py b/homeassistant/components/broadlink/device.py index 51d9b0a497f..24f473c3262 100644 --- a/homeassistant/components/broadlink/device.py +++ b/homeassistant/components/broadlink/device.py @@ -74,6 +74,7 @@ class BroadlinkDevice: name=config.title, ) api.timeout = config.data[CONF_TIMEOUT] + self.api = api try: await self.hass.async_add_executor_job(api.auth) @@ -91,7 +92,6 @@ class BroadlinkDevice: ) return False - self.api = api self.authorized = True update_manager = get_update_manager(self) @@ -165,8 +165,12 @@ class BroadlinkDevice: self.authorized = False _LOGGER.error( - "The device at %s is locked for authentication. Follow the configuration flow to unlock it", - self.config.data[CONF_HOST], + "%s (%s at %s) is locked. Click Configuration in the sidebar, " + "click Integrations, click Configure on the device and follow " + "the instructions to unlock it", + self.name, + self.api.model, + self.api.host[0], ) self.hass.async_create_task( diff --git a/homeassistant/components/broadlink/manifest.json b/homeassistant/components/broadlink/manifest.json index 9c6e571ec86..0562bc306a5 100644 --- a/homeassistant/components/broadlink/manifest.json +++ b/homeassistant/components/broadlink/manifest.json @@ -2,7 +2,7 @@ "domain": "broadlink", "name": "Broadlink", "documentation": "https://www.home-assistant.io/integrations/broadlink", - "requirements": ["broadlink==0.15.0"], + "requirements": ["broadlink==0.16.0"], "codeowners": ["@danielhiversen", "@felipediel"], "config_flow": true } diff --git a/homeassistant/components/broadlink/remote.py b/homeassistant/components/broadlink/remote.py index 7c7a05ac167..cd86244cea8 100644 --- a/homeassistant/components/broadlink/remote.py +++ b/homeassistant/components/broadlink/remote.py @@ -26,7 +26,7 @@ from homeassistant.components.remote import ( 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 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity): 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) diff --git a/homeassistant/components/broadlink/strings.json b/homeassistant/components/broadlink/strings.json index 3ed1383cc88..d324b0272a8 100644 --- a/homeassistant/components/broadlink/strings.json +++ b/homeassistant/components/broadlink/strings.json @@ -14,11 +14,11 @@ }, "reset": { "title": "Unlock the device", - "description": "Your device is locked for authentication. Follow the instructions to unlock it:\n1. Factory reset the device.\n2. Use the official app to add the device to your local network.\n3. Stop. Do not finish the setup. Close the app.\n4. Click Submit." + "description": "{name} ({model} at {host}) is locked. You need to unlock the device in order to authenticate and complete the configuration. Instructions:\n1. Open the Broadlink app.\n2. Click on the device.\n3. Click `...` in the upper right.\n4. Scroll to the bottom of the page.\n5. Disable the lock." }, "unlock": { "title": "Unlock the device (optional)", - "description": "Your device is locked. This can lead to authentication problems in Home Assistant. Would you like to unlock it?", + "description": "{name} ({model} at {host}) is locked. This can lead to authentication problems in Home Assistant. Would you like to unlock it?", "data": { "unlock": "Yes, do it." } diff --git a/homeassistant/components/broadlink/switch.py b/homeassistant/components/broadlink/switch.py index 4067d1e535d..644255d7d17 100644 --- a/homeassistant/components/broadlink/switch.py +++ b/homeassistant/components/broadlink/switch.py @@ -121,6 +121,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): elif device.api.type == "SP2": switches = [BroadlinkSP2Switch(device)] + elif device.api.type in {"SP4", "SP4B"}: + switches = [BroadlinkSP4Switch(device)] + elif device.api.type == "MP1": switches = [BroadlinkMP1Slot(device, slot) for slot in range(1, 5)] @@ -294,6 +297,27 @@ class BroadlinkSP2Switch(BroadlinkSP1Switch): self.async_write_ha_state() +class BroadlinkSP4Switch(BroadlinkSP1Switch): + """Representation of a Broadlink SP4 switch.""" + + def __init__(self, device, *args, **kwargs): + """Initialize the switch.""" + super().__init__(device, *args, **kwargs) + self._state = self._coordinator.data["pwr"] + + @property + def assumed_state(self): + """Return True if unable to access real state of the switch.""" + return False + + @callback + def update_data(self): + """Update data.""" + if self._coordinator.last_update_success: + self._state = self._coordinator.data["pwr"] + self.async_write_ha_state() + + class BroadlinkMP1Slot(BroadlinkSwitch): """Representation of a Broadlink MP1 slot.""" diff --git a/homeassistant/components/broadlink/translations/ca.json b/homeassistant/components/broadlink/translations/ca.json index edde3bbdfcf..9ea559dcf93 100644 --- a/homeassistant/components/broadlink/translations/ca.json +++ b/homeassistant/components/broadlink/translations/ca.json @@ -25,14 +25,14 @@ "title": "Tria un nom per al dispositiu" }, "reset": { - "description": "El dispositiu est\u00e0 bloquejat per autenticaci\u00f3. Segueix les instruccions per desbloquejar-lo:\n 1. Restableix de f\u00e0brica el dispositiu. \n 2. Utilitza l'aplicaci\u00f3 oficial per afegir el dispositiu a la teva xarxa local. \n 3. Atura'l. No acabis la configuraci\u00f3. Tanca l'aplicaci\u00f3. \n 4. Fes clic a Envia.", + "description": "{name} ({model} a {host}) est\u00e0 bloquejat. Has de desbloquejar el dispositiu per finalitzar la configuraci\u00f3 i l'autenticaci\u00f3. Instruccions:\n 1. Obre l'aplicaci\u00f3 de Broadlink. \n 2. Clica al dispositiu. \n 3. Clica a '...' situat a la cantonada superior dreta. \n 4. Baixa fins al final de la p\u00e0gina.\n 5. Desactiva el bloqueig.", "title": "Desbloqueig de dispositiu" }, "unlock": { "data": { "unlock": "S\u00ed, fes-ho." }, - "description": "El dispositiu est\u00e0 bloquejat. Aix\u00f2 pot donar problemes d'autenticaci\u00f3 a Home Assistant. Vols desbloquejar-lo?", + "description": "{name} ({model} a {host}) est\u00e0 bloquejat. Aix\u00f2 pot donar problemes d'autenticaci\u00f3 a Home Assistant. Vols desbloquejar-lo?", "title": "Desbloqueig de dispositiu (opcional)" }, "user": { diff --git a/homeassistant/components/broadlink/translations/cs.json b/homeassistant/components/broadlink/translations/cs.json index 1ce891d60af..79daf23cdf2 100644 --- a/homeassistant/components/broadlink/translations/cs.json +++ b/homeassistant/components/broadlink/translations/cs.json @@ -25,14 +25,14 @@ "title": "Vyberte jm\u00e9no za\u0159\u00edzen\u00ed" }, "reset": { - "description": "Va\u0161e za\u0159\u00edzen\u00ed je uzam\u010deno pro ov\u011b\u0159en\u00ed. Odemkn\u011bte jej podle pokyn\u016f:\n1. Obnovte tov\u00e1rn\u00ed nastaven\u00ed za\u0159\u00edzen\u00ed.\n2. Pomoc\u00ed ofici\u00e1ln\u00ed aplikace p\u0159idejte za\u0159\u00edzen\u00ed do m\u00edstn\u00ed s\u00edt\u011b.\n3. Stop. Neukon\u010dujte nastaven\u00ed. Zav\u0159ete aplikaci.\n4. Klikn\u011bte na Odeslat.", + "description": "{name} ({model} na {host}) je uzam\u010deno. Chcete-li za\u0159\u00edzen\u00ed ov\u011b\u0159it a dokon\u010dit nastaven\u00ed, mus\u00edte ho odemknout. Instrukce:\n1. Otev\u0159ete aplikaci Broadlink.\n2. Klikn\u011bte na za\u0159\u00edzen\u00ed.\n3. Vpravo naho\u0159e klikn\u011bte na `...`.\n4. P\u0159ejd\u011bte do doln\u00ed \u010d\u00e1sti str\u00e1nky.\n5. Vypn\u011bte z\u00e1mek.", "title": "Odemknout za\u0159\u00edzen\u00ed" }, "unlock": { "data": { "unlock": "Ano, ud\u011blej to." }, - "description": "Va\u0161e za\u0159\u00edzen\u00ed je uzam\u010deno. To m\u016f\u017ee v\u00e9st k probl\u00e9m\u016fm s ov\u011b\u0159ov\u00e1n\u00edm v Home Assistant. Chcete jej odemknout?", + "description": "{name} ({model} na {host}) je uzam\u010deno. To m\u016f\u017ee v\u00e9st k probl\u00e9m\u016fm s ov\u011b\u0159ov\u00e1n\u00edm v Home Assistant. Chcete jej odemknout?", "title": "Odemknut\u00ed za\u0159\u00edzen\u00ed (voliteln\u00e9)" }, "user": { diff --git a/homeassistant/components/broadlink/translations/de.json b/homeassistant/components/broadlink/translations/de.json index 99af347f1f4..e34db6d7262 100644 --- a/homeassistant/components/broadlink/translations/de.json +++ b/homeassistant/components/broadlink/translations/de.json @@ -1,8 +1,12 @@ { "config": { "abort": { + "invalid_host": "Ung\u00fcltiger Hostname oder IP Adresse", "not_supported": "Ger\u00e4t nicht unterst\u00fctzt" }, + "error": { + "invalid_host": "Ung\u00fcltiger Hostname oder IP Adresse" + }, "step": { "auth": { "title": "Authentifiziere dich beim Ger\u00e4t" diff --git a/homeassistant/components/broadlink/translations/en.json b/homeassistant/components/broadlink/translations/en.json index 0b1029b8a0a..f5d84b89d24 100644 --- a/homeassistant/components/broadlink/translations/en.json +++ b/homeassistant/components/broadlink/translations/en.json @@ -25,14 +25,14 @@ "title": "Choose a name for the device" }, "reset": { - "description": "Your device is locked for authentication. Follow the instructions to unlock it:\n1. Factory reset the device.\n2. Use the official app to add the device to your local network.\n3. Stop. Do not finish the setup. Close the app.\n4. Click Submit.", + "description": "{name} ({model} at {host}) is locked. You need to unlock the device in order to authenticate and complete the configuration. Instructions:\n1. Open the Broadlink app.\n2. Click on the device.\n3. Click `...` in the upper right.\n4. Scroll to the bottom of the page.\n5. Disable the lock.", "title": "Unlock the device" }, "unlock": { "data": { "unlock": "Yes, do it." }, - "description": "Your device is locked. This can lead to authentication problems in Home Assistant. Would you like to unlock it?", + "description": "{name} ({model} at {host}) is locked. This can lead to authentication problems in Home Assistant. Would you like to unlock it?", "title": "Unlock the device (optional)" }, "user": { diff --git a/homeassistant/components/broadlink/translations/et.json b/homeassistant/components/broadlink/translations/et.json index 20ae86b38c7..45f25362a4f 100644 --- a/homeassistant/components/broadlink/translations/et.json +++ b/homeassistant/components/broadlink/translations/et.json @@ -25,14 +25,14 @@ "title": "Seadme nime valimine" }, "reset": { - "description": "Seade on autentimiseks lukustatud. Selle avamiseks j\u00e4rgi juhiseid.\n 1. L\u00e4htesta seade tehaseseadetele.\n 2. Kasuta seadme kohalikku v\u00f5rku lisamiseks ametlikku rakendust.\n 3. Peatu. \u00c4ra l\u00f5petaa seadistamist. Sulgea rakendus.\n 4. Kl\u00f5psa nuppu Esita.", + "description": "{name} ( {model} asukohas {host} ) on lukus. Sidumise autentimiseks ja l\u00f5puleviimiseks pead seadme avama. Juhised:\n 1. Avad rakendus Broadlink.\n 2. Kl\u00f5psa seadmel.\n 3. Kl\u00f5psa paremas \u00fclanurgas nuppu ....\n 4. Keri lehe alaossa.\n 5. Keela lukk.", "title": "Seadme lukustuse eemaldamine" }, "unlock": { "data": { "unlock": "Jah, tee seda." }, - "description": "Seade on lukustatud. See v\u00f5ib p\u00f5hjustada Home Assistanti autentimisprobleeme. Kas soovid selle avada?", + "description": "{name} ( {model} asukohas {host} ) on lukus. See v\u00f5ib p\u00f5hjustada Home Assistanti autentimisprobleeme. Kas soovid selle avada?", "title": "Seadme lukustuse eemaldamine (valikuline)" }, "user": { diff --git a/homeassistant/components/broadlink/translations/fr.json b/homeassistant/components/broadlink/translations/fr.json index bb3af76ff95..1d80059fb7a 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/broadlink/translations/it.json b/homeassistant/components/broadlink/translations/it.json index d8e64b4bea3..3dcc07db87c 100644 --- a/homeassistant/components/broadlink/translations/it.json +++ b/homeassistant/components/broadlink/translations/it.json @@ -25,14 +25,14 @@ "title": "Scegliere un nome per il dispositivo" }, "reset": { - "description": "Il tuo dispositivo \u00e8 bloccato per l'autenticazione. Segui le istruzioni per sbloccarlo: \n 1. Ripristinare le impostazioni di fabbrica del dispositivo. \n 2. Usa l'app ufficiale per aggiungere il dispositivo alla tua rete locale. \n 3. Fermati. Non finire la configurazione. Chiudi l'app. \n 4. Fare clic su Invia.", + "description": "{name} ( {model} su {host} ) \u00e8 bloccato. \u00c8 necessario sbloccare il dispositivo per autenticarsi e completare la configurazione. Istruzioni:\n 1. Apri l'app Broadlink.\n 2. Fare clic sul dispositivo.\n 3. Fare clic su \"...\" in alto a destra.\n 4. Scorri fino in fondo alla pagina.\n 5. Disabilitare il blocco.", "title": "Sbloccare il dispositivo" }, "unlock": { "data": { "unlock": "S\u00ec, fallo." }, - "description": "Il tuo dispositivo \u00e8 bloccato. Ci\u00f2 pu\u00f2 causare problemi di autenticazione in Home Assistant. Vorresti sbloccarlo?", + "description": "{name} ({model} su {host}) \u00e8 bloccato. Ci\u00f2 pu\u00f2 causare problemi di autenticazione in Home Assistant. Vorresti sbloccarlo?", "title": "Sblocca il dispositivo (opzionale)" }, "user": { diff --git a/homeassistant/components/broadlink/translations/lb.json b/homeassistant/components/broadlink/translations/lb.json index 4946a504404..98e277654a4 100644 --- a/homeassistant/components/broadlink/translations/lb.json +++ b/homeassistant/components/broadlink/translations/lb.json @@ -25,6 +25,7 @@ "title": "Numm auswielen fir den Apparat" }, "reset": { + "description": "D\u00e4in Apparat ass gespaart fir Authentifikatioun. Folleg den Instruktiounen fir en z'entsp\u00e4rren:\n1. Factory Reset vum Apparat\n2. Benotz d\u00e9i offiziell App fir den Apparat zu dengem Netzwierk dob\u00e4izesetzen.\n3. Stop. Schl\u00e9iss den Setup net of. Maach d'app zou.\n4. Klick op ofsch\u00e9cken", "title": "Apparat entsp\u00e4ren" }, "unlock": { diff --git a/homeassistant/components/broadlink/translations/nl.json b/homeassistant/components/broadlink/translations/nl.json index ea0449afc58..7205512d368 100644 --- a/homeassistant/components/broadlink/translations/nl.json +++ b/homeassistant/components/broadlink/translations/nl.json @@ -1,13 +1,27 @@ { "config": { "abort": { - "not_supported": "Apparaat wordt niet ondersteund" + "already_configured": "Apparaat is al geconfigureerd", + "cannot_connect": "Kon niet verbinden", + "not_supported": "Apparaat wordt niet ondersteund", + "unknown": "Onverwachte fout" }, + "error": { + "cannot_connect": "Kon niet verbinden", + "unknown": "Onverwachte fout" + }, + "flow_title": "{name} ({model} bij {host})", "step": { "finish": { "data": { "name": "Naam" } + }, + "user": { + "data": { + "host": "Host" + }, + "title": "Verbinding maken met het apparaat" } } } diff --git a/homeassistant/components/broadlink/translations/no.json b/homeassistant/components/broadlink/translations/no.json index d052e495b72..8c72e9d92f8 100644 --- a/homeassistant/components/broadlink/translations/no.json +++ b/homeassistant/components/broadlink/translations/no.json @@ -25,14 +25,14 @@ "title": "Velg et navn p\u00e5 enheten" }, "reset": { - "description": "Enheten er l\u00e5st for godkjenning. F\u00f8lg instruksjonene for \u00e5 l\u00e5se den opp:\n1. Tilbakestill enheten til fabrikkstandard.\n2. Bruk den offisielle appen til \u00e5 legge til enheten i ditt lokale nettverk.\n3. Stopp. Ikke fullf\u00f8r oppsettet. Lukk appen.\n4. Klikk p\u00e5 Send.", + "description": "{name} ( {model} p\u00e5 {host} ) er l\u00e5st. Du m\u00e5 l\u00e5se opp enheten for \u00e5 autentisere og fullf\u00f8re konfigurasjonen. Bruksanvisning:\n 1. \u00c5pne Broadlink-appen.\n 2. Klikk p\u00e5 enheten.\n 3. Klikk p\u00e5 `...` \u00f8verst til h\u00f8yre.\n 4. Bla til bunnen av siden.\n 5. Deaktiver l\u00e5sen.", "title": "L\u00e5s opp enheten" }, "unlock": { "data": { "unlock": "Ja, gj\u00f8r det." }, - "description": "Enheten er l\u00e5st. Dette kan f\u00f8re til godkjenningsproblemer i Home Assistant. Vil du l\u00e5se den opp?", + "description": "{name} ( {model} p\u00e5 {host} ) er l\u00e5st. Dette kan f\u00f8re til autentiseringsproblemer i Home Assistant. Vil du l\u00e5se opp den?", "title": "L\u00e5s opp enheten (valgfritt)" }, "user": { diff --git a/homeassistant/components/broadlink/translations/pl.json b/homeassistant/components/broadlink/translations/pl.json index a93c15c4288..d3e517d9ec7 100644 --- a/homeassistant/components/broadlink/translations/pl.json +++ b/homeassistant/components/broadlink/translations/pl.json @@ -25,14 +25,14 @@ "title": "Wprowad\u017a nazw\u0119 dla urz\u0105dzenia" }, "reset": { - "description": "Twoje urz\u0105dzenie jest zablokowane. Post\u0119puj zgodnie z instrukcjami, aby je odblokowa\u0107: \nOpcja 1 (preferowana):\n1. W aplikacji Broadlink wejd\u017a w swoje urz\u0105dzenie\n2. Kliknij \"\u2022 \u2022 \u2022\" \n3. Wy\u0142\u0105cz opcje \"Lock Device\"\n\nOpcja 2:\n1. Zresetuj urz\u0105dzenie do ustawie\u0144 fabrycznych. \n2. Dodaj urz\u0105dzenie w oficjalnej aplikacji do swojej sieci. \n3. Stop! Nie ko\u0144cz konfiguracji w aplikacji tylko j\u0105 zamknij. \n4. Potwierd\u017a odblokowanie (przycisk Odblokuj).", + "description": "Urz\u0105dzenie {name} ({model} na {host}) jest zablokowane. Post\u0119puj zgodnie z instrukcjami, aby je odblokowa\u0107: \n1. Otw\u00f3rz aplikacj\u0119 Broadlink\n2. Wejd\u017a w swoje urz\u0105dzenie\n3. Kliknij \"\u2022 \u2022 \u2022\" w prawym g\u00f3rnym rogu\n4. Przewi\u0144 ekran na sam d\u00f3\u0142\n5. Wy\u0142\u0105cz opcj\u0119 \"Lock Device\"", "title": "Odblokuj urz\u0105dzeniem" }, "unlock": { "data": { "unlock": "Odblokuj" }, - "description": "To urz\u0105dzenie jest zablokowane. Mo\u017ce to prowadzi\u0107 do problem\u00f3w z uwierzytelnianiem w Home Assistant. Chcesz je odblokowa\u0107?", + "description": "Urz\u0105dzenie {name} ({model} na {host}) jest zablokowane. Mo\u017ce to prowadzi\u0107 do problem\u00f3w z uwierzytelnianiem w Home Assistant. Chcesz je odblokowa\u0107?", "title": "Odblokuj urz\u0105dzenie (opcjonalne)" }, "user": { diff --git a/homeassistant/components/broadlink/translations/ru.json b/homeassistant/components/broadlink/translations/ru.json index 617c508b8c2..19470d5a66d 100644 --- a/homeassistant/components/broadlink/translations/ru.json +++ b/homeassistant/components/broadlink/translations/ru.json @@ -25,14 +25,14 @@ "title": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430" }, "reset": { - "description": "\u0412\u0430\u0448\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0434\u043b\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0421\u043b\u0435\u0434\u0443\u0439\u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e: \n 1. \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u0431\u0440\u043e\u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u0437\u0430\u0432\u043e\u0434\u0441\u043a\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438. \n 2. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0432 \u0412\u0430\u0448\u0443 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u0435\u0442\u044c. \n 3. \u041d\u0435 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0438 \u0437\u0430\u043a\u0440\u043e\u0439\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \n 4. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c.", + "description": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e {name} ({model}, {host}) \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043e. \u0421\u043b\u0435\u0434\u0443\u0439\u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e: \n 1. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Broadlink. \n 2. \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e. \n 3. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 `...` \u0432 \u043f\u0440\u0430\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443. \n 4. \u041f\u0440\u043e\u043a\u0440\u0443\u0442\u0438\u0442\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0432\u043d\u0438\u0437.\n 5. \u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0437\u0430\u043c\u043e\u043a.", "title": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430" }, "unlock": { "data": { "unlock": "\u0414\u0430, \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e." }, - "description": "\u0412\u0430\u0448\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043e. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c \u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0432 Home Assistant. \u0425\u043e\u0442\u0438\u0442\u0435 \u0435\u0433\u043e \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c?", + "description": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e {name} ({model}, {host}) \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043e. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c \u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0432 Home Assistant. \u0425\u043e\u0442\u0438\u0442\u0435 \u0435\u0433\u043e \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c?", "title": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e)" }, "user": { diff --git a/homeassistant/components/broadlink/translations/zh-Hant.json b/homeassistant/components/broadlink/translations/zh-Hant.json index 01db5167bb2..8781b90c3d8 100644 --- a/homeassistant/components/broadlink/translations/zh-Hant.json +++ b/homeassistant/components/broadlink/translations/zh-Hant.json @@ -25,14 +25,14 @@ "title": "\u9078\u64c7\u8a2d\u5099\u540d\u7a31" }, "reset": { - "description": "\u8a2d\u5099\u5df2\u9396\u5b9a\u9700\u9032\u884c\u8a8d\u8b49\u3001\u8acb\u8ddf\u96a8\u6307\u793a\u9032\u884c\u89e3\u9396\uff1a\n1. \u91cd\u7f6e\u8a2d\u5099\u3002\n2. \u4f7f\u7528\u5b98\u65b9 App \u65b0\u589e\u8a2d\u5099\u81f3\u5340\u57df\u7db2\u8def\u3002\n3. \u4e2d\u65b7\uff0c\u4e0d\u8981\u5b8c\u6210\u8a2d\u5b9a\u3002\u95dc\u9589 App\u3002\n4. \u9ede\u9078\u50b3\u9001\u3002", + "description": "{name}\uff08\u4f4d\u65bc {host} \u7684 {model}\uff09\u8a2d\u5099\u5df2\u9396\u5b9a\uff0c\u9700\u8981\u89e3\u9396\u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u8207\u5b8c\u6210\u8a2d\u5b9a\uff0c\u8acb\u8ddf\u96a8\u6307\u793a\uff1a\n1. \u958b\u555f Broadlink App\u3002\n2. \u9ede\u9078\u8a2d\u5099\u3002\n3. \u9ede\u9078\u53f3\u4e0a\u65b9\u7684 `...`\u3002\n4. \u6372\u52d5\u81f3\u6700\u5e95\u9801\u3002\n5. \u95dc\u9589\u9396\u5b9a\u3002", "title": "\u89e3\u9396\u8a2d\u5099" }, "unlock": { "data": { "unlock": "\u662f\uff0c\u57f7\u884c\u3002" }, - "description": "\u8a2d\u5099\u5df2\u9396\u5b9a\uff0c\u53ef\u80fd\u5c0e\u81f4 Home Assistant \u8a8d\u8b49\u554f\u984c\uff0c\u662f\u5426\u8981\u89e3\u9396\uff1f", + "description": "{name}\uff08\u4f4d\u65bc {host} \u7684 {model}\uff09\u8a2d\u5099\u5df2\u9396\u5b9a\uff0c\u53ef\u80fd\u5c0e\u81f4 Home Assistant \u8a8d\u8b49\u554f\u984c\uff0c\u662f\u5426\u8981\u89e3\u9396\uff1f", "title": "\u89e3\u9396\u8a2d\u5099\uff08\u9078\u9805\uff09" }, "user": { diff --git a/homeassistant/components/broadlink/updater.py b/homeassistant/components/broadlink/updater.py index 6d3bbc5b6c1..eb42e688a59 100644 --- a/homeassistant/components/broadlink/updater.py +++ b/homeassistant/components/broadlink/updater.py @@ -31,6 +31,8 @@ def get_update_manager(device): "RM4": BroadlinkRMUpdateManager, "SP1": BroadlinkSP1UpdateManager, "SP2": BroadlinkSP2UpdateManager, + "SP4": BroadlinkSP4UpdateManager, + "SP4B": BroadlinkSP4UpdateManager, } return update_managers[device.api.type](device) @@ -42,6 +44,8 @@ class BroadlinkUpdateManager(ABC): monitor device availability. """ + SCAN_INTERVAL = timedelta(minutes=1) + def __init__(self, device): """Initialize the update manager.""" self.device = device @@ -50,7 +54,7 @@ class BroadlinkUpdateManager(ABC): _LOGGER, name=f"{device.name} ({device.api.model} at {device.api.host[0]})", update_method=self.async_update, - update_interval=timedelta(minutes=1), + update_interval=self.SCAN_INTERVAL, ) self.available = None self.last_update = None @@ -62,7 +66,7 @@ class BroadlinkUpdateManager(ABC): except (BroadlinkException, OSError) as err: if self.available and ( - dt.utcnow() - self.last_update > timedelta(minutes=3) + dt.utcnow() - self.last_update > self.SCAN_INTERVAL * 3 or isinstance(err, (AuthorizationError, OSError)) ): self.available = False @@ -94,6 +98,8 @@ class BroadlinkUpdateManager(ABC): class BroadlinkA1UpdateManager(BroadlinkUpdateManager): """Manages updates for Broadlink A1 devices.""" + SCAN_INTERVAL = timedelta(seconds=10) + async def async_fetch_data(self): """Fetch data from the device.""" return await self.device.async_request(self.device.api.check_sensors_raw) @@ -153,3 +159,11 @@ class BroadlinkSP2UpdateManager(BroadlinkUpdateManager): except (CommandNotSupportedError, StorageError): data["load_power"] = None return data + + +class BroadlinkSP4UpdateManager(BroadlinkUpdateManager): + """Manages updates for Broadlink SP4 devices.""" + + async def async_fetch_data(self): + """Fetch data from the device.""" + return await self.device.async_request(self.device.api.get_state) diff --git a/homeassistant/components/brother/translations/ca.json b/homeassistant/components/brother/translations/ca.json index e32d26ff79a..7d90fd8510d 100644 --- a/homeassistant/components/brother/translations/ca.json +++ b/homeassistant/components/brother/translations/ca.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "Ha fallat la connexi\u00f3", "snmp_error": "El servidor SNMP s'ha tancat o la impressora no \u00e9s compatible.", "wrong_host": "Nom de l'amfitri\u00f3 o adre\u00e7a IP inv\u00e0lids." }, diff --git a/homeassistant/components/brother/translations/cs.json b/homeassistant/components/brother/translations/cs.json index b44a68c9db3..1e2991c26d8 100644 --- a/homeassistant/components/brother/translations/cs.json +++ b/homeassistant/components/brother/translations/cs.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit", "wrong_host": "Neplatn\u00fd hostitel nebo IP adresa." }, "flow_title": "Tisk\u00e1rna Brother: {model} {serial_number}", @@ -21,7 +20,7 @@ "data": { "type": "Typ tisk\u00e1rny" }, - "description": "Chcete p\u0159idat tisk\u00e1rnu Brother {model} se s\u00e9riov\u00fdm \u010d\u00edslem \"{serial_number}\" do Home Assistant?", + "description": "Chcete p\u0159idat tisk\u00e1rnu Brother {model} se s\u00e9riov\u00fdm \u010d\u00edslem `{serial_number}` do Home Assistant?", "title": "Objeven\u00e1 tisk\u00e1rna Brother" } } diff --git a/homeassistant/components/brother/translations/da.json b/homeassistant/components/brother/translations/da.json index 09a8ca031dd..fc9cd0079d8 100644 --- a/homeassistant/components/brother/translations/da.json +++ b/homeassistant/components/brother/translations/da.json @@ -5,7 +5,6 @@ "unsupported_model": "Denne printermodel underst\u00f8ttes ikke." }, "error": { - "connection_error": "Forbindelsesfejl.", "snmp_error": "SNMP-server er sl\u00e5et fra, eller printeren underst\u00f8ttes ikke.", "wrong_host": "Ugyldigt v\u00e6rtsnavn eller IP-adresse." }, diff --git a/homeassistant/components/brother/translations/de.json b/homeassistant/components/brother/translations/de.json index 78f2dd882bd..4c07d1a2997 100644 --- a/homeassistant/components/brother/translations/de.json +++ b/homeassistant/components/brother/translations/de.json @@ -5,7 +5,6 @@ "unsupported_model": "Dieses Druckermodell wird nicht unterst\u00fctzt." }, "error": { - "connection_error": "Verbindungsfehler", "snmp_error": "SNMP-Server deaktiviert oder Drucker nicht unterst\u00fctzt.", "wrong_host": " Ung\u00fcltiger Hostname oder IP-Adresse" }, diff --git a/homeassistant/components/brother/translations/en.json b/homeassistant/components/brother/translations/en.json index af5cc681d51..66c5db4282d 100644 --- a/homeassistant/components/brother/translations/en.json +++ b/homeassistant/components/brother/translations/en.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect", "snmp_error": "SNMP server turned off or printer not supported.", "wrong_host": "Invalid hostname or IP address." }, diff --git a/homeassistant/components/brother/translations/es-419.json b/homeassistant/components/brother/translations/es-419.json index 17b1b8f9c89..33d06705017 100644 --- a/homeassistant/components/brother/translations/es-419.json +++ b/homeassistant/components/brother/translations/es-419.json @@ -5,7 +5,6 @@ "unsupported_model": "Este modelo de impresora no es compatible." }, "error": { - "connection_error": "Error de conexi\u00f3n.", "snmp_error": "El servidor SNMP est\u00e1 apagado o la impresora no es compatible.", "wrong_host": "Nombre de host o direcci\u00f3n IP no v\u00e1lidos." }, diff --git a/homeassistant/components/brother/translations/es.json b/homeassistant/components/brother/translations/es.json index c64fb9adad0..43b3cefdded 100644 --- a/homeassistant/components/brother/translations/es.json +++ b/homeassistant/components/brother/translations/es.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "connection_error": "No se pudo conectar", "snmp_error": "El servidor SNMP est\u00e1 apagado o la impresora no es compatible.", "wrong_host": "Nombre del host o direcci\u00f3n IP no v\u00e1lidos." }, diff --git a/homeassistant/components/brother/translations/et.json b/homeassistant/components/brother/translations/et.json index 27719d66d5b..190db6ed768 100644 --- a/homeassistant/components/brother/translations/et.json +++ b/homeassistant/components/brother/translations/et.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "\u00dchenduse t\u00f5rge.", "snmp_error": "SNMP-server on v\u00e4lja l\u00fclitatud v\u00f5i printerit ei toetata.", "wrong_host": "Sobimatu hostinimi v\u00f5i IP-aadress." }, diff --git a/homeassistant/components/brother/translations/fr.json b/homeassistant/components/brother/translations/fr.json index 83b360b1706..5eb00bb4447 100644 --- a/homeassistant/components/brother/translations/fr.json +++ b/homeassistant/components/brother/translations/fr.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "\u00c9chec de connexion", - "connection_error": "Erreur de connexion.", "snmp_error": "Serveur SNMP d\u00e9sactiv\u00e9 ou imprimante non prise en charge.", "wrong_host": "Nom d'h\u00f4te ou adresse IP invalide." }, diff --git a/homeassistant/components/brother/translations/hu.json b/homeassistant/components/brother/translations/hu.json index 3c29c7101b9..2869d74fd04 100644 --- a/homeassistant/components/brother/translations/hu.json +++ b/homeassistant/components/brother/translations/hu.json @@ -5,7 +5,6 @@ "unsupported_model": "Ez a nyomtat\u00f3modell nem t\u00e1mogatott." }, "error": { - "connection_error": "Csatlakoz\u00e1si hiba.", "snmp_error": "Az SNMP szerver ki van kapcsolva, vagy a nyomtat\u00f3 nem t\u00e1mogatott.", "wrong_host": "\u00c9rv\u00e9nytelen \u00e1llom\u00e1sn\u00e9v vagy IP-c\u00edm." }, diff --git a/homeassistant/components/brother/translations/it.json b/homeassistant/components/brother/translations/it.json index 47191618bc8..06decb26173 100644 --- a/homeassistant/components/brother/translations/it.json +++ b/homeassistant/components/brother/translations/it.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi", "snmp_error": "Server SNMP spento o stampante non supportata.", "wrong_host": "Nome host o indirizzo IP non valido." }, diff --git a/homeassistant/components/brother/translations/ko.json b/homeassistant/components/brother/translations/ko.json index ce0231c497c..a54aea7f108 100644 --- a/homeassistant/components/brother/translations/ko.json +++ b/homeassistant/components/brother/translations/ko.json @@ -5,7 +5,6 @@ "unsupported_model": "\uc774 \ud504\ub9b0\ud130 \ubaa8\ub378\uc740 \uc9c0\uc6d0\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4." }, "error": { - "connection_error": "\uc5f0\uacb0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.", "snmp_error": "SNMP \uc11c\ubc84\uac00 \uaebc\uc838 \uc788\uac70\ub098 \uc9c0\uc6d0\ub418\uc9c0 \uc54a\ub294 \ud504\ub9b0\ud130\uc785\ub2c8\ub2e4.", "wrong_host": "\ud638\uc2a4\ud2b8 \uc774\ub984 \ub610\ub294 IP \uc8fc\uc18c\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, diff --git a/homeassistant/components/brother/translations/lb.json b/homeassistant/components/brother/translations/lb.json index 8c1842f9c26..91964ec90ca 100644 --- a/homeassistant/components/brother/translations/lb.json +++ b/homeassistant/components/brother/translations/lb.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "already_configured": "D\u00ebse Printer ass scho konfigur\u00e9iert.", + "already_configured": "Apparat ass scho konfigur\u00e9iert.", "unsupported_model": "D\u00ebse Printer Modell g\u00ebtt net \u00ebnnerst\u00ebtzt." }, "error": { "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler bei der Verbindung.", "snmp_error": "SNMP Server ausgeschalt oder Printer net \u00ebnnerst\u00ebtzt.", "wrong_host": "Ong\u00ebltege Numm oder IP Adresse" }, diff --git a/homeassistant/components/brother/translations/nl.json b/homeassistant/components/brother/translations/nl.json index f1d1763e0be..d754b2df9c1 100644 --- a/homeassistant/components/brother/translations/nl.json +++ b/homeassistant/components/brother/translations/nl.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Verbindingsfout.", "snmp_error": "SNMP-server uitgeschakeld of printer wordt niet ondersteund.", "wrong_host": "Ongeldige hostnaam of IP-adres." }, diff --git a/homeassistant/components/brother/translations/no.json b/homeassistant/components/brother/translations/no.json index 2894b57dfe0..923d1afe68d 100644 --- a/homeassistant/components/brother/translations/no.json +++ b/homeassistant/components/brother/translations/no.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes", "snmp_error": "SNMP verten er skrudd av eller printeren er ikke st\u00f8ttet.", "wrong_host": "Ugyldig vertsnavn eller IP-adresse." }, diff --git a/homeassistant/components/brother/translations/pl.json b/homeassistant/components/brother/translations/pl.json index 4fe878947fa..9b62e9afed4 100644 --- a/homeassistant/components/brother/translations/pl.json +++ b/homeassistant/components/brother/translations/pl.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "snmp_error": "Serwer SNMP wy\u0142\u0105czony lub drukarka nie jest obs\u0142ugiwana", "wrong_host": "Niepoprawna nazwa hosta lub adres IP drukarki" }, diff --git a/homeassistant/components/brother/translations/pt-BR.json b/homeassistant/components/brother/translations/pt-BR.json index 03f0788cb85..e7ee63e6e5b 100644 --- a/homeassistant/components/brother/translations/pt-BR.json +++ b/homeassistant/components/brother/translations/pt-BR.json @@ -4,7 +4,6 @@ "unsupported_model": "Este modelo de impressora n\u00e3o \u00e9 suportado." }, "error": { - "connection_error": "Erro de conex\u00e3o.", "snmp_error": "Servidor SNMP desligado ou impressora n\u00e3o suportada.", "wrong_host": "Nome de host ou endere\u00e7o IP inv\u00e1lido." }, diff --git a/homeassistant/components/brother/translations/ru.json b/homeassistant/components/brother/translations/ru.json index 635fbf87f48..6c90cd374a8 100644 --- a/homeassistant/components/brother/translations/ru.json +++ b/homeassistant/components/brother/translations/ru.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "snmp_error": "\u0421\u0435\u0440\u0432\u0435\u0440 SNMP \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d \u0438\u043b\u0438 \u043f\u0440\u0438\u043d\u0442\u0435\u0440 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f.", "wrong_host": "\u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u0438\u043b\u0438 IP-\u0430\u0434\u0440\u0435\u0441." }, diff --git a/homeassistant/components/brother/translations/sl.json b/homeassistant/components/brother/translations/sl.json index 2736366be02..53ce1423819 100644 --- a/homeassistant/components/brother/translations/sl.json +++ b/homeassistant/components/brother/translations/sl.json @@ -5,7 +5,6 @@ "unsupported_model": "Ta model tiskalnika ni podprt." }, "error": { - "connection_error": "Napaka v povezavi.", "snmp_error": "Stre\u017enik SNMP je izklopljen ali tiskalnik ni podprt.", "wrong_host": "Neveljavno ime gostitelja ali IP naslov." }, diff --git a/homeassistant/components/brother/translations/sv.json b/homeassistant/components/brother/translations/sv.json index 204064c0ab4..3a049bb92c8 100644 --- a/homeassistant/components/brother/translations/sv.json +++ b/homeassistant/components/brother/translations/sv.json @@ -5,7 +5,6 @@ "unsupported_model": "Den h\u00e4r skrivarmodellen st\u00f6ds inte." }, "error": { - "connection_error": "Anslutningsfel.", "snmp_error": "SNMP-servern har st\u00e4ngts av eller s\u00e5 st\u00f6ds inte skrivaren.", "wrong_host": "Ogiltigt v\u00e4rdnamn eller IP-adress." }, diff --git a/homeassistant/components/brother/translations/zh-Hant.json b/homeassistant/components/brother/translations/zh-Hant.json index 36455eaf085..79dc4c81b2a 100644 --- a/homeassistant/components/brother/translations/zh-Hant.json +++ b/homeassistant/components/brother/translations/zh-Hant.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557", "snmp_error": "SNMP \u4f3a\u670d\u5668\u70ba\u95dc\u9589\u72c0\u614b\u6216\u5370\u8868\u6a5f\u4e0d\u652f\u63f4\u3002", "wrong_host": "\u7121\u6548\u4e3b\u6a5f\u540d\u6216 IP \u4f4d\u5740" }, diff --git a/homeassistant/components/bsblan/__init__.py b/homeassistant/components/bsblan/__init__.py index 870d96dab86..9f4bb38e315 100644 --- a/homeassistant/components/bsblan/__init__.py +++ b/homeassistant/components/bsblan/__init__.py @@ -28,7 +28,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: bsblan = BSBLan( entry.data[CONF_HOST], passkey=entry.data[CONF_PASSKEY], - loop=hass.loop, port=entry.data[CONF_PORT], session=session, ) diff --git a/homeassistant/components/bsblan/climate.py b/homeassistant/components/bsblan/climate.py index c84b3304c7b..a97c13c3424 100644 --- a/homeassistant/components/bsblan/climate.py +++ b/homeassistant/components/bsblan/climate.py @@ -94,14 +94,13 @@ class BSBLanClimate(ClimateEntity): """Initialize BSBLan climate device.""" self._current_temperature: Optional[float] = None self._available = True - self._current_hvac_mode: Optional[int] = None + self._hvac_mode: Optional[str] = None self._target_temperature: Optional[float] = None - self._info: Info = info - self.bsblan = bsblan self._temperature_unit = None - self._hvac_mode = None self._preset_mode = None self._store_hvac_mode = None + self._info: Info = info + self.bsblan = bsblan @property def name(self) -> str: @@ -138,7 +137,7 @@ class BSBLanClimate(ClimateEntity): @property def hvac_mode(self): """Return the current operation mode.""" - return self._current_hvac_mode + return self._hvac_mode @property def hvac_modes(self): @@ -165,10 +164,10 @@ class BSBLanClimate(ClimateEntity): _LOGGER.debug("Setting preset mode to: %s", preset_mode) if preset_mode == PRESET_NONE: # restore previous hvac mode - self._current_hvac_mode = self._store_hvac_mode + self._hvac_mode = self._store_hvac_mode else: # Store hvac mode. - self._store_hvac_mode = self._current_hvac_mode + self._store_hvac_mode = self._hvac_mode await self.async_set_data(preset_mode=preset_mode) async def async_set_hvac_mode(self, hvac_mode): @@ -216,18 +215,18 @@ class BSBLanClimate(ClimateEntity): self._available = True - self._current_temperature = float(state.current_temperature) - self._target_temperature = float(state.target_temperature) + self._current_temperature = float(state.current_temperature.value) + self._target_temperature = float(state.target_temperature.value) # check if preset is active else get hvac mode - _LOGGER.debug("state hvac/preset mode: %s", state.current_hvac_mode) - if state.current_hvac_mode == "2": + _LOGGER.debug("state hvac/preset mode: %s", state.hvac_mode.value) + if state.hvac_mode.value == "2": self._preset_mode = PRESET_ECO else: - self._current_hvac_mode = BSBLAN_TO_HA_STATE[state.current_hvac_mode] + self._hvac_mode = BSBLAN_TO_HA_STATE[state.hvac_mode.value] self._preset_mode = PRESET_NONE - self._temperature_unit = state.temperature_unit + self._temperature_unit = state.current_temperature.unit @property def device_info(self) -> Dict[str, Any]: diff --git a/homeassistant/components/bsblan/config_flow.py b/homeassistant/components/bsblan/config_flow.py index e0e806ae205..faca81bb6a7 100644 --- a/homeassistant/components/bsblan/config_flow.py +++ b/homeassistant/components/bsblan/config_flow.py @@ -75,7 +75,5 @@ class BSBLanFlowHandler(ConfigFlow, domain=DOMAIN): """Get device information from an BSBLan device.""" session = async_get_clientsession(self.hass) _LOGGER.debug("request bsblan.info:") - bsblan = BSBLan( - host, passkey=passkey, port=port, session=session, loop=self.hass.loop - ) + bsblan = BSBLan(host, passkey=passkey, port=port, session=session) return await bsblan.info() diff --git a/homeassistant/components/bsblan/manifest.json b/homeassistant/components/bsblan/manifest.json index e396db57962..0348cf3eeb4 100644 --- a/homeassistant/components/bsblan/manifest.json +++ b/homeassistant/components/bsblan/manifest.json @@ -3,6 +3,6 @@ "name": "BSB-Lan", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/bsblan", - "requirements": ["bsblan==0.3.7"], + "requirements": ["bsblan==0.4.0"], "codeowners": ["@liudger"] } diff --git a/homeassistant/components/bsblan/strings.json b/homeassistant/components/bsblan/strings.json index 1003f75a4a3..d9510808fc1 100644 --- a/homeassistant/components/bsblan/strings.json +++ b/homeassistant/components/bsblan/strings.json @@ -1,5 +1,4 @@ { - "title": "BSB-Lan", "config": { "flow_title": "BSB-Lan: {name}", "step": { diff --git a/homeassistant/components/bsblan/translations/ca.json b/homeassistant/components/bsblan/translations/ca.json index 6096784c879..0cce690257d 100644 --- a/homeassistant/components/bsblan/translations/ca.json +++ b/homeassistant/components/bsblan/translations/ca.json @@ -4,8 +4,7 @@ "already_configured": "El dispositiu ja est\u00e0 configurat" }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar amb el dispositiu BSB-Lan." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "flow_title": "BSB-Lan: {name}", "step": { @@ -19,6 +18,5 @@ "title": "Connexi\u00f3 amb dispositiu BSB-Lan" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/cs.json b/homeassistant/components/bsblan/translations/cs.json index a29f842c49c..3df55116d19 100644 --- a/homeassistant/components/bsblan/translations/cs.json +++ b/homeassistant/components/bsblan/translations/cs.json @@ -4,8 +4,7 @@ "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed BSB-Lan se nezda\u0159ilo." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "flow_title": "BSB-Lan: {name}", "step": { @@ -17,6 +16,5 @@ "title": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed BSB-Lan" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/de.json b/homeassistant/components/bsblan/translations/de.json index 3d31a23d69d..39be96b84d5 100644 --- a/homeassistant/components/bsblan/translations/de.json +++ b/homeassistant/components/bsblan/translations/de.json @@ -11,6 +11,5 @@ } } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/en.json b/homeassistant/components/bsblan/translations/en.json index b8e3d0b5495..b0773c5bb5e 100644 --- a/homeassistant/components/bsblan/translations/en.json +++ b/homeassistant/components/bsblan/translations/en.json @@ -4,8 +4,7 @@ "already_configured": "Device is already configured" }, "error": { - "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect to BSB-Lan device." + "cannot_connect": "Failed to connect" }, "flow_title": "BSB-Lan: {name}", "step": { @@ -19,6 +18,5 @@ "title": "Connect to the BSB-Lan device" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/es-419.json b/homeassistant/components/bsblan/translations/es-419.json index 9793144e26b..b41be14a5d3 100644 --- a/homeassistant/components/bsblan/translations/es-419.json +++ b/homeassistant/components/bsblan/translations/es-419.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado" }, - "error": { - "connection_error": "No se pudo conectar al dispositivo BSB-Lan." - }, "flow_title": "BSB-Lan: {name}", "step": { "user": { @@ -18,6 +15,5 @@ "title": "Con\u00e9ctese al dispositivo BSB-Lan" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/es.json b/homeassistant/components/bsblan/translations/es.json index 319948ff5d1..287bd0fb49d 100644 --- a/homeassistant/components/bsblan/translations/es.json +++ b/homeassistant/components/bsblan/translations/es.json @@ -4,8 +4,7 @@ "already_configured": "El dispositivo ya est\u00e1 configurado" }, "error": { - "cannot_connect": "No se pudo conectar", - "connection_error": "No se ha podido conectar con el dispositivo BSB-Lan." + "cannot_connect": "No se pudo conectar" }, "flow_title": "BSB-Lan: {name}", "step": { @@ -19,6 +18,5 @@ "title": "Conectar con el dispositivo BSB-Lan" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/et.json b/homeassistant/components/bsblan/translations/et.json index 1c38cb46336..70f35535112 100644 --- a/homeassistant/components/bsblan/translations/et.json +++ b/homeassistant/components/bsblan/translations/et.json @@ -4,8 +4,7 @@ "already_configured": "Seade on juba h\u00e4\u00e4lestatud" }, "error": { - "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "BSB-Lan seadmega \u00fchenduse loomine nurjus." + "cannot_connect": "\u00dchendamine nurjus" }, "flow_title": "BSB-Lan: {name}", "step": { @@ -19,6 +18,5 @@ "title": "\u00dchendu BSB-Lan seadmega" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/fi.json b/homeassistant/components/bsblan/translations/fi.json index 1ab0cc17429..015fd1ccb00 100644 --- a/homeassistant/components/bsblan/translations/fi.json +++ b/homeassistant/components/bsblan/translations/fi.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Laite on jo m\u00e4\u00e4ritetty" }, - "error": { - "connection_error": "Yhteyden muodostaminen BSB-Lan-laitteeseen ep\u00e4onnistui." - }, "flow_title": "BSB-Lan: {name}", "step": { "user": { @@ -18,6 +15,5 @@ "title": "Yhdist\u00e4 BSB-Lan-laitteeseen" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/fr.json b/homeassistant/components/bsblan/translations/fr.json index 1b912eaa93b..d650d6596f7 100644 --- a/homeassistant/components/bsblan/translations/fr.json +++ b/homeassistant/components/bsblan/translations/fr.json @@ -4,8 +4,7 @@ "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" }, "error": { - "cannot_connect": "\u00c9chec de connexion", - "connection_error": "Impossible de se connecter \u00e0 l'appareil BSB-Lan." + "cannot_connect": "\u00c9chec de connexion" }, "flow_title": "BSB-Lan: {name}", "step": { @@ -19,6 +18,5 @@ "title": "Connectez-vous \u00e0 l'appareil BSB-Lan" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/it.json b/homeassistant/components/bsblan/translations/it.json index 2ff7f173d17..1f27531f769 100644 --- a/homeassistant/components/bsblan/translations/it.json +++ b/homeassistant/components/bsblan/translations/it.json @@ -4,8 +4,7 @@ "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato" }, "error": { - "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi al dispositivo BSB-Lan." + "cannot_connect": "Impossibile connettersi" }, "flow_title": "BSB-Lan: {name}", "step": { @@ -19,6 +18,5 @@ "title": "Collegamento al dispositivo BSB-Lan" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/ko.json b/homeassistant/components/bsblan/translations/ko.json index 7392edf62b3..41b421ff817 100644 --- a/homeassistant/components/bsblan/translations/ko.json +++ b/homeassistant/components/bsblan/translations/ko.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, - "error": { - "connection_error": "BSB-Lan \uae30\uae30\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." - }, "flow_title": "BSB-Lan: {name}", "step": { "user": { @@ -18,6 +15,5 @@ "title": "BSB-Lan \uae30\uae30\uc5d0 \uc5f0\uacb0\ud558\uae30" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/lb.json b/homeassistant/components/bsblan/translations/lb.json index ee8e54c7d24..56ace699cee 100644 --- a/homeassistant/components/bsblan/translations/lb.json +++ b/homeassistant/components/bsblan/translations/lb.json @@ -4,8 +4,7 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen mam BSB-Lan Apparat." + "cannot_connect": "Feeler beim verbannen" }, "flow_title": "BSB-LAN: {name}", "step": { @@ -19,6 +18,5 @@ "title": "Mam BSB-Lan Apparat verbannen" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/nl.json b/homeassistant/components/bsblan/translations/nl.json index a9f769389c5..850f942df2e 100644 --- a/homeassistant/components/bsblan/translations/nl.json +++ b/homeassistant/components/bsblan/translations/nl.json @@ -1,14 +1,21 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, "error": { "cannot_connect": "Kan geen verbinding maken" }, + "flow_title": "BSB-Lan: {name}", "step": { "user": { "data": { "host": "Host", + "passkey": "Passkey-tekenreeks", "port": "Poort" - } + }, + "description": "Stel uw BSB-Lan-apparaat in om te integreren met Home Assistant.", + "title": "Maak verbinding met het BSB-Lan-apparaat" } } } diff --git a/homeassistant/components/bsblan/translations/no.json b/homeassistant/components/bsblan/translations/no.json index 2661c1d1d0e..685f3afb1f4 100644 --- a/homeassistant/components/bsblan/translations/no.json +++ b/homeassistant/components/bsblan/translations/no.json @@ -4,8 +4,7 @@ "already_configured": "Enheten er allerede konfigurert" }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kunne ikke koble til BSB-Lan-enheten." + "cannot_connect": "Tilkobling mislyktes" }, "flow_title": "", "step": { @@ -19,6 +18,5 @@ "title": "Koble til BSB-Lan-enheten" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/pl.json b/homeassistant/components/bsblan/translations/pl.json index d4039c92f28..f95f2695883 100644 --- a/homeassistant/components/bsblan/translations/pl.json +++ b/homeassistant/components/bsblan/translations/pl.json @@ -4,8 +4,7 @@ "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z urz\u0105dzeniem BSB_LAN" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "flow_title": "BSB-Lan: {name}", "step": { @@ -19,6 +18,5 @@ "title": "Po\u0142\u0105czenie z urz\u0105dzeniem BSB-Lan" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/pt-BR.json b/homeassistant/components/bsblan/translations/pt-BR.json index 2b5e083220d..3f8701092d1 100644 --- a/homeassistant/components/bsblan/translations/pt-BR.json +++ b/homeassistant/components/bsblan/translations/pt-BR.json @@ -6,6 +6,5 @@ "title": "Conecte-se ao dispositivo BSB-Lan" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/ru.json b/homeassistant/components/bsblan/translations/ru.json index 3d4009abb7b..7d7bcb9fa0e 100644 --- a/homeassistant/components/bsblan/translations/ru.json +++ b/homeassistant/components/bsblan/translations/ru.json @@ -4,8 +4,7 @@ "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "flow_title": "BSB-Lan: {name}", "step": { @@ -19,6 +18,5 @@ "title": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/bsblan/translations/zh-Hant.json b/homeassistant/components/bsblan/translations/zh-Hant.json index 81de5bf5365..3d3bcb44ac7 100644 --- a/homeassistant/components/bsblan/translations/zh-Hant.json +++ b/homeassistant/components/bsblan/translations/zh-Hant.json @@ -4,8 +4,7 @@ "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "BSB-Lan \u8a2d\u5099\u9023\u7dda\u5931\u6557\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "flow_title": "BSB-Lan\uff1a{name}", "step": { @@ -19,6 +18,5 @@ "title": "\u9023\u7dda\u81f3 BSB-Lan \u8a2d\u5099" } } - }, - "title": "BSB-Lan" + } } \ No newline at end of file diff --git a/homeassistant/components/buienradar/sensor.py b/homeassistant/components/buienradar/sensor.py index b1e41122dc0..4e35542b581 100644 --- a/homeassistant/components/buienradar/sensor.py +++ b/homeassistant/components/buienradar/sensor.py @@ -32,10 +32,10 @@ from homeassistant.const import ( LENGTH_KILOMETERS, LENGTH_MILLIMETERS, PERCENTAGE, + PRECIPITATION_MILLIMETERS_PER_HOUR, PRESSURE_HPA, SPEED_KILOMETERS_PER_HOUR, TEMP_CELSIUS, - TIME_HOURS, ) from homeassistant.core import callback import homeassistant.helpers.config_validation as cv @@ -85,13 +85,13 @@ SENSOR_TYPES = { "windgust": ["Wind gust", SPEED_KILOMETERS_PER_HOUR, "mdi:weather-windy"], "precipitation": [ "Precipitation", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", + PRECIPITATION_MILLIMETERS_PER_HOUR, "mdi:weather-pouring", ], "irradiance": ["Irradiance", IRRADIATION_WATTS_PER_SQUARE_METER, "mdi:sunglasses"], "precipitation_forecast_average": [ "Precipitation forecast average", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", + PRECIPITATION_MILLIMETERS_PER_HOUR, "mdi:weather-pouring", ], "precipitation_forecast_total": [ diff --git a/homeassistant/components/camera/translations/pl.json b/homeassistant/components/camera/translations/pl.json index e7922e118df..bb668c6e6ea 100644 --- a/homeassistant/components/camera/translations/pl.json +++ b/homeassistant/components/camera/translations/pl.json @@ -1,7 +1,7 @@ { "state": { "_": { - "idle": "nieaktywna", + "idle": "bezczynno\u015b\u0107", "recording": "nagrywanie", "streaming": "strumieniowanie" } diff --git a/homeassistant/components/camera/translations/tr.json b/homeassistant/components/camera/translations/tr.json index 313eaeb887b..001fe174386 100644 --- a/homeassistant/components/camera/translations/tr.json +++ b/homeassistant/components/camera/translations/tr.json @@ -3,7 +3,7 @@ "_": { "idle": "Bo\u015fta", "recording": "Kaydediliyor", - "streaming": "Yay\u0131n ak\u0131\u015f\u0131" + "streaming": "Yay\u0131nlan\u0131yor" } }, "title": "Kamera" diff --git a/homeassistant/components/canary/translations/cs.json b/homeassistant/components/canary/translations/cs.json index 5b883f253be..1cc46650531 100644 --- a/homeassistant/components/canary/translations/cs.json +++ b/homeassistant/components/canary/translations/cs.json @@ -22,6 +22,7 @@ "step": { "init": { "data": { + "ffmpeg_arguments": "Argumenty p\u0159edan\u00e9 ffmpeg pro kamery", "timeout": "\u010casov\u00fd limit po\u017eadavku (v sekund\u00e1ch)" } } diff --git a/homeassistant/components/cast/config_flow.py b/homeassistant/components/cast/config_flow.py index 80d4abc9796..e00048a7589 100644 --- a/homeassistant/components/cast/config_flow.py +++ b/homeassistant/components/cast/config_flow.py @@ -4,6 +4,7 @@ import functools from pychromecast.discovery import discover_chromecasts, stop_discovery from homeassistant import config_entries +from homeassistant.components import zeroconf from homeassistant.helpers import config_entry_flow from .const import DOMAIN @@ -11,12 +12,19 @@ from .helpers import ChromeCastZeroconf async def _async_has_devices(hass): - """Return if there are devices that can be discovered.""" + """ + Return if there are devices that can be discovered. + + This function will be called if no devices are already found through the zeroconf + integration. + """ + + zeroconf_instance = ChromeCastZeroconf.get_zeroconf() + if zeroconf_instance is None: + zeroconf_instance = await zeroconf.async_get_instance(hass) casts, browser = await hass.async_add_executor_job( - functools.partial( - discover_chromecasts, zeroconf_instance=ChromeCastZeroconf.get_zeroconf() - ) + functools.partial(discover_chromecasts, zeroconf_instance=zeroconf_instance) ) stop_discovery(browser) return casts diff --git a/homeassistant/components/cast/translations/lb.json b/homeassistant/components/cast/translations/lb.json index 813ffd10072..bf4bc68b5ad 100644 --- a/homeassistant/components/cast/translations/lb.json +++ b/homeassistant/components/cast/translations/lb.json @@ -1,12 +1,12 @@ { "config": { "abort": { - "no_devices_found": "Keng Google Cast Apparater am Netzwierk fonnt.", - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun Google Cast ass n\u00e9ideg." + "no_devices_found": "Keng Apparater am Netzwierk fonnt.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "confirm": { - "description": "Soll Google Cast konfigur\u00e9iert ginn?" + "description": "Soll den Ariichtungs Prozess gestart ginn?" } } } diff --git a/homeassistant/components/cert_expiry/translations/cs.json b/homeassistant/components/cert_expiry/translations/cs.json index 61bd93f40b3..c4b61df7084 100644 --- a/homeassistant/components/cert_expiry/translations/cs.json +++ b/homeassistant/components/cert_expiry/translations/cs.json @@ -17,5 +17,6 @@ } } } - } + }, + "title": "Platnost certifik\u00e1tu" } \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/translations/lb.json b/homeassistant/components/cert_expiry/translations/lb.json index 679220898cc..9f0496ddcb7 100644 --- a/homeassistant/components/cert_expiry/translations/lb.json +++ b/homeassistant/components/cert_expiry/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "D\u00ebs Kombinatioun vun Host an Port sinn scho konfigur\u00e9iert", + "already_configured": "Service ass scho konfigur\u00e9iert", "import_failed": "Import vun der Konfiguratioun feelgeschloen" }, "error": { diff --git a/homeassistant/components/climate/translations/pl.json b/homeassistant/components/climate/translations/pl.json index 885938c2562..ceebac3851c 100644 --- a/homeassistant/components/climate/translations/pl.json +++ b/homeassistant/components/climate/translations/pl.json @@ -22,7 +22,7 @@ "fan_only": "tylko wentylator", "heat": "grzanie", "heat_cool": "grzanie/ch\u0142odzenie", - "off": "wy\u0142\u0105czony" + "off": "wy\u0142." } }, "title": "Klimat" diff --git a/homeassistant/components/climate/translations/ru.json b/homeassistant/components/climate/translations/ru.json index 3cc2cc37a5c..3e4ff1844d6 100644 --- a/homeassistant/components/climate/translations/ru.json +++ b/homeassistant/components/climate/translations/ru.json @@ -1,12 +1,12 @@ { "device_automation": { "action_type": { - "set_hvac_mode": "{entity_name}: \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c HVAC", - "set_preset_mode": "{entity_name}: \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c" + "set_hvac_mode": "{entity_name}: \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u044b", + "set_preset_mode": "{entity_name}: \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443" }, "condition_type": { "is_hvac_mode": "{entity_name} \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0431\u043e\u0442\u044b", - "is_preset_mode": "{entity_name} \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u043f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a" + "is_preset_mode": "{entity_name} \u0432 \u043f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435" }, "trigger_type": { "current_humidity_changed": "{entity_name} \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u043d\u043e\u0439 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438", diff --git a/homeassistant/components/climate/translations/tr.json b/homeassistant/components/climate/translations/tr.json index bfac4a6e7c6..0b027dbd87f 100644 --- a/homeassistant/components/climate/translations/tr.json +++ b/homeassistant/components/climate/translations/tr.json @@ -2,10 +2,10 @@ "state": { "_": { "auto": "Otomatik", - "cool": "Serin", - "dry": "Kuru", + "cool": "So\u011futma", + "dry": "Nem alma", "fan_only": "Sadece fan", - "heat": "S\u0131cak", + "heat": "Is\u0131tma", "heat_cool": "Is\u0131tma / So\u011futma", "off": "Kapal\u0131" } diff --git a/homeassistant/components/cloud/client.py b/homeassistant/components/cloud/client.py index 8e309d92c7f..2a2d383f362 100644 --- a/homeassistant/components/cloud/client.py +++ b/homeassistant/components/cloud/client.py @@ -1,5 +1,6 @@ """Interface implementation for cloud client.""" import asyncio +import logging from pathlib import Path from typing import Any, Dict @@ -14,6 +15,7 @@ from homeassistant.components.google_assistant import const as gc, smart_home as from homeassistant.const import HTTP_OK from homeassistant.core import Context, callback from homeassistant.helpers.dispatcher import async_dispatcher_send +from homeassistant.helpers.event import async_call_later from homeassistant.helpers.typing import HomeAssistantType from homeassistant.util.aiohttp import MockRequest @@ -106,13 +108,22 @@ class CloudClient(Interface): """When user logs in.""" await self.prefs.async_set_username(self.cloud.username) - if self.alexa_config.enabled and self.alexa_config.should_report_state: + async def enable_alexa(_): + """Enable Alexa.""" try: await self.alexa_config.async_enable_proactive_mode() + except aiohttp.ClientError as err: # If no internet available yet + if self._hass.is_running: + logging.getLogger(__package__).warning( + "Unable to activate Alexa Report State: %s. Retrying in 30 seconds", + err, + ) + async_call_later(self._hass, 30, enable_alexa) except alexa_errors.NoTokenAvailable: pass - if self._prefs.google_enabled: + async def enable_google(_): + """Enable Google.""" gconf = await self.get_google_config() gconf.async_enable_local_sdk() @@ -120,6 +131,17 @@ class CloudClient(Interface): if gconf.should_report_state: gconf.async_enable_report_state() + tasks = [] + + if self.alexa_config.enabled and self.alexa_config.should_report_state: + tasks.append(enable_alexa) + + if self._prefs.google_enabled: + tasks.append(enable_google) + + if tasks: + await asyncio.gather(*[task(None) for task in tasks]) + async def cleanups(self) -> None: """Cleanup some stuff after logout.""" await self.prefs.async_set_username(None) diff --git a/homeassistant/components/cloud/manifest.json b/homeassistant/components/cloud/manifest.json index 81986a3cf6d..f3c79a470ea 100644 --- a/homeassistant/components/cloud/manifest.json +++ b/homeassistant/components/cloud/manifest.json @@ -2,7 +2,7 @@ "domain": "cloud", "name": "Home Assistant Cloud", "documentation": "https://www.home-assistant.io/integrations/cloud", - "requirements": ["hass-nabucasa==0.37.1"], + "requirements": ["hass-nabucasa==0.37.2"], "dependencies": ["http", "webhook", "alexa"], "after_dependencies": ["google_assistant"], "codeowners": ["@home-assistant/cloud"] diff --git a/homeassistant/components/cloud/strings.json b/homeassistant/components/cloud/strings.json new file mode 100644 index 00000000000..357575c7bd0 --- /dev/null +++ b/homeassistant/components/cloud/strings.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "can_reach_cert_server": "Reach Certificate Server", + "can_reach_cloud": "Reach Home Assistant Cloud", + "can_reach_cloud_auth": "Reach Authentication Server", + "relayer_connected": "Relayer Connected", + "remote_connected": "Remote Connected", + "remote_enabled": "Remote Enabled", + "alexa_enabled": "Alexa Enabled", + "google_enabled": "Google Enabled", + "logged_in": "Logged In", + "subscription_expiration": "Subscription Expiration" + } + } +} diff --git a/homeassistant/components/cloud/system_health.py b/homeassistant/components/cloud/system_health.py new file mode 100644 index 00000000000..6d700c4fb8e --- /dev/null +++ b/homeassistant/components/cloud/system_health.py @@ -0,0 +1,48 @@ +"""Provide info to system health.""" +from hass_nabucasa import Cloud +from yarl import URL + +from homeassistant.components import system_health +from homeassistant.core import HomeAssistant, callback + +from .client import CloudClient +from .const import DOMAIN + + +@callback +def async_register( + hass: HomeAssistant, register: system_health.SystemHealthRegistration +) -> None: + """Register system health callbacks.""" + register.async_register_info(system_health_info, "/config/cloud") + + +async def system_health_info(hass): + """Get info for the info page.""" + cloud: Cloud = hass.data[DOMAIN] + client: CloudClient = cloud.client + + data = { + "logged_in": cloud.is_logged_in, + } + + if cloud.is_logged_in: + data["subscription_expiration"] = cloud.expiration_date + data["relayer_connected"] = cloud.is_connected + data["remote_enabled"] = client.prefs.remote_enabled + data["remote_connected"] = cloud.remote.is_connected + data["alexa_enabled"] = client.prefs.alexa_enabled + data["google_enabled"] = client.prefs.google_enabled + + data["can_reach_cert_server"] = system_health.async_check_can_reach_url( + hass, cloud.acme_directory_server + ) + data["can_reach_cloud_auth"] = system_health.async_check_can_reach_url( + hass, + f"https://cognito-idp.{cloud.region}.amazonaws.com/{cloud.user_pool_id}/.well-known/jwks.json", + ) + data["can_reach_cloud"] = system_health.async_check_can_reach_url( + hass, URL(cloud.relayer).with_scheme("https").with_path("/status") + ) + + return data diff --git a/homeassistant/components/cloud/translations/ca.json b/homeassistant/components/cloud/translations/ca.json new file mode 100644 index 00000000000..fede749c7dd --- /dev/null +++ b/homeassistant/components/cloud/translations/ca.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa activada", + "can_reach_cert_server": "Servidor de certificaci\u00f3 accessible", + "can_reach_cloud": "Home Assistant Cloud accessible", + "can_reach_cloud_auth": "Servidor d'autenticaci\u00f3 accessible", + "google_enabled": "Google activat", + "logged_in": "Sessi\u00f3 iniciada", + "relayer_connected": "Encaminador connectat", + "remote_connected": "Connexi\u00f3 remota establerta", + "remote_enabled": "Connexi\u00f3 remota activada", + "subscription_expiration": "Caducitat de la subscripci\u00f3" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/cs.json b/homeassistant/components/cloud/translations/cs.json new file mode 100644 index 00000000000..e6cf308e370 --- /dev/null +++ b/homeassistant/components/cloud/translations/cs.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa povolena", + "can_reach_cert_server": "Certifika\u010dn\u00ed server dosa\u017een", + "can_reach_cloud": "Home Assistant Cloud dosa\u017een", + "can_reach_cloud_auth": "Ov\u011b\u0159ovac\u00ed server dosa\u017een", + "google_enabled": "Google povolen", + "logged_in": "P\u0159ihl\u00e1\u0161en", + "relayer_connected": "Relayer p\u0159ipojen", + "remote_connected": "Vzd\u00e1len\u00e1 spr\u00e1va p\u0159ipojena", + "remote_enabled": "Vzd\u00e1len\u00e1 spr\u00e1va povolena", + "subscription_expiration": "Platnost p\u0159edplatn\u00e9ho" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/en.json b/homeassistant/components/cloud/translations/en.json new file mode 100644 index 00000000000..34af1f57cfa --- /dev/null +++ b/homeassistant/components/cloud/translations/en.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa Enabled", + "can_reach_cert_server": "Reach Certificate Server", + "can_reach_cloud": "Reach Home Assistant Cloud", + "can_reach_cloud_auth": "Reach Authentication Server", + "google_enabled": "Google Enabled", + "logged_in": "Logged In", + "relayer_connected": "Relayer Connected", + "remote_connected": "Remote Connected", + "remote_enabled": "Remote Enabled", + "subscription_expiration": "Subscription Expiration" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/es.json b/homeassistant/components/cloud/translations/es.json new file mode 100644 index 00000000000..de05ccf527a --- /dev/null +++ b/homeassistant/components/cloud/translations/es.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa habilitada", + "can_reach_cert_server": "Servidor de Certificados accesible", + "can_reach_cloud": "Home Assistant Cloud accesible", + "can_reach_cloud_auth": "Servidor de Autenticaci\u00f3n accesible", + "google_enabled": "Google habilitado", + "logged_in": "Iniciada sesi\u00f3n", + "relayer_connected": "Relayer conectado", + "remote_connected": "Remoto conectado", + "remote_enabled": "Remoto habilitado", + "subscription_expiration": "Caducidad de la suscripci\u00f3n" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/et.json b/homeassistant/components/cloud/translations/et.json new file mode 100644 index 00000000000..07e7748e133 --- /dev/null +++ b/homeassistant/components/cloud/translations/et.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa on lubatud", + "can_reach_cert_server": "\u00dchendu serdiserveriga", + "can_reach_cloud": "\u00dchendu Home Assistant Cloudiga", + "can_reach_cloud_auth": "\u00dchendu tuvastusserveriga", + "google_enabled": "Google on lubatud", + "logged_in": "Sisse logitud", + "relayer_connected": "Edastaja on \u00fchendatud", + "remote_connected": "Kaug\u00fchendus on loodud", + "remote_enabled": "Kaug\u00fchendus on lubatud", + "subscription_expiration": "Tellimuse aegumine" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/it.json b/homeassistant/components/cloud/translations/it.json new file mode 100644 index 00000000000..320ca70b810 --- /dev/null +++ b/homeassistant/components/cloud/translations/it.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa abilitato", + "can_reach_cert_server": "Raggiungi il server dei certificati", + "can_reach_cloud": "Raggiungi Home Assistant Cloud", + "can_reach_cloud_auth": "Raggiungi il server di autenticazione", + "google_enabled": "Google abilitato", + "logged_in": "Accesso effettuato", + "relayer_connected": "Relayer connesso", + "remote_connected": "Connesso in remoto", + "remote_enabled": "Remoto abilitato", + "subscription_expiration": "Scadenza abbonamento" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/lb.json b/homeassistant/components/cloud/translations/lb.json new file mode 100644 index 00000000000..3806c2d6ebe --- /dev/null +++ b/homeassistant/components/cloud/translations/lb.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa aktiv\u00e9iert", + "can_reach_cert_server": "Zertifikat Server ereechbar", + "can_reach_cloud": "Home Assistant Cloud ereechbar", + "can_reach_cloud_auth": "Authentifikatioun Server ereechbar", + "google_enabled": "Google aktiv\u00e9iert", + "logged_in": "Ageloggt", + "relayer_connected": "Relayer verbonnen", + "remote_connected": "Remote verbonnen", + "remote_enabled": "Remote aktiv\u00e9iert", + "subscription_expiration": "Abonnement Verfallsdatum" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/no.json b/homeassistant/components/cloud/translations/no.json new file mode 100644 index 00000000000..585811f0eb4 --- /dev/null +++ b/homeassistant/components/cloud/translations/no.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa aktivert", + "can_reach_cert_server": "N\u00e5 sertifikatserver", + "can_reach_cloud": "N\u00e5 Home Assistant Cloud", + "can_reach_cloud_auth": "N\u00e5 autentiseringsserver", + "google_enabled": "Google aktivert", + "logged_in": "Logget inn", + "relayer_connected": "Relayer tilkoblet", + "remote_connected": "Ekstern tilkobling", + "remote_enabled": "Ekstern aktivert", + "subscription_expiration": "Abonnementets utl\u00f8p" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/pl.json b/homeassistant/components/cloud/translations/pl.json new file mode 100644 index 00000000000..30aaeeb77d1 --- /dev/null +++ b/homeassistant/components/cloud/translations/pl.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa w\u0142\u0105czona", + "can_reach_cert_server": "Dost\u0119p do serwera certyfikat\u00f3w", + "can_reach_cloud": "Dost\u0119p do chmury Home Assistant", + "can_reach_cloud_auth": "Dost\u0119p do serwera uwierzytelniania", + "google_enabled": "Asystent Google w\u0142\u0105czony", + "logged_in": "Zalogowany", + "relayer_connected": "Relayer pod\u0142\u0105czony", + "remote_connected": "Zdalny dost\u0119p pod\u0142\u0105czony", + "remote_enabled": "Zdalny dost\u0119p w\u0142\u0105czony", + "subscription_expiration": "Wyga\u015bni\u0119cie subskrypcji" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/pt.json b/homeassistant/components/cloud/translations/pt.json new file mode 100644 index 00000000000..b1316213baf --- /dev/null +++ b/homeassistant/components/cloud/translations/pt.json @@ -0,0 +1,12 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa ativa", + "google_enabled": "Google ativo", + "logged_in": "Ligado em", + "remote_connected": "Ligado remotamente", + "remote_enabled": "Remoto ativo", + "subscription_expiration": "Validade da Subscri\u00e7\u00e3o" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/ru.json b/homeassistant/components/cloud/translations/ru.json new file mode 100644 index 00000000000..b66e2ca51fa --- /dev/null +++ b/homeassistant/components/cloud/translations/ru.json @@ -0,0 +1,13 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 Alexa", + "can_reach_cert_server": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432", + "can_reach_cloud": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a Home Assistant Cloud", + "can_reach_cloud_auth": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438", + "google_enabled": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 Google", + "logged_in": "\u0412\u0445\u043e\u0434 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443", + "subscription_expiration": "\u0421\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloud/translations/zh-Hant.json b/homeassistant/components/cloud/translations/zh-Hant.json new file mode 100644 index 00000000000..8b97fd51a03 --- /dev/null +++ b/homeassistant/components/cloud/translations/zh-Hant.json @@ -0,0 +1,16 @@ +{ + "system_health": { + "info": { + "alexa_enabled": "Alexa \u5df2\u555f\u7528", + "can_reach_cert_server": "\u9023\u7dda\u9a57\u8b49\u4f3a\u670d\u5668", + "can_reach_cloud": "\u9023\u7dda Home Assistant Cloud", + "can_reach_cloud_auth": "\u9023\u7dda\u8a8d\u8b49\u4f3a\u670d\u5668", + "google_enabled": "Google \u5df2\u555f\u7528", + "logged_in": "\u5df2\u767b\u5165", + "relayer_connected": "\u4e2d\u7e7c\u5df2\u9023\u7dda", + "remote_connected": "\u9060\u7aef\u63a7\u5236\u5df2\u9023\u7dda", + "remote_enabled": "\u9060\u7aef\u63a7\u5236\u5df2\u555f\u7528", + "subscription_expiration": "\u8a02\u95b1\u5230\u671f" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloudflare/translations/cs.json b/homeassistant/components/cloudflare/translations/cs.json index d618c25c4f0..e20f26236be 100644 --- a/homeassistant/components/cloudflare/translations/cs.json +++ b/homeassistant/components/cloudflare/translations/cs.json @@ -21,6 +21,7 @@ "data": { "api_token": "API token" }, + "description": "Tato integrace vy\u017eaduje API token vytvo\u0159en\u00fd s opravn\u011bn\u00edmi Z\u00f3na:Z\u00f3na:\u010c\u00edst a Z\u00f3na:DNS: Upravit pro v\u0161echny z\u00f3ny ve va\u0161em \u00fa\u010dtu.", "title": "P\u0159ipojen\u00ed ke Cloudflare" }, "zone": { diff --git a/homeassistant/components/cloudflare/translations/de.json b/homeassistant/components/cloudflare/translations/de.json new file mode 100644 index 00000000000..68b18568156 --- /dev/null +++ b/homeassistant/components/cloudflare/translations/de.json @@ -0,0 +1,21 @@ +{ + "config": { + "error": { + "cannot_connect": "Verbindung fehlgeschlagen", + "invalid_zone": "Ung\u00fcltige Zone" + }, + "step": { + "records": { + "data": { + "records": "Datens\u00e4tze" + } + }, + "user": { + "data": { + "api_token": "API Token" + }, + "title": "Mit Cloudflare verbinden" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloudflare/translations/es.json b/homeassistant/components/cloudflare/translations/es.json new file mode 100644 index 00000000000..7f9fdc15dfb --- /dev/null +++ b/homeassistant/components/cloudflare/translations/es.json @@ -0,0 +1,35 @@ +{ + "config": { + "abort": { + "single_instance_allowed": "Ya configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "unknown": "Error inesperado" + }, + "error": { + "cannot_connect": "No se pudo conectar", + "invalid_auth": "Autenticaci\u00f3n inv\u00e1lida", + "invalid_zone": "Zona no v\u00e1lida" + }, + "flow_title": "Cloudflare: {name}", + "step": { + "records": { + "data": { + "records": "Registros" + }, + "title": "Elija los registros que desea actualizar" + }, + "user": { + "data": { + "api_token": "Token de la API" + }, + "description": "Esta integraci\u00f3n requiere un token de API creado con los permisos Zone:Zone:Read y Zone:DNS:Edit para todas las zonas de su cuenta.", + "title": "Conectar con Cloudflare" + }, + "zone": { + "data": { + "zone": "Zona" + }, + "title": "Elija la zona para actualizar" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloudflare/translations/et.json b/homeassistant/components/cloudflare/translations/et.json index 9c9ab666a83..1f4d91c71d7 100644 --- a/homeassistant/components/cloudflare/translations/et.json +++ b/homeassistant/components/cloudflare/translations/et.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", "unknown": "Tundmatu viga" }, "error": { diff --git a/homeassistant/components/cloudflare/translations/fr.json b/homeassistant/components/cloudflare/translations/fr.json new file mode 100644 index 00000000000..be6d4c3e2b3 --- /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/cloudflare/translations/it.json b/homeassistant/components/cloudflare/translations/it.json new file mode 100644 index 00000000000..48d9acc0861 --- /dev/null +++ b/homeassistant/components/cloudflare/translations/it.json @@ -0,0 +1,35 @@ +{ + "config": { + "abort": { + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "unknown": "Errore imprevisto" + }, + "error": { + "cannot_connect": "Impossibile connettersi", + "invalid_auth": "Autenticazione non valida", + "invalid_zone": "Zona non valida" + }, + "flow_title": "Cloudflare: {name}", + "step": { + "records": { + "data": { + "records": "Record" + }, + "title": "Scegliere i record da aggiornare" + }, + "user": { + "data": { + "api_token": "Token API" + }, + "description": "Questa integrazione richiede un Token API creato con i permessi Zone:Zone:Read e Zone:DNS:Edit per tutte le zone del tuo account.", + "title": "Connettiti a Cloudflare" + }, + "zone": { + "data": { + "zone": "Zona" + }, + "title": "Scegliere la zona da aggiornare" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloudflare/translations/lb.json b/homeassistant/components/cloudflare/translations/lb.json new file mode 100644 index 00000000000..753406d8d92 --- /dev/null +++ b/homeassistant/components/cloudflare/translations/lb.json @@ -0,0 +1,27 @@ +{ + "config": { + "abort": { + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech.", + "unknown": "Onerwaarte Feeler" + }, + "error": { + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", + "invalid_zone": "Ong\u00eblteg Zon" + }, + "flow_title": "Cloudflare: {name}", + "step": { + "user": { + "data": { + "api_token": "API Jeton" + }, + "title": "Mat Cloudflare verbannen" + }, + "zone": { + "data": { + "zone": "Zon" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloudflare/translations/nl.json b/homeassistant/components/cloudflare/translations/nl.json new file mode 100644 index 00000000000..37162761d86 --- /dev/null +++ b/homeassistant/components/cloudflare/translations/nl.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "invalid_auth": "Ongeldige authenticatie" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloudflare/translations/no.json b/homeassistant/components/cloudflare/translations/no.json new file mode 100644 index 00000000000..33e4ca61f78 --- /dev/null +++ b/homeassistant/components/cloudflare/translations/no.json @@ -0,0 +1,35 @@ +{ + "config": { + "abort": { + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "unknown": "Uventet feil" + }, + "error": { + "cannot_connect": "Tilkobling mislyktes", + "invalid_auth": "Ugyldig godkjenning", + "invalid_zone": "Ugyldig sone" + }, + "flow_title": "Cloudflare: {name}", + "step": { + "records": { + "data": { + "records": "Poster" + }, + "title": "Velg postene du vil oppdatere" + }, + "user": { + "data": { + "api_token": "API-token" + }, + "description": "Denne integreringen krever et API-token som er opprettet med Zone:Zone:Read og Zone:DNS:Edit-tillatelser for alle soner i kontoen din", + "title": "Koble til Cloudflare" + }, + "zone": { + "data": { + "zone": "Sone" + }, + "title": "Velg sonen du vil oppdatere" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cloudflare/translations/zh-Hans.json b/homeassistant/components/cloudflare/translations/zh-Hans.json new file mode 100644 index 00000000000..4b0a696e5fc --- /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/cloudflare/translations/zh-Hant.json b/homeassistant/components/cloudflare/translations/zh-Hant.json new file mode 100644 index 00000000000..e84966b8d53 --- /dev/null +++ b/homeassistant/components/cloudflare/translations/zh-Hant.json @@ -0,0 +1,35 @@ +{ + "config": { + "abort": { + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "unknown": "\u672a\u9810\u671f\u932f\u8aa4" + }, + "error": { + "cannot_connect": "\u9023\u7dda\u5931\u6557", + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", + "invalid_zone": "\u5340\u57df\u7121\u6548" + }, + "flow_title": "Cloudflare\uff1a{name}", + "step": { + "records": { + "data": { + "records": "\u8a18\u9304" + }, + "title": "\u9078\u64c7\u6240\u8981\u66f4\u65b0\u7684\u7d00\u9304" + }, + "user": { + "data": { + "api_token": "API \u5bc6\u9470" + }, + "description": "\u6b64\u6574\u5408\u9700\u8981\u5e33\u865f\u4e2d\u6240\u6709\u5340\u57df Zone:Zone:Read \u8207 Zone:DNS:Edit \u6b0a\u9650 API \u5bc6\u9470\u3002", + "title": "\u9023\u7dda\u81f3 Cloudflare" + }, + "zone": { + "data": { + "zone": "\u5340\u57df" + }, + "title": "\u9078\u64c7\u6240\u8981\u66f4\u65b0\u7684\u5340\u57df" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/color_extractor/__init__.py b/homeassistant/components/color_extractor/__init__.py new file mode 100644 index 00000000000..ddd2ae967e4 --- /dev/null +++ b/homeassistant/components/color_extractor/__init__.py @@ -0,0 +1,149 @@ +"""Module for color_extractor (RGB extraction from images) component.""" +import asyncio +import io +import logging + +from PIL import UnidentifiedImageError +import aiohttp +import async_timeout +from colorthief import ColorThief +import voluptuous as vol + +from homeassistant.components.color_extractor.const import ( + ATTR_PATH, + ATTR_URL, + DOMAIN, + SERVICE_TURN_ON, +) +from homeassistant.components.light import ( + ATTR_RGB_COLOR, + DOMAIN as LIGHT_DOMAIN, + LIGHT_TURN_ON_SCHEMA, + SERVICE_TURN_ON as LIGHT_SERVICE_TURN_ON, +) +from homeassistant.helpers import aiohttp_client +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +# Extend the existing light.turn_on service schema +SERVICE_SCHEMA = vol.All( + cv.has_at_least_one_key(ATTR_URL, ATTR_PATH), + cv.make_entity_service_schema( + { + **LIGHT_TURN_ON_SCHEMA, + vol.Exclusive(ATTR_PATH, "color_extractor"): cv.isfile, + vol.Exclusive(ATTR_URL, "color_extractor"): cv.url, + } + ), +) + + +def _get_file(file_path): + """Get a PIL acceptable input file reference. + + Allows us to mock patch during testing to make BytesIO stream. + """ + return file_path + + +def _get_color(file_handler) -> tuple: + """Given an image file, extract the predominant color from it.""" + color_thief = ColorThief(file_handler) + + # get_color returns a SINGLE RGB value for the given image + color = color_thief.get_color(quality=1) + + _LOGGER.debug("Extracted RGB color %s from image", color) + + return color + + +async def async_setup(hass, hass_config): + """Set up services for color_extractor integration.""" + + async def async_handle_service(service_call): + """Decide which color_extractor method to call based on service.""" + service_data = dict(service_call.data) + + try: + if ATTR_URL in service_data: + image_type = "URL" + image_reference = service_data.pop(ATTR_URL) + color = await async_extract_color_from_url(image_reference) + + elif ATTR_PATH in service_data: + image_type = "file path" + image_reference = service_data.pop(ATTR_PATH) + color = await hass.async_add_executor_job( + extract_color_from_path, image_reference + ) + + except UnidentifiedImageError as ex: + _LOGGER.error( + "Bad image from %s '%s' provided, are you sure it's an image? %s", + image_type, + image_reference, + ex, + ) + return + + if color: + service_data[ATTR_RGB_COLOR] = color + + await hass.services.async_call( + LIGHT_DOMAIN, LIGHT_SERVICE_TURN_ON, service_data, blocking=True + ) + + hass.services.async_register( + DOMAIN, + SERVICE_TURN_ON, + async_handle_service, + schema=SERVICE_SCHEMA, + ) + + async def async_extract_color_from_url(url): + """Handle call for URL based image.""" + if not hass.config.is_allowed_external_url(url): + _LOGGER.error( + "External URL '%s' is not allowed, please add to 'allowlist_external_urls'", + url, + ) + return None + + _LOGGER.debug("Getting predominant RGB from image URL '%s'", url) + + # Download the image into a buffer for ColorThief to check against + try: + session = aiohttp_client.async_get_clientsession(hass) + + with async_timeout.timeout(10): + response = await session.get(url) + + except (asyncio.TimeoutError, aiohttp.ClientError) as err: + _LOGGER.error("Failed to get ColorThief image due to HTTPError: %s", err) + return None + + content = await response.content.read() + + with io.BytesIO(content) as _file: + _file.name = "color_extractor.jpg" + _file.seek(0) + + return _get_color(_file) + + def extract_color_from_path(file_path): + """Handle call for local file based image.""" + if not hass.config.is_allowed_path(file_path): + _LOGGER.error( + "File path '%s' is not allowed, please add to 'allowlist_external_dirs'", + file_path, + ) + return None + + _LOGGER.debug("Getting predominant RGB from file path '%s'", file_path) + + _file = _get_file(file_path) + return _get_color(_file) + + return True diff --git a/homeassistant/components/color_extractor/const.py b/homeassistant/components/color_extractor/const.py new file mode 100644 index 00000000000..a6c59ea434b --- /dev/null +++ b/homeassistant/components/color_extractor/const.py @@ -0,0 +1,7 @@ +"""Constants for the color_extractor component.""" +ATTR_PATH = "color_extract_path" +ATTR_URL = "color_extract_url" + +DOMAIN = "color_extractor" + +SERVICE_TURN_ON = "turn_on" diff --git a/homeassistant/components/color_extractor/manifest.json b/homeassistant/components/color_extractor/manifest.json new file mode 100644 index 00000000000..7ffdad3660b --- /dev/null +++ b/homeassistant/components/color_extractor/manifest.json @@ -0,0 +1,9 @@ +{ + "domain": "color_extractor", + "name": "ColorExtractor", + "config_flow": false, + "documentation": "https://www.home-assistant.io/integrations/color_extractor", + "requirements": ["colorthief==0.2.1"], + "codeowners": ["@GenericStudent"] + } + \ No newline at end of file diff --git a/homeassistant/components/color_extractor/services.yaml b/homeassistant/components/color_extractor/services.yaml new file mode 100644 index 00000000000..fa97dacf3d1 --- /dev/null +++ b/homeassistant/components/color_extractor/services.yaml @@ -0,0 +1,12 @@ +turn_on: + description: Set the light RGB to the predominant color found in the image provided by url or file path. + fields: + color_extract_url: + description: The URL of the image we want to extract RGB values from. Must be allowed in allowlist_external_urls. + example: https://www.example.com/images/logo.png + color_extract_path: + description: The full system path to the image we want to extract RGB values from. Must be allowed in allowlist_external_dirs. + example: /opt/images/logo.png + entity_id: + description: The entity we want to set our RGB color on. + example: "light.living_room_shelves" diff --git a/homeassistant/components/comfoconnect/sensor.py b/homeassistant/components/comfoconnect/sensor.py index 5f04ba134a8..8b34fe1fd72 100644 --- a/homeassistant/components/comfoconnect/sensor.py +++ b/homeassistant/components/comfoconnect/sensor.py @@ -33,8 +33,7 @@ from homeassistant.const import ( POWER_WATT, TEMP_CELSIUS, TIME_DAYS, - TIME_HOURS, - VOLUME_CUBIC_METERS, + VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, ) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -160,14 +159,14 @@ SENSOR_TYPES = { ATTR_AIR_FLOW_SUPPLY: { ATTR_DEVICE_CLASS: None, ATTR_LABEL: "Supply airflow", - ATTR_UNIT: f"{VOLUME_CUBIC_METERS}/{TIME_HOURS}", + ATTR_UNIT: VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, ATTR_ICON: "mdi:fan", ATTR_ID: SENSOR_FAN_SUPPLY_FLOW, }, ATTR_AIR_FLOW_EXHAUST: { ATTR_DEVICE_CLASS: None, ATTR_LABEL: "Exhaust airflow", - ATTR_UNIT: f"{VOLUME_CUBIC_METERS}/{TIME_HOURS}", + ATTR_UNIT: VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, ATTR_ICON: "mdi:fan", ATTR_ID: SENSOR_FAN_EXHAUST_FLOW, }, diff --git a/homeassistant/components/config/entity_registry.py b/homeassistant/components/config/entity_registry.py index f024f146a60..73327ecf23c 100644 --- a/homeassistant/components/config/entity_registry.py +++ b/homeassistant/components/config/entity_registry.py @@ -1,6 +1,7 @@ """HTTP views to interact with the entity registry.""" import voluptuous as vol +from homeassistant import config_entries from homeassistant.components import websocket_api from homeassistant.components.websocket_api.const import ERR_NOT_FOUND from homeassistant.components.websocket_api.decorators import ( @@ -71,6 +72,7 @@ async def websocket_get_entity(hass, connection, msg): # If passed in, we update value. Passing None will remove old value. vol.Optional("name"): vol.Any(str, None), vol.Optional("icon"): vol.Any(str, None), + vol.Optional("area_id"): vol.Any(str, None), vol.Optional("new_entity_id"): str, # We only allow setting disabled_by user via API. vol.Optional("disabled_by"): vol.Any("user", None), @@ -91,7 +93,7 @@ async def websocket_update_entity(hass, connection, msg): changes = {} - for key in ("name", "icon", "disabled_by"): + for key in ("name", "icon", "area_id", "disabled_by"): if key in msg: changes[key] = msg[key] @@ -112,10 +114,15 @@ async def websocket_update_entity(hass, connection, msg): connection.send_message( websocket_api.error_message(msg["id"], "invalid_info", str(err)) ) - else: - connection.send_message( - websocket_api.result_message(msg["id"], _entry_ext_dict(entry)) - ) + return + result = {"entity_entry": _entry_ext_dict(entry)} + if "disabled_by" in changes and changes["disabled_by"] is None: + config_entry = hass.config_entries.async_get_entry(entry.config_entry_id) + if config_entry and not config_entry.supports_unload: + result["require_restart"] = True + else: + result["reload_delay"] = config_entries.RELOAD_AFTER_UPDATE_DELAY + connection.send_result(msg["id"], result) @require_admin @@ -149,6 +156,7 @@ def _entry_dict(entry): return { "config_entry_id": entry.config_entry_id, "device_id": entry.device_id, + "area_id": entry.area_id, "disabled_by": entry.disabled_by, "entity_id": entry.entity_id, "name": entry.name, diff --git a/homeassistant/components/configurator/translations/pl.json b/homeassistant/components/configurator/translations/pl.json index 849a7e7bfef..45e5af46722 100644 --- a/homeassistant/components/configurator/translations/pl.json +++ b/homeassistant/components/configurator/translations/pl.json @@ -1,7 +1,7 @@ { "state": { "_": { - "configure": "konfiguruj", + "configure": "skonfiguruj", "configured": "skonfigurowany" } }, diff --git a/homeassistant/components/configurator/translations/tr.json b/homeassistant/components/configurator/translations/tr.json index 2c78391b563..31b82d268c0 100644 --- a/homeassistant/components/configurator/translations/tr.json +++ b/homeassistant/components/configurator/translations/tr.json @@ -1,8 +1,8 @@ { "state": { "_": { - "configure": "Ayarla", - "configured": "Ayarland\u0131" + "configure": "Konfig\u00fcre et", + "configured": "Konfig\u00fcre edildi" } }, "title": "Yap\u0131land\u0131r\u0131c\u0131" diff --git a/homeassistant/components/control4/light.py b/homeassistant/components/control4/light.py index 08ac23e40e2..f8c94c6a932 100644 --- a/homeassistant/components/control4/light.py +++ b/homeassistant/components/control4/light.py @@ -187,10 +187,9 @@ class Control4Light(Control4Entity, LightEntity): @property def supported_features(self) -> int: """Flag supported features.""" - flags = 0 if self._is_dimmer: - flags |= SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION - return flags + return SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION + return 0 async def async_turn_on(self, **kwargs) -> None: """Turn the entity on.""" diff --git a/homeassistant/components/control4/translations/cs.json b/homeassistant/components/control4/translations/cs.json index c54454e9afe..327d642b308 100644 --- a/homeassistant/components/control4/translations/cs.json +++ b/homeassistant/components/control4/translations/cs.json @@ -14,6 +14,16 @@ "host": "IP adresa", "password": "Heslo", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" + }, + "description": "Zadejte pros\u00edm \u00fadaje o sv\u00e9m \u00fa\u010dtu Control4 a IP adresu m\u00edstn\u00edho ovlada\u010de." + } + } + }, + "options": { + "step": { + "init": { + "data": { + "scan_interval": "Po\u010det sekund mezi aktualizacemi" } } } diff --git a/homeassistant/components/control4/translations/nl.json b/homeassistant/components/control4/translations/nl.json index 1cc1070f6b9..1c4e7de05c9 100644 --- a/homeassistant/components/control4/translations/nl.json +++ b/homeassistant/components/control4/translations/nl.json @@ -1,9 +1,17 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { "host": "IP-adres", + "password": "Wachtwoord", "username": "Gebruikersnaam" } } diff --git a/homeassistant/components/coolmaster/translations/bg.json b/homeassistant/components/coolmaster/translations/bg.json index a7fff4f036d..079082c01cf 100644 --- a/homeassistant/components/coolmaster/translations/bg.json +++ b/homeassistant/components/coolmaster/translations/bg.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connection_error": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 CoolMasterNet. \u041c\u043e\u043b\u044f, \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u0442\u0435 \u0430\u0434\u0440\u0435\u0441\u0430.", "no_units": "\u041d\u0435 \u0431\u044f\u0445\u0430 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438 \u043a\u043b\u0438\u043c\u0430\u0442\u0438\u0447\u043d\u0438/\u0432\u0435\u043d\u0442\u0438\u043b\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0438 \u043d\u0430 \u0437\u0430\u0434\u0430\u0434\u0435\u043d\u0438\u044f CoolMasterNet \u0430\u0434\u0440\u0435\u0441." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/ca.json b/homeassistant/components/coolmaster/translations/ca.json index 40186987031..6db6a6d72d0 100644 --- a/homeassistant/components/coolmaster/translations/ca.json +++ b/homeassistant/components/coolmaster/translations/ca.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar amb la inst\u00e0ncia de CoolMasterNet. Comprova l'amfitri\u00f3.", "no_units": "No s'ha pogut trobar cap unitat d'HVAC a l'amfitri\u00f3 de CoolMasterNet." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/cs.json b/homeassistant/components/coolmaster/translations/cs.json index 2f65198b6b4..9e820808f0c 100644 --- a/homeassistant/components/coolmaster/translations/cs.json +++ b/homeassistant/components/coolmaster/translations/cs.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit k instanci CoolMasterNet. Zkontrolujte pros\u00edm sv\u00e9ho hostitele.", "no_units": "V hostiteli CoolMasterNet nelze naj\u00edt \u017e\u00e1dn\u00e9 jednotky HVAC." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/da.json b/homeassistant/components/coolmaster/translations/da.json index 5cd4b98faf8..c23a257789f 100644 --- a/homeassistant/components/coolmaster/translations/da.json +++ b/homeassistant/components/coolmaster/translations/da.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connection_error": "Kunne ikke oprette forbindelse til CoolMasterNet-instansen. Tjek din v\u00e6rt.", "no_units": "Kunne ikke finde nogen klimaanl\u00e6g i CoolMasterNet-v\u00e6rt." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/de.json b/homeassistant/components/coolmaster/translations/de.json index b29decd38bc..19a57c3180e 100644 --- a/homeassistant/components/coolmaster/translations/de.json +++ b/homeassistant/components/coolmaster/translations/de.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connection_error": "Verbindung zur CoolMasterNet-Instanz fehlgeschlagen. Bitte \u00fcberpr\u00fcfe deinen Host.", "no_units": "Es wurden keine HVAC-Ger\u00e4te im CoolMasterNet-Host gefunden." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/en.json b/homeassistant/components/coolmaster/translations/en.json index 3e69c5c82fd..f3467de9121 100644 --- a/homeassistant/components/coolmaster/translations/en.json +++ b/homeassistant/components/coolmaster/translations/en.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect to CoolMasterNet instance. Please check your host.", "no_units": "Could not find any HVAC units in CoolMasterNet host." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/es-419.json b/homeassistant/components/coolmaster/translations/es-419.json index 8cdf9675fd2..9073238aa91 100644 --- a/homeassistant/components/coolmaster/translations/es-419.json +++ b/homeassistant/components/coolmaster/translations/es-419.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connection_error": "Error al conectarse a la instancia de CoolMasterNet. Por favor revise su host.", "no_units": "No se encontraron unidades de HVAC en el host CoolMasterNet." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/es.json b/homeassistant/components/coolmaster/translations/es.json index 3d5524d1f13..a2c830756bd 100644 --- a/homeassistant/components/coolmaster/translations/es.json +++ b/homeassistant/components/coolmaster/translations/es.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "No se pudo conectar", - "connection_error": "Error al conectarse a la instancia de CoolMasterNet. Por favor revise su anfitri\u00f3n.", "no_units": "No se ha encontrado ninguna unidad HVAC en el host CoolMasterNet." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/et.json b/homeassistant/components/coolmaster/translations/et.json index f4e0eb74c94..6fb29910387 100644 --- a/homeassistant/components/coolmaster/translations/et.json +++ b/homeassistant/components/coolmaster/translations/et.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "CoolMasterNet'iga \u00fchenduse loomine nurjus. Palun kontrolli hosti andmeid.", "no_units": "CoolMasterNet'ist ei leitud \u00fchtegi HVAC seadet." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/fr.json b/homeassistant/components/coolmaster/translations/fr.json index 2028043dc3e..500ef3077cb 100644 --- a/homeassistant/components/coolmaster/translations/fr.json +++ b/homeassistant/components/coolmaster/translations/fr.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "\u00c9chec de connexion", - "connection_error": "\u00c9chec de la connexion \u00e0 l'instance CoolMasterNet. S'il vous pla\u00eet v\u00e9rifier votre h\u00f4te.", "no_units": "Impossible de trouver des unit\u00e9s HVAC dans l'h\u00f4te CoolMasterNet." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/it.json b/homeassistant/components/coolmaster/translations/it.json index 0e7814581e3..9e1342257fb 100644 --- a/homeassistant/components/coolmaster/translations/it.json +++ b/homeassistant/components/coolmaster/translations/it.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi all'istanza CoolMasterNet. Controlla il tuo host.", "no_units": "Impossibile trovare alcuna unit\u00e0 HVAC nell'host CoolMasterNet." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/ko.json b/homeassistant/components/coolmaster/translations/ko.json index cd9ac7a3970..5d0636bddcd 100644 --- a/homeassistant/components/coolmaster/translations/ko.json +++ b/homeassistant/components/coolmaster/translations/ko.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connection_error": "CoolMasterNet \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \ud638\uc2a4\ud2b8\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694.", "no_units": "CoolMasterNet \ud638\uc2a4\ud2b8\uc5d0\uc11c HVAC \uae30\uae30\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/lb.json b/homeassistant/components/coolmaster/translations/lb.json index bcb77aa2a4e..02a0f58cc4d 100644 --- a/homeassistant/components/coolmaster/translations/lb.json +++ b/homeassistant/components/coolmaster/translations/lb.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbanne mat der CoolMasterNet Instanz. Iwwerpr\u00e9ift w.e.g. \u00e4ren Apparat.", "no_units": "Konnt keng HVAC Eenheeten am CoolMasterNet Apparat fannen." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/nl.json b/homeassistant/components/coolmaster/translations/nl.json index ca44d4aef02..2ea24fd2161 100644 --- a/homeassistant/components/coolmaster/translations/nl.json +++ b/homeassistant/components/coolmaster/translations/nl.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met CoolMasterNet-instantie. Controleer uw host", "no_units": "Kon geen HVAC units vinden in CoolMasterNet host." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/no.json b/homeassistant/components/coolmaster/translations/no.json index 7b4b2159e07..7ccb23927bd 100644 --- a/homeassistant/components/coolmaster/translations/no.json +++ b/homeassistant/components/coolmaster/translations/no.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kunne ikke koble til CoolMasterNet-forekomsten. Sjekk verten din.", "no_units": "Kunne ikke finne noen HVAC-enheter i CoolMasterNet vert." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/pl.json b/homeassistant/components/coolmaster/translations/pl.json index fce8f840f5d..81e8aa3e5a9 100644 --- a/homeassistant/components/coolmaster/translations/pl.json +++ b/homeassistant/components/coolmaster/translations/pl.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna po\u0142\u0105czy\u0107 z CoolMasterNet. Sprawd\u017a adres hosta", "no_units": "Nie mo\u017cna znale\u017a\u0107 urz\u0105dze\u0144 HVAC na ho\u015bcie CoolMasterNet" }, "step": { @@ -16,7 +15,7 @@ "host": "Nazwa hosta lub adres IP", "off": "Mo\u017ce by\u0107 wy\u0142\u0105czone" }, - "title": "Skonfiguruj szczeg\u00f3\u0142y po\u0142\u0105czenia CoolMasterNet." + "title": "Konfiguracja po\u0142\u0105czenia CoolMasterNet." } } } diff --git a/homeassistant/components/coolmaster/translations/ru.json b/homeassistant/components/coolmaster/translations/ru.json index 3c508e80ab3..25b060aa65f 100644 --- a/homeassistant/components/coolmaster/translations/ru.json +++ b/homeassistant/components/coolmaster/translations/ru.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0430\u0434\u0440\u0435\u0441 \u0445\u043e\u0441\u0442\u0430.", "no_units": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043e\u0442\u043e\u043f\u043b\u0435\u043d\u0438\u044f, \u0432\u0435\u043d\u0442\u0438\u043b\u044f\u0446\u0438\u0438 \u0438 \u043a\u043e\u043d\u0434\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/sl.json b/homeassistant/components/coolmaster/translations/sl.json index d97fe244cda..af5e854191f 100644 --- a/homeassistant/components/coolmaster/translations/sl.json +++ b/homeassistant/components/coolmaster/translations/sl.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connection_error": "Povezava s CoolMasterNet ni uspela. Preverite svojega gostitelja.", "no_units": "V gostitelju CoolMasterNet ni bilo mogo\u010de najti nobenih enot HVAC." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/sv.json b/homeassistant/components/coolmaster/translations/sv.json index 60a26c21023..366295c0966 100644 --- a/homeassistant/components/coolmaster/translations/sv.json +++ b/homeassistant/components/coolmaster/translations/sv.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connection_error": "Det gick inte att ansluta till CoolMasterNet-instansen. Kontrollera din v\u00e4rd.", "no_units": "Det gick inte att hitta n\u00e5gra HVAC-enheter i CoolMasterNet-v\u00e4rden." }, "step": { diff --git a/homeassistant/components/coolmaster/translations/zh-Hant.json b/homeassistant/components/coolmaster/translations/zh-Hant.json index e3d6fc83db7..03f9cb3cfbc 100644 --- a/homeassistant/components/coolmaster/translations/zh-Hant.json +++ b/homeassistant/components/coolmaster/translations/zh-Hant.json @@ -2,7 +2,6 @@ "config": { "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u81f3 CoolMasterNet \u5931\u6557\uff0c\u8acb\u6aa2\u67e5\u4e3b\u6a5f\u7aef\u3002", "no_units": "\u7121\u6cd5\u65bc CoolMasterNet \u4e3b\u6a5f\u627e\u5230\u4efb\u4f55 HVAC \u8a2d\u5099\u3002" }, "step": { diff --git a/homeassistant/components/coronavirus/translations/lb.json b/homeassistant/components/coronavirus/translations/lb.json index 916a3e1d20e..2fb5a7ceffd 100644 --- a/homeassistant/components/coronavirus/translations/lb.json +++ b/homeassistant/components/coronavirus/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "D\u00ebst Land ass scho konfigur\u00e9iert" + "already_configured": "Service ass scho konfigur\u00e9iert" }, "step": { "user": { diff --git a/homeassistant/components/cover/translations/ru.json b/homeassistant/components/cover/translations/ru.json index 21bbe7e2c4d..f2eff4388cf 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": { @@ -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/cover/translations/zh-Hans.json b/homeassistant/components/cover/translations/zh-Hans.json index 0ff73407298..ccc1edd42c5 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/daikin/translations/ca.json b/homeassistant/components/daikin/translations/ca.json index eecb0026fe3..0b8c2aae7eb 100644 --- a/homeassistant/components/daikin/translations/ca.json +++ b/homeassistant/components/daikin/translations/ca.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "device_fail": "Error inesperat", - "device_timeout": "Ha fallat la connexi\u00f3", - "forbidden": "Autenticaci\u00f3 inv\u00e0lida", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", "unknown": "Error inesperat" }, @@ -17,7 +14,6 @@ "data": { "api_key": "Clau API", "host": "Amfitri\u00f3", - "key": "Clau API", "password": "Contrasenya" }, "description": "Introdueix l'Adre\u00e7a IP del teu AC Daikin.\n\nTingues en compte que la Clau API i la Contrasenya s'utilitzen nom\u00e9s als dispositius BRP072Cxx i SKYFi respectivament.", diff --git a/homeassistant/components/daikin/translations/cs.json b/homeassistant/components/daikin/translations/cs.json index 2fe8f6378a0..86625365a30 100644 --- a/homeassistant/components/daikin/translations/cs.json +++ b/homeassistant/components/daikin/translations/cs.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "device_fail": "Neo\u010dek\u00e1van\u00e1 chyba", - "device_timeout": "Nepoda\u0159ilo se p\u0159ipojit", - "forbidden": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, @@ -17,7 +14,6 @@ "data": { "api_key": "Kl\u00ed\u010d API", "host": "Hostitel", - "key": "Kl\u00ed\u010d API", "password": "Heslo" }, "description": "Zadejte IP adresu va\u0161eho Daikin AC. \n\nV\u0161imn\u011bte si, \u017ee Kl\u00ed\u010d API a Heslo jsou pou\u017eit\u00e9 za\u0159\u00edzen\u00edm BRP072Cxx, respektive SKYFi.", diff --git a/homeassistant/components/daikin/translations/de.json b/homeassistant/components/daikin/translations/de.json index cebe5f8647e..1d9ede292f6 100644 --- a/homeassistant/components/daikin/translations/de.json +++ b/homeassistant/components/daikin/translations/de.json @@ -4,14 +4,12 @@ "already_configured": "Ger\u00e4t ist bereits konfiguriert" }, "error": { - "device_timeout": "Verbindung fehlgeschlagen", "unknown": "Unerwarteter Fehler" }, "step": { "user": { "data": { "host": "Host", - "key": "Authentifizierungsschl\u00fcssel (wird nur von BRP072C / Zena-Ger\u00e4ten verwendet)", "password": "Passwort" }, "description": "Gib die IP-Adresse deiner Daikin AC ein.", diff --git a/homeassistant/components/daikin/translations/en.json b/homeassistant/components/daikin/translations/en.json index f4b2deef9af..d1db170d769 100644 --- a/homeassistant/components/daikin/translations/en.json +++ b/homeassistant/components/daikin/translations/en.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "Failed to connect", - "device_fail": "Unexpected error", - "device_timeout": "Failed to connect", - "forbidden": "Invalid authentication", "invalid_auth": "Invalid authentication", "unknown": "Unexpected error" }, @@ -17,7 +14,6 @@ "data": { "api_key": "API Key", "host": "Host", - "key": "API Key", "password": "Password" }, "description": "Enter IP Address of your Daikin AC.\n\nNote that API Key and Password only are used by BRP072Cxx and SKYFi devices respectively.", diff --git a/homeassistant/components/daikin/translations/es.json b/homeassistant/components/daikin/translations/es.json index 7f690b0a0df..d1fb98670ae 100644 --- a/homeassistant/components/daikin/translations/es.json +++ b/homeassistant/components/daikin/translations/es.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "device_fail": "Error inesperado", - "device_timeout": "No se pudo conectar", - "forbidden": "Autenticaci\u00f3n no v\u00e1lida", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", "unknown": "Error inesperado" }, @@ -17,7 +14,6 @@ "data": { "api_key": "Clave API", "host": "Host", - "key": "Clave API", "password": "Contrase\u00f1a" }, "description": "Introduce la direcci\u00f3n IP de tu aire acondicionado Daikin.\n\nTen en cuenta que la Clave API y la Contrase\u00f1a son usadas por los dispositivos BRP072Cxx y SKYFi respectivamente.", diff --git a/homeassistant/components/daikin/translations/et.json b/homeassistant/components/daikin/translations/et.json index 85e69c3ac9f..0f303d2014e 100644 --- a/homeassistant/components/daikin/translations/et.json +++ b/homeassistant/components/daikin/translations/et.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "device_fail": "Tundmatu viga", - "device_timeout": "\u00dchendamine nurjus", - "forbidden": "Tuvastamine nurjus", "invalid_auth": "Tuvastamise viga", "unknown": "Tundmatu viga" }, @@ -17,7 +14,6 @@ "data": { "api_key": "API v\u00f5ti", "host": "", - "key": "API v\u00f5ti", "password": "Salas\u00f5na" }, "description": "Sisesta oma Daikin AC IP aadress.\nPane t\u00e4hele, et API v\u00f5ti ja Salas\u00f5na kasutavad ainult seadmed BRP072Cxx ja SKYFi.", diff --git a/homeassistant/components/daikin/translations/fr.json b/homeassistant/components/daikin/translations/fr.json index 75f3260a86c..ab193dc20af 100644 --- a/homeassistant/components/daikin/translations/fr.json +++ b/homeassistant/components/daikin/translations/fr.json @@ -5,15 +5,15 @@ "cannot_connect": "\u00c9chec de connexion" }, "error": { - "device_fail": "Erreur inattendue", - "device_timeout": "Echec de la connexion", - "forbidden": "Authentification invalide" + "cannot_connect": "\u00c9chec de connexion", + "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)" }, "description": "Saisissez l'adresse IP de votre Daikin AC. \n\n Notez que Cl\u00e9 d'API et Mot de passe sont utilis\u00e9s respectivement par les p\u00e9riph\u00e9riques BRP072Cxx et SKYFi.", diff --git a/homeassistant/components/daikin/translations/he.json b/homeassistant/components/daikin/translations/he.json index bde111561a2..3007c0e968c 100644 --- a/homeassistant/components/daikin/translations/he.json +++ b/homeassistant/components/daikin/translations/he.json @@ -1,14 +1,8 @@ { "config": { - "error": { - "device_fail": "\u05d0\u05d9\u05e8\u05d0\u05d4 \u05e9\u05d2\u05d9\u05d0\u05d4", - "device_timeout": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05e0\u05db\u05e9\u05dc\u05d4", - "forbidden": "\u05d0\u05d9\u05de\u05d5\u05ea \u05dc\u05d0 \u05d7\u05d5\u05e7\u05d9" - }, "step": { "user": { "data": { - "key": "\u05de\u05e4\u05ea\u05d7 API", "password": "\u05e1\u05d9\u05e1\u05de\u05d4" } } diff --git a/homeassistant/components/daikin/translations/hu.json b/homeassistant/components/daikin/translations/hu.json index b11dba9028e..149a1f713f4 100644 --- a/homeassistant/components/daikin/translations/hu.json +++ b/homeassistant/components/daikin/translations/hu.json @@ -3,16 +3,10 @@ "abort": { "already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van" }, - "error": { - "device_fail": "V\u00e1ratlan hiba", - "device_timeout": "Sikertelen csatlakoz\u00e1s", - "forbidden": "\u00c9rv\u00e9nytelen hiteles\u00edt\u00e9s" - }, "step": { "user": { "data": { "host": "Hoszt", - "key": "API kulcs", "password": "Jelsz\u00f3" }, "description": "Add meg a Daikin l\u00e9gkond\u00edcion\u00e1l\u00f3 IP-c\u00edm\u00e9t.", diff --git a/homeassistant/components/daikin/translations/it.json b/homeassistant/components/daikin/translations/it.json index 6416024224a..c85f4961e57 100644 --- a/homeassistant/components/daikin/translations/it.json +++ b/homeassistant/components/daikin/translations/it.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "device_fail": "Errore imprevisto", - "device_timeout": "Impossibile connettersi", - "forbidden": "Autenticazione non valida", "invalid_auth": "Autenticazione non valida", "unknown": "Errore imprevisto" }, @@ -17,7 +14,6 @@ "data": { "api_key": "Chiave API", "host": "Host", - "key": "Chiave API", "password": "Password" }, "description": "Inserire l'Indirizzo IP del tuo condizionatore d'aria Daikin.\n\nNotare che solo la Chiave API e la Password sono rispettivamente usati dai dispositivi BRP072Cxx e SKYFi.", diff --git a/homeassistant/components/daikin/translations/ko.json b/homeassistant/components/daikin/translations/ko.json index e5981dcb626..9c4a6c8d50c 100644 --- a/homeassistant/components/daikin/translations/ko.json +++ b/homeassistant/components/daikin/translations/ko.json @@ -4,16 +4,10 @@ "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "cannot_connect": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4" }, - "error": { - "device_fail": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4", - "device_timeout": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4", - "forbidden": "\uc778\uc99d\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { "host": "\ud638\uc2a4\ud2b8", - "key": "API \ud0a4", "password": "\ube44\ubc00\ubc88\ud638" }, "description": "\ub2e4\uc774\ud0a8 \uc5d0\uc5b4\ucee8\uc758 IP \uc8fc\uc18c\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694.\n\nAPI \ud0a4 \ubc0f \ube44\ubc00\ubc88\ud638\ub294 BRP072Cxx \uc640 SKYFi \uae30\uae30\uc5d0\uc11c \uc0ac\uc6a9\ub41c\ub2e4\ub294 \uc810\uc5d0 \uc720\uc758\ud558\uc138\uc694.", diff --git a/homeassistant/components/daikin/translations/lb.json b/homeassistant/components/daikin/translations/lb.json index aa59b6dfa50..86f2fd7e2d0 100644 --- a/homeassistant/components/daikin/translations/lb.json +++ b/homeassistant/components/daikin/translations/lb.json @@ -5,18 +5,18 @@ "cannot_connect": "Feeler beim verbannen" }, "error": { - "device_fail": "Onerwaarte Feeler", - "device_timeout": "Feeler beim verbannen", - "forbidden": "Ong\u00eblteg Authentifikatioun" + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", + "unknown": "Onerwaarte Feeler" }, "step": { "user": { "data": { + "api_key": "API Schl\u00ebssel", "host": "Apparat", - "key": "API Schl\u00ebssel", "password": "Passwuert" }, - "description": "Gitt d'IP Adresse vum Daikin AC an.\n\nRemarque: API Schl\u00ebssel a Passwuert gi vu BRP072Cxx a SKYFi Apparater respektiv benotzt.", + "description": "G\u00ebff d'IP Adresse vum Daikin AC an.\n\nRemarque: API Schl\u00ebssel a Passwuert gi vu BRP072Cxx a SKYFi Apparater benotzt.", "title": "Daikin AC konfigur\u00e9ieren" } } diff --git a/homeassistant/components/daikin/translations/nl.json b/homeassistant/components/daikin/translations/nl.json index 775e358d205..2d1e1edbdbb 100644 --- a/homeassistant/components/daikin/translations/nl.json +++ b/homeassistant/components/daikin/translations/nl.json @@ -1,11 +1,13 @@ { "config": { "abort": { - "already_configured": "Apparaat is al geconfigureerd" + "already_configured": "Apparaat is al geconfigureerd", + "cannot_connect": "Kon niet verbinden" }, "step": { "user": { "data": { + "api_key": "API-sleutel", "host": "Host", "password": "Wachtwoord" }, diff --git a/homeassistant/components/daikin/translations/no.json b/homeassistant/components/daikin/translations/no.json index 6bcf2b2e77c..e63b8eeef0d 100644 --- a/homeassistant/components/daikin/translations/no.json +++ b/homeassistant/components/daikin/translations/no.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "device_fail": "Uventet feil", - "device_timeout": "Tilkobling mislyktes", - "forbidden": "Ugyldig godkjenning", "invalid_auth": "Ugyldig godkjenning", "unknown": "Uventet feil" }, @@ -17,7 +14,6 @@ "data": { "api_key": "API-n\u00f8kkel", "host": "Vert", - "key": "API-n\u00f8kkel", "password": "Passord" }, "description": "Skriv inn IP adresse av Daikin AC.\n\n Merk at API-n\u00f8kkel og Passord bare brukes av henholdsvis BRP072Cxx og SKYFi-enheter.", diff --git a/homeassistant/components/daikin/translations/pl.json b/homeassistant/components/daikin/translations/pl.json index f20666fda33..d11ffd4dd3a 100644 --- a/homeassistant/components/daikin/translations/pl.json +++ b/homeassistant/components/daikin/translations/pl.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "device_fail": "Nieoczekiwany b\u0142\u0105d", - "device_timeout": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "forbidden": "Niepoprawne uwierzytelnienie", "invalid_auth": "Niepoprawne uwierzytelnienie", "unknown": "Nieoczekiwany b\u0142\u0105d" }, @@ -17,7 +14,6 @@ "data": { "api_key": "Klucz API", "host": "Nazwa hosta lub adres IP", - "key": "Klucz API", "password": "Has\u0142o" }, "description": "Wprowad\u017a adres IP klimatyzacji Daikin.\n\nZwr\u00f3\u0107 uwag\u0119, \u017ce klucz API oraz has\u0142o u\u017cywane s\u0105 odpowiednio tylko przez urz\u0105dzenia BRP072Cxx i SKYFi.", diff --git a/homeassistant/components/daikin/translations/pt-BR.json b/homeassistant/components/daikin/translations/pt-BR.json index a844969172f..11642b57627 100644 --- a/homeassistant/components/daikin/translations/pt-BR.json +++ b/homeassistant/components/daikin/translations/pt-BR.json @@ -4,11 +4,6 @@ "already_configured": "O dispositivo j\u00e1 est\u00e1 configurado", "cannot_connect": "Falha na conex\u00e3o" }, - "error": { - "device_fail": "Erro inesperado", - "device_timeout": "Falha ao conectar", - "forbidden": "Autentica\u00e7\u00e3o inv\u00e1lida" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/daikin/translations/ru.json b/homeassistant/components/daikin/translations/ru.json index 8587232fbbb..df7d9fb07dc 100644 --- a/homeassistant/components/daikin/translations/ru.json +++ b/homeassistant/components/daikin/translations/ru.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "device_fail": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", - "device_timeout": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "forbidden": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, @@ -17,7 +14,6 @@ "data": { "api_key": "\u041a\u043b\u044e\u0447 API", "host": "\u0425\u043e\u0441\u0442", - "key": "\u041a\u043b\u044e\u0447 API", "password": "\u041f\u0430\u0440\u043e\u043b\u044c" }, "description": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 IP-\u0430\u0434\u0440\u0435\u0441 \u0412\u0430\u0448\u0435\u0433\u043e Daikin AC. \n\n\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u041a\u043b\u044e\u0447 API \u0438 \u041f\u0430\u0440\u043e\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 BRP072Cxx \u0438 SKYFi \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e.", diff --git a/homeassistant/components/daikin/translations/sv.json b/homeassistant/components/daikin/translations/sv.json index 8c3e221f0bc..a704822f0b7 100644 --- a/homeassistant/components/daikin/translations/sv.json +++ b/homeassistant/components/daikin/translations/sv.json @@ -7,7 +7,6 @@ "user": { "data": { "host": "V\u00e4rddatorn", - "key": "API nyckel", "password": "Enhetsl\u00f6senord (anv\u00e4nds endast av SKYFi-enheter)" }, "description": "Ange IP-adressen f\u00f6r din Daikin AC.", diff --git a/homeassistant/components/daikin/translations/zh-Hant.json b/homeassistant/components/daikin/translations/zh-Hant.json index 6ebd03b4376..1949bd98b26 100644 --- a/homeassistant/components/daikin/translations/zh-Hant.json +++ b/homeassistant/components/daikin/translations/zh-Hant.json @@ -6,9 +6,6 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "device_fail": "\u672a\u9810\u671f\u932f\u8aa4", - "device_timeout": "\u9023\u7dda\u5931\u6557", - "forbidden": "\u9a57\u8b49\u78bc\u7121\u6548", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, @@ -17,7 +14,6 @@ "data": { "api_key": "API \u5bc6\u9470", "host": "\u4e3b\u6a5f\u7aef", - "key": "API \u5bc6\u9470", "password": "\u5bc6\u78bc" }, "description": "\u8f38\u5165\u60a8\u7684\u5927\u91d1\u7a7a\u8abfIP \u4f4d\u5740\u3002\n\n\u8acb\u6ce8\u610f\uff1aBRP072Cxx \u8207 SKYFi \u8a2d\u5099\u4e4b API \u5bc6\u9470\u8207\u5bc6\u78bc\u70ba\u5206\u958b\u4f7f\u7528\u3002", diff --git a/homeassistant/components/darksky/sensor.py b/homeassistant/components/darksky/sensor.py index 49b5c6c69f6..0bafdbb3d81 100644 --- a/homeassistant/components/darksky/sensor.py +++ b/homeassistant/components/darksky/sensor.py @@ -18,15 +18,14 @@ from homeassistant.const import ( DEGREE, LENGTH_CENTIMETERS, LENGTH_KILOMETERS, - LENGTH_MILLIMETERS, PERCENTAGE, + PRECIPITATION_MILLIMETERS_PER_HOUR, PRESSURE_MBAR, SPEED_KILOMETERS_PER_HOUR, SPEED_METERS_PER_SECOND, SPEED_MILES_PER_HOUR, TEMP_CELSIUS, TEMP_FAHRENHEIT, - TIME_HOURS, UV_INDEX, ) import homeassistant.helpers.config_validation as cv @@ -111,11 +110,11 @@ SENSOR_TYPES = { ], "precip_intensity": [ "Precip Intensity", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", + PRECIPITATION_MILLIMETERS_PER_HOUR, "in", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", + PRECIPITATION_MILLIMETERS_PER_HOUR, + PRECIPITATION_MILLIMETERS_PER_HOUR, + PRECIPITATION_MILLIMETERS_PER_HOUR, "mdi:weather-rainy", ["currently", "minutely", "hourly", "daily"], ], @@ -331,11 +330,11 @@ SENSOR_TYPES = { ], "precip_intensity_max": [ "Daily Max Precip Intensity", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", + PRECIPITATION_MILLIMETERS_PER_HOUR, "in", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", + PRECIPITATION_MILLIMETERS_PER_HOUR, + PRECIPITATION_MILLIMETERS_PER_HOUR, + PRECIPITATION_MILLIMETERS_PER_HOUR, "mdi:thermometer", ["daily"], ], diff --git a/homeassistant/components/debugpy/manifest.json b/homeassistant/components/debugpy/manifest.json index 1c77323180c..18583186c3b 100644 --- a/homeassistant/components/debugpy/manifest.json +++ b/homeassistant/components/debugpy/manifest.json @@ -2,7 +2,7 @@ "domain": "debugpy", "name": "Remote Python Debugger", "documentation": "https://www.home-assistant.io/integrations/debugpy", - "requirements": ["debugpy==1.0.0rc2"], + "requirements": ["debugpy==1.1.0"], "codeowners": ["@frenck"], "quality_scale": "internal" } diff --git a/homeassistant/components/deconz/translations/bg.json b/homeassistant/components/deconz/translations/bg.json index 11a91d859a3..0aef2e3ec98 100644 --- a/homeassistant/components/deconz/translations/bg.json +++ b/homeassistant/components/deconz/translations/bg.json @@ -5,7 +5,6 @@ "already_in_progress": "\u0412 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0442\u0435\u0447\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0431\u0430\u0437\u043e\u0432\u0430 \u0441\u0442\u0430\u043d\u0446\u0438\u044f.", "no_bridges": "\u041d\u0435 \u0441\u0430 \u043e\u0442\u043a\u0440\u0438\u0442\u0438 \u043c\u043e\u0441\u0442\u043e\u0432\u0435 deCONZ", "not_deconz_bridge": "\u041d\u0435 \u0435 deCONZ \u0431\u0430\u0437\u043e\u0432\u0430 \u0441\u0442\u0430\u043d\u0446\u0438\u044f", - "one_instance_only": "\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u043e \u043a\u043e\u043f\u0438\u0435 \u043d\u0430 deCONZ", "updated_instance": "\u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 deCONZ \u0441 \u043d\u043e\u0432 \u0430\u0434\u0440\u0435\u0441" }, "error": { diff --git a/homeassistant/components/deconz/translations/ca.json b/homeassistant/components/deconz/translations/ca.json index 0cda0b9c78d..49374ee123f 100644 --- a/homeassistant/components/deconz/translations/ca.json +++ b/homeassistant/components/deconz/translations/ca.json @@ -6,7 +6,6 @@ "no_bridges": "No s'han descobert enlla\u00e7os amb deCONZ", "no_hardware_available": "No hi ha cap maquinari r\u00e0dio connectat a deCONZ", "not_deconz_bridge": "No \u00e9s un enlla\u00e7 deCONZ", - "one_instance_only": "El component nom\u00e9s admet una inst\u00e0ncia deCONZ", "updated_instance": "S'ha actualitzat la inst\u00e0ncia de deCONZ amb una nova adre\u00e7a" }, "error": { diff --git a/homeassistant/components/deconz/translations/cs.json b/homeassistant/components/deconz/translations/cs.json index 6591366f75c..3ad72dc9ac9 100644 --- a/homeassistant/components/deconz/translations/cs.json +++ b/homeassistant/components/deconz/translations/cs.json @@ -4,8 +4,8 @@ "already_configured": "P\u0159emost\u011bn\u00ed je ji\u017e nastaveno", "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", "no_bridges": "\u017d\u00e1dn\u00e9 deCONZ p\u0159emost\u011bn\u00ed nebyly nalezeny", + "no_hardware_available": "K deCONZ nen\u00ed p\u0159ipojeno \u017e\u00e1dn\u00e9 r\u00e1diov\u00e9 za\u0159\u00edzen\u00ed", "not_deconz_bridge": "Nejedn\u00e1 se o deCONZ p\u0159emost\u011bn\u00ed", - "one_instance_only": "Komponent podporuje pouze jednu instanci deCONZ", "updated_instance": "Instance deCONZ aktualizov\u00e1na s nov\u00fdm hostitelem" }, "error": { @@ -64,6 +64,7 @@ "remote_button_long_release": "Uvoln\u011bno tla\u010d\u00edtko \"{subtype}\" po dlouh\u00e9m stisku", "remote_button_quadruple_press": "\u010cty\u0159ikr\u00e1t stisknuto tla\u010d\u00edtko \"{subtype}\"", "remote_button_quintuple_press": "P\u011btkr\u00e1t stisknuto tla\u010d\u00edtko \"{subtype}\"", + "remote_button_rotation_stopped": "Oto\u010den\u00ed tla\u010d\u00edtka \"{subtype}\" bylo zastaveno", "remote_button_short_press": "Stiknuto tla\u010d\u00edtko \"{subtype}\"", "remote_button_short_release": "Uvoln\u011bno tla\u010d\u00edtko \"{subtype}\"", "remote_button_triple_press": "T\u0159ikr\u00e1t stisknuto tla\u010d\u00edtko \"{subtype}\"", diff --git a/homeassistant/components/deconz/translations/cy.json b/homeassistant/components/deconz/translations/cy.json index 6119486f841..6752be229e3 100644 --- a/homeassistant/components/deconz/translations/cy.json +++ b/homeassistant/components/deconz/translations/cy.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "Pont eisoes wedi'i ffurfweddu", - "no_bridges": "Dim pontydd deCONZ wedi eu darganfod", - "one_instance_only": "Elfen dim ond yn cefnogi enghraifft deCONZ" + "no_bridges": "Dim pontydd deCONZ wedi eu darganfod" }, "error": { "no_key": "Methu cael allwedd API" diff --git a/homeassistant/components/deconz/translations/da.json b/homeassistant/components/deconz/translations/da.json index e4f57869779..50cdd242ad0 100644 --- a/homeassistant/components/deconz/translations/da.json +++ b/homeassistant/components/deconz/translations/da.json @@ -5,7 +5,6 @@ "already_in_progress": "Konfigurationsflow for bro er allerede i gang.", "no_bridges": "Ingen deConz-bridge fundet", "not_deconz_bridge": "Ikke en deCONZ-bro", - "one_instance_only": "Komponenten underst\u00f8tter kun \u00e9n deCONZ-instans", "updated_instance": "Opdaterede deCONZ-instans med ny v\u00e6rtadresse" }, "error": { diff --git a/homeassistant/components/deconz/translations/de.json b/homeassistant/components/deconz/translations/de.json index 6b9fcc0d3a6..f9448705c5d 100644 --- a/homeassistant/components/deconz/translations/de.json +++ b/homeassistant/components/deconz/translations/de.json @@ -5,7 +5,6 @@ "already_in_progress": "Der Konfigurationsablauf f\u00fcr die Bridge wird bereits ausgef\u00fchrt.", "no_bridges": "Keine deCON-Bridges entdeckt", "not_deconz_bridge": "Keine deCONZ Bridge entdeckt", - "one_instance_only": "Komponente unterst\u00fctzt nur eine deCONZ-Instanz", "updated_instance": "deCONZ-Instanz mit neuer Host-Adresse aktualisiert" }, "error": { diff --git a/homeassistant/components/deconz/translations/en.json b/homeassistant/components/deconz/translations/en.json index 3604e2464c8..014280d8cc4 100644 --- a/homeassistant/components/deconz/translations/en.json +++ b/homeassistant/components/deconz/translations/en.json @@ -6,7 +6,6 @@ "no_bridges": "No deCONZ bridges discovered", "no_hardware_available": "No radio hardware connected to deCONZ", "not_deconz_bridge": "Not a deCONZ bridge", - "one_instance_only": "Component only supports one deCONZ instance", "updated_instance": "Updated deCONZ instance with new host address" }, "error": { diff --git a/homeassistant/components/deconz/translations/es-419.json b/homeassistant/components/deconz/translations/es-419.json index 79a43c76b50..e454d080ad7 100644 --- a/homeassistant/components/deconz/translations/es-419.json +++ b/homeassistant/components/deconz/translations/es-419.json @@ -5,7 +5,6 @@ "already_in_progress": "El flujo de configuraci\u00f3n para el puente ya est\u00e1 en progreso.", "no_bridges": "No se descubrieron puentes deCONZ", "not_deconz_bridge": "No es un puente deCONZ", - "one_instance_only": "El componente solo admite una instancia deCONZ", "updated_instance": "Instancia deCONZ actualizada con nueva direcci\u00f3n de host" }, "error": { diff --git a/homeassistant/components/deconz/translations/es.json b/homeassistant/components/deconz/translations/es.json index c935e7398b3..62ab509e268 100644 --- a/homeassistant/components/deconz/translations/es.json +++ b/homeassistant/components/deconz/translations/es.json @@ -6,7 +6,6 @@ "no_bridges": "No se han descubierto pasarelas deCONZ", "no_hardware_available": "No hay hardware de radio conectado a deCONZ", "not_deconz_bridge": "No es una pasarela deCONZ", - "one_instance_only": "El componente solo admite una instancia de deCONZ", "updated_instance": "Instancia deCONZ actualizada con nueva direcci\u00f3n de host" }, "error": { diff --git a/homeassistant/components/deconz/translations/et.json b/homeassistant/components/deconz/translations/et.json index 0af02237071..ad5c07b6607 100644 --- a/homeassistant/components/deconz/translations/et.json +++ b/homeassistant/components/deconz/translations/et.json @@ -6,7 +6,6 @@ "no_bridges": "DeCONZ l\u00fc\u00fcse ei leitud", "no_hardware_available": "DeCONZi raadio riistvara puudub", "not_deconz_bridge": "See pole deCONZ-i sild", - "one_instance_only": "Komponent toetab ainult \u00fchte deCONZ-i sidumist", "updated_instance": "DeCONZ-i eksemplarile omistati uus hostiaadress" }, "error": { @@ -67,7 +66,7 @@ "remote_button_quadruple_press": "\"{subtype}\" nuppu on neljakordselt kl\u00f5psatud", "remote_button_quintuple_press": "\"{subtype}\" nuppu on viiekordselt kl\u00f5psatud", "remote_button_rotated": "Nuppu \"{subtype}\" keerati", - "remote_button_rotated_fast": "Nuppu \"{ subtype}\"p\u00f6\u00f6rati kiiresti ", + "remote_button_rotated_fast": "Nuppu \"{ subtype}\"p\u00f6\u00f6rati kiiresti", "remote_button_rotation_stopped": "Nupu \" {subtype} \" p\u00f6\u00f6ramine peatus", "remote_button_short_press": "\"{subtype}\" nupp on vajutatud", "remote_button_short_release": "\"{subtype}\" nupp vabastati", @@ -77,7 +76,15 @@ "remote_falling": "Seade on vabalangemises", "remote_flip_180_degrees": "Seadet p\u00f6\u00f6rati 180 kraadi", "remote_flip_90_degrees": "Seadet p\u00f6\u00f6rati 90 kraadi", - "remote_gyro_activated": "Seadet raputati", + "remote_gyro_activated": "seadet raputati", + "remote_moved": "Seadet liigutati k\u00fcljega \"{subtype}\" \u00fclal", + "remote_moved_any_side": "Seadet liigutati suvaline k\u00fclg \u00fcleval pool", + "remote_rotate_from_side_1": "Seade p\u00f6\u00f6rati k\u00fcljelt \"1\u201d asendisse \"{subtype}\u201d", + "remote_rotate_from_side_2": "Seade p\u00f6\u00f6rati k\u00fcljelt \"2\u201d asendisse \"{subtype}\u201d", + "remote_rotate_from_side_3": "Seade p\u00f6\u00f6rati k\u00fcljelt \"3\u201d asendisse \"{subtype}\u201d", + "remote_rotate_from_side_4": "Seade p\u00f6\u00f6rati k\u00fcljelt \"4\u201d asendisse \"{subtype}\u201d", + "remote_rotate_from_side_5": "Seade p\u00f6\u00f6rati k\u00fcljelt \"5\u201d asendisse \"{subtype}\u201d", + "remote_rotate_from_side_6": "Seade p\u00f6\u00f6rati k\u00fcljelt \"6\u201d asendisse \"{subtype}\"", "remote_turned_clockwise": "Seadet p\u00f6\u00f6rati p\u00e4rip\u00e4eva", "remote_turned_counter_clockwise": "Seadet p\u00f6\u00f6rati vastup\u00e4eva" } @@ -86,8 +93,12 @@ "step": { "deconz_devices": { "data": { + "allow_clip_sensor": "Luba deCONZ CLIP andurid", + "allow_deconz_groups": "Luba deCONZi valgustgrupid", "allow_new_devices": "Luba uute seadmete automaatne lisamine" - } + }, + "description": "Seadista deCONZ-i seadmet\u00fc\u00fcpide n\u00e4htavus", + "title": "deCONZi valikud" } } } diff --git a/homeassistant/components/deconz/translations/fr.json b/homeassistant/components/deconz/translations/fr.json index 2704951db5c..b64819471a0 100644 --- a/homeassistant/components/deconz/translations/fr.json +++ b/homeassistant/components/deconz/translations/fr.json @@ -6,7 +6,6 @@ "no_bridges": "Aucun pont deCONZ n'a \u00e9t\u00e9 d\u00e9couvert", "no_hardware_available": "Aucun mat\u00e9riel radio connect\u00e9 \u00e0 deCONZ", "not_deconz_bridge": "Pas un pont deCONZ", - "one_instance_only": "Le composant prend uniquement en charge une instance deCONZ", "updated_instance": "Instance deCONZ mise \u00e0 jour avec la nouvelle adresse d'h\u00f4te" }, "error": { @@ -67,6 +66,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/he.json b/homeassistant/components/deconz/translations/he.json index 2011ebdde0d..163cd813dc3 100644 --- a/homeassistant/components/deconz/translations/he.json +++ b/homeassistant/components/deconz/translations/he.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "\u05d4\u05de\u05d2\u05e9\u05e8 \u05db\u05d1\u05e8 \u05de\u05d5\u05d2\u05d3\u05e8", - "no_bridges": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05d2\u05e9\u05e8\u05d9 deCONZ", - "one_instance_only": "\u05d4\u05e8\u05db\u05d9\u05d1 \u05ea\u05d5\u05de\u05da \u05e8\u05e7 \u05d0\u05d7\u05d3 deCONZ \u05dc\u05de\u05e9\u05dc" + "no_bridges": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05d2\u05e9\u05e8\u05d9 deCONZ" }, "error": { "no_key": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05d4\u05d9\u05d4 \u05dc\u05e7\u05d1\u05dc \u05de\u05e4\u05ea\u05d7 API" diff --git a/homeassistant/components/deconz/translations/hu.json b/homeassistant/components/deconz/translations/hu.json index bc07dd2cf97..4651a7c08e0 100644 --- a/homeassistant/components/deconz/translations/hu.json +++ b/homeassistant/components/deconz/translations/hu.json @@ -5,7 +5,6 @@ "already_in_progress": "Az \u00e1tj\u00e1r\u00f3 konfigur\u00e1ci\u00f3s folyamata m\u00e1r folyamatban van.", "no_bridges": "Nem tal\u00e1ltam deCONZ bridget", "not_deconz_bridge": "Nem egy deCONZ \u00e1tj\u00e1r\u00f3", - "one_instance_only": "Ez a komponens csak egy deCONZ egys\u00e9get t\u00e1mogat", "updated_instance": "A deCONZ-p\u00e9ld\u00e1ny \u00faj \u00e1llom\u00e1sc\u00edmmel friss\u00edtve" }, "error": { diff --git a/homeassistant/components/deconz/translations/id.json b/homeassistant/components/deconz/translations/id.json index 9c57eadb0ca..0d46cf7c176 100644 --- a/homeassistant/components/deconz/translations/id.json +++ b/homeassistant/components/deconz/translations/id.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "Bridge sudah dikonfigurasi", - "no_bridges": "deCONZ bridges tidak ditemukan", - "one_instance_only": "Komponen hanya mendukung satu instance deCONZ" + "no_bridges": "deCONZ bridges tidak ditemukan" }, "error": { "no_key": "Tidak bisa mendapatkan kunci API" diff --git a/homeassistant/components/deconz/translations/it.json b/homeassistant/components/deconz/translations/it.json index 2029e11613f..00ecd316da7 100644 --- a/homeassistant/components/deconz/translations/it.json +++ b/homeassistant/components/deconz/translations/it.json @@ -6,7 +6,6 @@ "no_bridges": "Nessun bridge deCONZ rilevato", "no_hardware_available": "Nessun hardware radio collegato a deCONZ", "not_deconz_bridge": "Non \u00e8 un bridge deCONZ", - "one_instance_only": "Il componente supporto solo un'istanza di deCONZ", "updated_instance": "Istanza deCONZ aggiornata con nuovo indirizzo host" }, "error": { @@ -67,6 +66,7 @@ "remote_button_quadruple_press": "Pulsante \"{subtype}\" cliccato quattro volte", "remote_button_quintuple_press": "Pulsante \"{subtype}\" cliccato cinque volte", "remote_button_rotated": "Pulsante ruotato \"{subtype}\"", + "remote_button_rotated_fast": "Pulsante ruotato velocemente \"{subtype}\"", "remote_button_rotation_stopped": "La rotazione dei pulsanti \"{subtype}\" si \u00e8 arrestata", "remote_button_short_press": "Pulsante \"{subtype}\" premuto", "remote_button_short_release": "Pulsante \"{subtype}\" rilasciato", diff --git a/homeassistant/components/deconz/translations/ko.json b/homeassistant/components/deconz/translations/ko.json index 74905c7dacc..6c7dde04e31 100644 --- a/homeassistant/components/deconz/translations/ko.json +++ b/homeassistant/components/deconz/translations/ko.json @@ -5,7 +5,6 @@ "already_in_progress": "\ube0c\ub9ac\uc9c0 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4.", "no_bridges": "\ubc1c\uacac\ub41c deCONZ \ube0c\ub9ac\uc9c0\uac00 \uc5c6\uc2b5\ub2c8\ub2e4", "not_deconz_bridge": "deCONZ \ube0c\ub9ac\uc9c0\uac00 \uc544\ub2d9\ub2c8\ub2e4", - "one_instance_only": "\uad6c\uc131\uc694\uc18c\ub294 \ud558\ub098\uc758 deCONZ \uc778\uc2a4\ud134\uc2a4\ub9cc \uc9c0\uc6d0\ud569\ub2c8\ub2e4", "updated_instance": "deCONZ \uc778\uc2a4\ud134\uc2a4\ub97c \uc0c8\ub85c\uc6b4 \ud638\uc2a4\ud2b8 \uc8fc\uc18c\ub85c \uc5c5\ub370\uc774\ud2b8\ud588\uc2b5\ub2c8\ub2e4" }, "error": { diff --git a/homeassistant/components/deconz/translations/lb.json b/homeassistant/components/deconz/translations/lb.json index d2c36eb30bd..25adae28583 100644 --- a/homeassistant/components/deconz/translations/lb.json +++ b/homeassistant/components/deconz/translations/lb.json @@ -2,11 +2,10 @@ "config": { "abort": { "already_configured": "Bridge ass schon konfigur\u00e9iert", - "already_in_progress": "Konfiguratioun fir d\u00ebsen Apparat ass schonn am gaang.", + "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaang.", "no_bridges": "Keng dECONZ bridges fonnt", "no_hardware_available": "Keng Radio Hardware verbonne mat deCONZ", "not_deconz_bridge": "Keng deCONZ Bridge", - "one_instance_only": "Komponent \u00ebnnerst\u00ebtzt n\u00ebmmen eng deCONZ Instanz", "updated_instance": "deCONZ Instanz gouf mat der neier Adress vum Apparat ge\u00e4nnert" }, "error": { diff --git a/homeassistant/components/deconz/translations/nl.json b/homeassistant/components/deconz/translations/nl.json index edd65efe3d8..2d43ca63bfe 100644 --- a/homeassistant/components/deconz/translations/nl.json +++ b/homeassistant/components/deconz/translations/nl.json @@ -6,7 +6,6 @@ "no_bridges": "Geen deCONZ apparaten ontdekt", "no_hardware_available": "Geen radiohardware aangesloten op deCONZ", "not_deconz_bridge": "Dit is geen deCONZ bridge", - "one_instance_only": "Component ondersteunt slechts \u00e9\u00e9n deCONZ instantie", "updated_instance": "DeCONZ-instantie bijgewerkt met nieuw host-adres" }, "error": { @@ -67,6 +66,7 @@ "remote_button_quadruple_press": "\" {subtype} \" knop viervoudig aangeklikt", "remote_button_quintuple_press": "\" {subtype} \" knop vijf keer aangeklikt", "remote_button_rotated": "Knop gedraaid \" {subtype} \"", + "remote_button_rotated_fast": "Knop is snel gedraaid \" {subtype} \"", "remote_button_rotation_stopped": "Knoprotatie \" {subtype} \" gestopt", "remote_button_short_press": "\"{subtype}\" knop ingedrukt", "remote_button_short_release": "\"{subtype}\" knop losgelaten", diff --git a/homeassistant/components/deconz/translations/nn.json b/homeassistant/components/deconz/translations/nn.json index 9b962ae0577..b892e059e95 100644 --- a/homeassistant/components/deconz/translations/nn.json +++ b/homeassistant/components/deconz/translations/nn.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "Brua er allereie konfigurert", - "no_bridges": "Oppdaga ingen deCONZ-bruer", - "one_instance_only": "Komponenten st\u00f8ttar berre \u00e9in deCONZ-instans" + "no_bridges": "Oppdaga ingen deCONZ-bruer" }, "error": { "no_key": "Kunne ikkje f\u00e5 ein API-n\u00f8kkel" diff --git a/homeassistant/components/deconz/translations/no.json b/homeassistant/components/deconz/translations/no.json index 5515595bdee..48716379483 100644 --- a/homeassistant/components/deconz/translations/no.json +++ b/homeassistant/components/deconz/translations/no.json @@ -6,7 +6,6 @@ "no_bridges": "Ingen deCONZ broer oppdaget", "no_hardware_available": "Ingen radiomaskinvare koblet til deCONZ", "not_deconz_bridge": "Ikke en deCONZ bro", - "one_instance_only": "Komponenten st\u00f8tter bare \u00e9n deCONZ forekomst", "updated_instance": "Oppdatert deCONZ forekomst med ny vertsadresse" }, "error": { diff --git a/homeassistant/components/deconz/translations/pl.json b/homeassistant/components/deconz/translations/pl.json index c0b4ecf2e1d..e6c89d53b4a 100644 --- a/homeassistant/components/deconz/translations/pl.json +++ b/homeassistant/components/deconz/translations/pl.json @@ -6,7 +6,6 @@ "no_bridges": "Nie odkryto mostk\u00f3w deCONZ", "no_hardware_available": "Nie wykryto komponentu radiowego pod\u0142\u0105czonego do deCONZ", "not_deconz_bridge": "To nie jest mostek deCONZ", - "one_instance_only": "Komponent obs\u0142uguje tylko jedn\u0105 instancj\u0119 deCONZ", "updated_instance": "Zaktualizowano instancj\u0119 deCONZ o nowy adres hosta" }, "error": { @@ -56,8 +55,8 @@ "side_5": "strona 5", "side_6": "strona 6", "top_buttons": "g\u00f3rne przyciski", - "turn_off": "wy\u0142\u0105cz", - "turn_on": "w\u0142\u0105cz" + "turn_off": "wy\u0142\u0105cznik", + "turn_on": "w\u0142\u0105cznik" }, "trigger_type": { "remote_awakened": "urz\u0105dzenie si\u0119 obudzi", diff --git a/homeassistant/components/deconz/translations/pt-BR.json b/homeassistant/components/deconz/translations/pt-BR.json index dccbb0f69ca..a13c94d82d7 100644 --- a/homeassistant/components/deconz/translations/pt-BR.json +++ b/homeassistant/components/deconz/translations/pt-BR.json @@ -5,7 +5,6 @@ "already_in_progress": "Fluxo de configura\u00e7\u00e3o para ponte j\u00e1 est\u00e1 em andamento.", "no_bridges": "N\u00e3o h\u00e1 pontes de deCONZ descobertas", "not_deconz_bridge": "N\u00e3o \u00e9 uma ponte deCONZ", - "one_instance_only": "Componente suporta apenas uma inst\u00e2ncia deCONZ", "updated_instance": "Atualiza\u00e7\u00e3o da inst\u00e2ncia deCONZ com novo endere\u00e7o de host" }, "error": { diff --git a/homeassistant/components/deconz/translations/pt.json b/homeassistant/components/deconz/translations/pt.json index 19bfd346ff7..ce6d6df8906 100644 --- a/homeassistant/components/deconz/translations/pt.json +++ b/homeassistant/components/deconz/translations/pt.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "Bridge j\u00e1 est\u00e1 configurada", - "no_bridges": "Nenhum hub deCONZ descoberto", - "one_instance_only": "Componente suporta apenas uma conex\u00e3o deCONZ" + "no_bridges": "Nenhum hub deCONZ descoberto" }, "error": { "no_key": "N\u00e3o foi poss\u00edvel obter uma chave de API" diff --git a/homeassistant/components/deconz/translations/ru.json b/homeassistant/components/deconz/translations/ru.json index 92cb2deb27c..a6bc0daaa3e 100644 --- a/homeassistant/components/deconz/translations/ru.json +++ b/homeassistant/components/deconz/translations/ru.json @@ -6,7 +6,6 @@ "no_bridges": "\u0428\u043b\u044e\u0437\u044b deCONZ \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.", "no_hardware_available": "\u041a deCONZ \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043e \u0440\u0430\u0434\u0438\u043e\u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435.", "not_deconz_bridge": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0448\u043b\u044e\u0437\u043e\u043c deCONZ.", - "one_instance_only": "\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 deCONZ.", "updated_instance": "\u0410\u0434\u0440\u0435\u0441 \u0445\u043e\u0441\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d." }, "error": { @@ -15,8 +14,8 @@ "flow_title": "\u0428\u043b\u044e\u0437 Zigbee deCONZ ({host})", "step": { "hassio_confirm": { - "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 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a deCONZ (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", - "title": "Zigbee \u0448\u043b\u044e\u0437 deCONZ (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io)" + "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 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a deCONZ (\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", + "title": "Zigbee \u0448\u043b\u044e\u0437 deCONZ (\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io)" }, "link": { "description": "\u0420\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0439\u0442\u0435 \u0448\u043b\u044e\u0437 deCONZ \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0432 Home Assistant:\n\n1. \u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u044b deCONZ -> Gateway -> Advanced.\n2. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00abAuthenticate app\u00bb.", @@ -61,17 +60,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/deconz/translations/sl.json b/homeassistant/components/deconz/translations/sl.json index 092d65fb4cb..cf5600c20e4 100644 --- a/homeassistant/components/deconz/translations/sl.json +++ b/homeassistant/components/deconz/translations/sl.json @@ -5,7 +5,6 @@ "already_in_progress": "Konfiguracijski tok za most je \u017ee v teku.", "no_bridges": "Ni odkritih mostov deCONZ", "not_deconz_bridge": "Ni deCONZ most", - "one_instance_only": "Komponenta podpira le en primerek deCONZ", "updated_instance": "Posodobljen deCONZ z novim naslovom gostitelja" }, "error": { diff --git a/homeassistant/components/deconz/translations/sv.json b/homeassistant/components/deconz/translations/sv.json index 795a2464ad9..225b9f0b4e3 100644 --- a/homeassistant/components/deconz/translations/sv.json +++ b/homeassistant/components/deconz/translations/sv.json @@ -5,7 +5,6 @@ "already_in_progress": "Konfigurations fl\u00f6det f\u00f6r bryggan p\u00e5g\u00e5r redan.", "no_bridges": "Inga deCONZ-bryggor uppt\u00e4cktes", "not_deconz_bridge": "Inte en deCONZ-brygga", - "one_instance_only": "Komponenten st\u00f6djer endast en deCONZ-instans", "updated_instance": "Uppdaterad deCONZ-instans med ny v\u00e4rdadress" }, "error": { diff --git a/homeassistant/components/deconz/translations/vi.json b/homeassistant/components/deconz/translations/vi.json index ad4ff457a77..5d18501caec 100644 --- a/homeassistant/components/deconz/translations/vi.json +++ b/homeassistant/components/deconz/translations/vi.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "C\u1ea7u \u0111\u00e3 \u0111\u01b0\u1ee3c c\u1ea5u h\u00ecnh", - "no_bridges": "Kh\u00f4ng t\u00ecm th\u1ea5y c\u1ea7u deCONZ n\u00e0o", - "one_instance_only": "Th\u00e0nh ph\u1ea7n ch\u1ec9 h\u1ed7 tr\u1ee3 m\u1ed9t c\u00e1 th\u1ec3 deCONZ" + "no_bridges": "Kh\u00f4ng t\u00ecm th\u1ea5y c\u1ea7u deCONZ n\u00e0o" }, "error": { "no_key": "Kh\u00f4ng th\u1ec3 l\u1ea5y kh\u00f3a API" diff --git a/homeassistant/components/deconz/translations/zh-Hans.json b/homeassistant/components/deconz/translations/zh-Hans.json index 57993237696..a85ed6d72ca 100644 --- a/homeassistant/components/deconz/translations/zh-Hans.json +++ b/homeassistant/components/deconz/translations/zh-Hans.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "\u6865\u63a5\u5668\u5df2\u914d\u7f6e\u5b8c\u6210", - "no_bridges": "\u6ca1\u6709\u53d1\u73b0 deCONZ \u7684\u6865\u63a5\u8bbe\u5907", - "one_instance_only": "\u7ec4\u4ef6\u53ea\u652f\u6301\u4e00\u4e2a deCONZ \u5b9e\u4f8b" + "no_bridges": "\u6ca1\u6709\u53d1\u73b0 deCONZ \u7684\u6865\u63a5\u8bbe\u5907" }, "error": { "no_key": "\u65e0\u6cd5\u83b7\u53d6 API \u5bc6\u94a5" diff --git a/homeassistant/components/deconz/translations/zh-Hant.json b/homeassistant/components/deconz/translations/zh-Hant.json index 1ae61f03ffd..f6695fc2af9 100644 --- a/homeassistant/components/deconz/translations/zh-Hant.json +++ b/homeassistant/components/deconz/translations/zh-Hant.json @@ -6,7 +6,6 @@ "no_bridges": "\u672a\u641c\u5c0b\u5230 deCONZ Bridfe", "no_hardware_available": "deCONZ \u6c92\u6709\u4efb\u4f55\u7121\u7dda\u96fb\u8a2d\u5099\u9023\u7dda", "not_deconz_bridge": "\u975e deCONZ Bridge \u8a2d\u5099", - "one_instance_only": "\u7d44\u4ef6\u50c5\u652f\u63f4\u4e00\u7d44 deCONZ \u7269\u4ef6", "updated_instance": "\u4f7f\u7528\u65b0\u4e3b\u6a5f\u7aef\u4f4d\u5740\u66f4\u65b0 deCONZ \u8a2d\u5099" }, "error": { diff --git a/homeassistant/components/demo/translations/cs.json b/homeassistant/components/demo/translations/cs.json index 1a9e6570085..1bac6710266 100644 --- a/homeassistant/components/demo/translations/cs.json +++ b/homeassistant/components/demo/translations/cs.json @@ -3,6 +3,7 @@ "step": { "options_1": { "data": { + "constant": "Konstanta", "int": "\u010c\u00edseln\u00fd vstup" } }, diff --git a/homeassistant/components/demo/translations/pl.json b/homeassistant/components/demo/translations/pl.json index fb1da06bc1a..bc9e6701c65 100644 --- a/homeassistant/components/demo/translations/pl.json +++ b/homeassistant/components/demo/translations/pl.json @@ -12,7 +12,7 @@ "options_1": { "data": { "bool": "Warto\u015b\u0107 logiczna", - "constant": "Sta\u0142y(-a)", + "constant": "Sta\u0142a", "int": "Warto\u015b\u0107 numeryczna" } }, diff --git a/homeassistant/components/denon/media_player.py b/homeassistant/components/denon/media_player.py index ed90c2ddcb0..b909dc7c070 100644 --- a/homeassistant/components/denon/media_player.py +++ b/homeassistant/components/denon/media_player.py @@ -230,7 +230,7 @@ class DenonDevice(MediaPlayerEntity): @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/denonavr/translations/ca.json b/homeassistant/components/denonavr/translations/ca.json index c11bbbf7ce1..01f91f894c2 100644 --- a/homeassistant/components/denonavr/translations/ca.json +++ b/homeassistant/components/denonavr/translations/ca.json @@ -4,7 +4,6 @@ "already_configured": "El dispositiu ja est\u00e0 configurat", "already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs", "cannot_connect": "No s'ha pogut connectar, torna-ho a provar. Pot ser \u00fatil desconnectar i tornar a connectar els cables d'Ethernet i d'alimentaci\u00f3", - "connection_error": "No s'ha pogut connectar, torna-ho a provar. \u00c9s possible que s'arregli si desconnectes i tornes a connectar els cables d'Ethernet i d'alimentaci\u00f3.", "not_denonavr_manufacturer": "No \u00e9s un receptor de xarxa Denon AVR, no coincideix el fabricant descobert", "not_denonavr_missing": "No \u00e9s un receptor de xarxa Denon AVR, informaci\u00f3 de descobriment no completa" }, diff --git a/homeassistant/components/denonavr/translations/cs.json b/homeassistant/components/denonavr/translations/cs.json index 0572ece02be..1c66dae10f0 100644 --- a/homeassistant/components/denonavr/translations/cs.json +++ b/homeassistant/components/denonavr/translations/cs.json @@ -4,9 +4,18 @@ "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", "cannot_connect": "P\u0159ipojen\u00ed se nezda\u0159ilo, zkuste to pros\u00edm znovu - odpojen\u00ed napajec\u00edch a ethernetov\u00fdch kabel\u016f a jejich op\u011btovn\u00e9 p\u0159ipojen\u00ed m\u016f\u017ee pomoci", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit, zkuste to pros\u00edm znovu - m\u016f\u017ee pomoci odpojen\u00ed a op\u011btovn\u00e9 p\u0159ipojen\u00ed nap\u00e1jec\u00edho a ethernetov\u00e9ho kabelu" + "not_denonavr_manufacturer": "Nejedn\u00e1 se o s\u00ed\u0165ov\u00fd p\u0159ij\u00edma\u010d Denon AVR, objeven\u00fd v\u00fdrobce se neshoduje", + "not_denonavr_missing": "Nejedn\u00e1 se o s\u00ed\u0165ov\u00fd p\u0159ij\u00edma\u010d Denon AVR, informace o zji\u0161\u0165ov\u00e1n\u00ed nejsou \u00fapln\u00e9" }, + "error": { + "discovery_error": "Nepoda\u0159ilo se naj\u00edt s\u00ed\u0165ov\u00fd p\u0159ij\u00edma\u010d Denon AVR" + }, + "flow_title": "S\u00ed\u0165ov\u00fd p\u0159ij\u00edma\u010d Denon AVR: {name}", "step": { + "confirm": { + "description": "Potvr\u010fte pros\u00edm p\u0159id\u00e1n\u00ed p\u0159ij\u00edma\u010de", + "title": "S\u00ed\u0165ov\u00e9 p\u0159ij\u00edma\u010de Denon AVR" + }, "user": { "data": { "host": "IP adresa" diff --git a/homeassistant/components/denonavr/translations/de.json b/homeassistant/components/denonavr/translations/de.json index 4fd05d6c578..5af7d3393e2 100644 --- a/homeassistant/components/denonavr/translations/de.json +++ b/homeassistant/components/denonavr/translations/de.json @@ -1,6 +1,11 @@ { "config": { "step": { + "select": { + "data": { + "select_host": "IP-Adresse des Empf\u00e4ngers" + } + }, "user": { "data": { "host": "IP-Adresse" diff --git a/homeassistant/components/denonavr/translations/en.json b/homeassistant/components/denonavr/translations/en.json index b3d7d74b8a1..8c8f26d9b8c 100644 --- a/homeassistant/components/denonavr/translations/en.json +++ b/homeassistant/components/denonavr/translations/en.json @@ -4,7 +4,6 @@ "already_configured": "Device is already configured", "already_in_progress": "Configuration flow is already in progress", "cannot_connect": "Failed to connect, please try again, disconnecting mains power and ethernet cables and reconnecting them may help", - "connection_error": "Failed to connect, please try again, disconnecting mains power and ethernet cables and reconnecting them may help", "not_denonavr_manufacturer": "Not a Denon AVR Network Receiver, discovered manafucturer did not match", "not_denonavr_missing": "Not a Denon AVR Network Receiver, discovery information not complete" }, diff --git a/homeassistant/components/denonavr/translations/es.json b/homeassistant/components/denonavr/translations/es.json index a240420bb1e..83478ff42a1 100644 --- a/homeassistant/components/denonavr/translations/es.json +++ b/homeassistant/components/denonavr/translations/es.json @@ -3,7 +3,7 @@ "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado", "already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en proceso", - "connection_error": "Fallo en la conexi\u00f3n, por favor int\u00e9ntalo de nuevo, desconectar la alimentaci\u00f3n y los cables de ethernet y reconectarlos puede ayudar.", + "cannot_connect": "Fallo en la conexi\u00f3n, por favor int\u00e9ntelo de nuevo, desconectar la alimentaci\u00f3n y los cables de ethernet y reconectarlos puede ayudar.", "not_denonavr_manufacturer": "No es un Receptor AVR Denon AVR en Red, el fabricante detectado no concuerda", "not_denonavr_missing": "No es un Receptor AVR Denon AVR en Red, la informaci\u00f3n detectada no est\u00e1 completa" }, diff --git a/homeassistant/components/denonavr/translations/et.json b/homeassistant/components/denonavr/translations/et.json index a8f2fceb897..9f793f03023 100644 --- a/homeassistant/components/denonavr/translations/et.json +++ b/homeassistant/components/denonavr/translations/et.json @@ -4,7 +4,11 @@ "already_configured": "Seade on juba h\u00e4\u00e4lestatud", "already_in_progress": "Seadistamine on juba k\u00e4imas", "cannot_connect": "\u00dchenduse loomine nurjus. Vooluv\u00f5rgust ja LAN v\u00f5rgust eemaldamine ja taas\u00fchendamine v\u00f5ib aidata", - "connection_error": "\u00dchenduse loomine nurjus. Vooluv\u00f5rgust ja LAN v\u00f5rgust eemaldamine ja taas\u00fchendamine v\u00f5ib aidata" + "not_denonavr_manufacturer": "Pole Denoni AVR Network Receiver, avastatud tootja pole \u00f5ige", + "not_denonavr_missing": "Pole Denoni AVR Network Receiver, avastamisteave pole t\u00e4ielik" + }, + "error": { + "discovery_error": "Denon AVR Network Receiver'i avastamine nurjus" }, "flow_title": "Denon AVR v\u00f5rguvastuv\u00f5tja: {nimi}", "step": { @@ -14,7 +18,7 @@ }, "select": { "data": { - "select_host": "Ressiiveri IP" + "select_host": "Ressiiveri IP aadress" }, "description": "Kui soovid t\u00e4iendavaid vastuv\u00f5tjaid \u00fchendada, k\u00e4ivitad seadistamine uuesti", "title": "Valivastuv\u00f5tja, millega soovid \u00fchenduda" diff --git a/homeassistant/components/denonavr/translations/fr.json b/homeassistant/components/denonavr/translations/fr.json index 09c7abf93ac..16183c90c17 100644 --- a/homeassistant/components/denonavr/translations/fr.json +++ b/homeassistant/components/denonavr/translations/fr.json @@ -3,7 +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", - "connection_error": "\u00c9chec de la connexion, veuillez r\u00e9essayer, d\u00e9brancher l'alimentation secteur et les c\u00e2bles ethernet et les reconnecter peut aider", + "cannot_connect": "\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/denonavr/translations/it.json b/homeassistant/components/denonavr/translations/it.json index 9fc4e3cf90f..3d994456f8d 100644 --- a/homeassistant/components/denonavr/translations/it.json +++ b/homeassistant/components/denonavr/translations/it.json @@ -3,7 +3,7 @@ "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso", - "connection_error": "Impossibile connettersi, si prega di riprovare, pu\u00f2 essere utile scollegare i cavi di alimentazione ed i cavi Ethernet e ricollegarli", + "cannot_connect": "Impossibile connettersi, riprovare, scollegare l'alimentazione della rete elettrica e i cavi ethernet e ricollegarli potrebbe essere d'aiuto", "not_denonavr_manufacturer": "Non \u00e8 un ricevitore di rete Denon AVR, il produttore rilevato non corrisponde", "not_denonavr_missing": "Non \u00e8 un ricevitore di rete Denon AVR, le informazioni di rilevamento non sono complete" }, @@ -18,7 +18,7 @@ }, "select": { "data": { - "select_host": "IP del ricevitore" + "select_host": "Indirizzo IP del ricevitore" }, "description": "Eseguire nuovamente il setup se si desidera collegare altri ricevitori", "title": "Selezionare il ricevitore che si desidera collegare" diff --git a/homeassistant/components/denonavr/translations/ko.json b/homeassistant/components/denonavr/translations/ko.json index 02377f982ee..f995b852a57 100644 --- a/homeassistant/components/denonavr/translations/ko.json +++ b/homeassistant/components/denonavr/translations/ko.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "already_in_progress": "Denon AVR \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4.", - "connection_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694. \uc8fc \uc804\uc6d0 \ubc0f \uc774\ub354\ub137 \ucf00\uc774\ube14\uc758 \uc5f0\uacb0\uc744 \ub04a\uc5c8\ub2e4\uac00 \ub2e4\uc2dc \uc5f0\uacb0\ud558\ub294 \uac83\uc774 \ub3c4\uc6c0\uc774 \ub420 \uc218 \uc788\uc2b5\ub2c8\ub2e4", "not_denonavr_manufacturer": "Denon AVR \ub124\ud2b8\uc6cc\ud06c \ub9ac\uc2dc\ubc84\uac00 \uc544\ub2d9\ub2c8\ub2e4. \ubc1c\uacac\ub41c \uc81c\uc870\uc0ac\uac00 \uc77c\uce58\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4", "not_denonavr_missing": "Denon AVR \ub124\ud2b8\uc6cc\ud06c \ub9ac\uc2dc\ubc84\uac00 \uc544\ub2d9\ub2c8\ub2e4. \uac80\uc0c9 \uc815\ubcf4\uac00 \uc644\uc804\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4" }, diff --git a/homeassistant/components/denonavr/translations/lb.json b/homeassistant/components/denonavr/translations/lb.json index 8b2580209a1..fd8ece3c0bc 100644 --- a/homeassistant/components/denonavr/translations/lb.json +++ b/homeassistant/components/denonavr/translations/lb.json @@ -2,8 +2,8 @@ "config": { "abort": { "already_configured": "Apparat ass scho konfigur\u00e9iert", - "already_in_progress": "Konfiguratioun fir d\u00ebsen Denon AVR ass schonn am gaang.", - "connection_error": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaang", + "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol. Stroumkabel an R\u00e9seau Kabel rausz\u00e9ien an drastiechen k\u00e9int h\u00ebllefen.", "not_denonavr_manufacturer": "Kee Denon AVR Netzwierk Empf\u00e4nger, entdeckte Hiersteller passt net", "not_denonavr_missing": "Kee Denon AVR Netzwierk Empf\u00e4nger, Discovery Informatioun net vollst\u00e4nneg" }, @@ -18,7 +18,7 @@ }, "select": { "data": { - "select_host": "IP vum Receiver" + "select_host": "IP Adresse vum Receiver" }, "description": "Start den Setup nach eemol falls nach zous\u00e4tzlech Receiver solle verbonne ginn", "title": "Wielt de Receiver aus dee soll verbonne ginn" diff --git a/homeassistant/components/denonavr/translations/nl.json b/homeassistant/components/denonavr/translations/nl.json index bd7efabf1c7..eac5783809c 100644 --- a/homeassistant/components/denonavr/translations/nl.json +++ b/homeassistant/components/denonavr/translations/nl.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "connection_error": "Kan geen verbinding maken, probeer het opnieuw, het kan helpen om de netvoeding en ethernetkabels los te koppelen en opnieuw aan te sluiten" + "already_configured": "Apparaat is al geconfigureerd" }, "flow_title": "Denon AVR Network Receiver: {naam}", "step": { @@ -12,12 +12,14 @@ "data": { "select_host": "Receiver IP-adres" }, + "description": "Voer de installatie opnieuw uit als u extra ontvangers wilt aansluiten", "title": "Selecteer de receiver waarmee u verbinding wilt maken" }, "user": { "data": { "host": "IP-adres" - } + }, + "description": "Maak verbinding met uw ontvanger. Als het IP-adres niet is ingesteld, wordt automatische detectie gebruikt" } } }, diff --git a/homeassistant/components/denonavr/translations/no.json b/homeassistant/components/denonavr/translations/no.json index 5e0018118e9..93afb82e3c1 100644 --- a/homeassistant/components/denonavr/translations/no.json +++ b/homeassistant/components/denonavr/translations/no.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Enheten er allerede konfigurert", "already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede", - "cannot_connect": "Kunne ikke koble til, vennligst pr\u00f8v igjen. Det kan hjelpe \u00e5 koble fra str\u00f8m- og Ethernet-kabler og koble dem til igjen", - "connection_error": "Kunne ikke koble til, vennligst pr\u00f8v igjen. Det kan hjelpe \u00e5 koble fra str\u00f8m- og Ethernet-kabler og koble dem til igjen", + "cannot_connect": "[%key:component::denonavr::config::abort::connection_error%]", "not_denonavr_manufacturer": "Ikke en Denon AVR Network Receiver, oppdaget manafucturer stemte ikke overens", "not_denonavr_missing": "Ikke en Denon AVR Network Receiver, oppdagelsesinformasjon ikke fullf\u00f8rt" }, diff --git a/homeassistant/components/denonavr/translations/pl.json b/homeassistant/components/denonavr/translations/pl.json index b96d02240c0..19061bf5252 100644 --- a/homeassistant/components/denonavr/translations/pl.json +++ b/homeassistant/components/denonavr/translations/pl.json @@ -4,7 +4,6 @@ "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "already_in_progress": "Konfiguracja jest ju\u017c w toku", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia, spr\u00f3buj ponownie. Od\u0142\u0105czenie zasilania oraz kabla sieciowego i ponowne ich pod\u0142\u0105czenie mo\u017ce pom\u00f3c.", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia, spr\u00f3buj ponownie. Od\u0142\u0105czenie zasilania oraz kabla sieciowego i ponowne ich pod\u0142\u0105czenie mo\u017ce pom\u00f3c.", "not_denonavr_manufacturer": "Nie jest to urz\u0105dzenie AVR firmy Denon, producent wykrytego urz\u0105dzenia nie pasuje", "not_denonavr_missing": "Nie jest to urz\u0105dzenie AVR firmy Denon, dane z automatycznego wykrywania nie s\u0105 kompletne" }, diff --git a/homeassistant/components/denonavr/translations/ru.json b/homeassistant/components/denonavr/translations/ru.json index c16d5d0a250..f914d83bfa2 100644 --- a/homeassistant/components/denonavr/translations/ru.json +++ b/homeassistant/components/denonavr/translations/ru.json @@ -4,7 +4,6 @@ "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437. \u0415\u0441\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442\u0441\u044f, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u0430\u0431\u0435\u043b\u044c Ethernet \u0438 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043a\u0430\u0431\u0435\u043b\u044c.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437. \u0415\u0441\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442\u0441\u044f, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u0430\u0431\u0435\u043b\u044c Ethernet \u0438 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043a\u0430\u0431\u0435\u043b\u044c.", "not_denonavr_manufacturer": "\u042d\u0442\u043e \u043d\u0435 \u0440\u0435\u0441\u0438\u0432\u0435\u0440 Denon. \u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442.", "not_denonavr_missing": "\u041d\u0435\u043f\u043e\u043b\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430." }, diff --git a/homeassistant/components/denonavr/translations/zh-Hant.json b/homeassistant/components/denonavr/translations/zh-Hant.json index ad398ceee44..fab16780a57 100644 --- a/homeassistant/components/denonavr/translations/zh-Hant.json +++ b/homeassistant/components/denonavr/translations/zh-Hant.json @@ -4,7 +4,6 @@ "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d", "cannot_connect": "\u9023\u7dda\u5931\u6557\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002\u95dc\u9589\u4e3b\u96fb\u6e90\u3001\u5c07\u4e59\u592a\u7db2\u8def\u65b7\u7dda\u5f8c\u91cd\u65b0\u9023\u7dda\uff0c\u53ef\u80fd\u6703\u6709\u6240\u5e6b\u52a9", - "connection_error": "\u9023\u7dda\u5931\u6557\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002\u95dc\u9589\u4e3b\u96fb\u6e90\u3001\u5c07\u4e59\u592a\u7db2\u8def\u65b7\u7dda\u5f8c\u91cd\u65b0\u9023\u7dda\uff0c\u53ef\u80fd\u6703\u6709\u6240\u5e6b\u52a9", "not_denonavr_manufacturer": "\u4e26\u975e Denon AVR \u7db2\u8def\u63a5\u6536\u5668\uff0c\u6240\u63a2\u7d22\u4e4b\u88fd\u9020\u5ee0\u5546\u4e0d\u7b26\u5408", "not_denonavr_missing": "\u4e26\u975e Denon AVR \u7db2\u8def\u63a5\u6536\u5668\uff0c\u63a2\u7d22\u8cc7\u8a0a\u4e0d\u5b8c\u6574" }, diff --git a/homeassistant/components/device_tracker/device_trigger.py b/homeassistant/components/device_tracker/device_trigger.py new file mode 100644 index 00000000000..2c92304a246 --- /dev/null +++ b/homeassistant/components/device_tracker/device_trigger.py @@ -0,0 +1,105 @@ +"""Provides device automations for Device Tracker.""" +from typing import List + +import voluptuous as vol + +from homeassistant.components.automation import AutomationActionType +from homeassistant.components.device_automation import TRIGGER_BASE_SCHEMA +from homeassistant.components.zone import DOMAIN as DOMAIN_ZONE, trigger as zone +from homeassistant.const import ( + CONF_DEVICE_ID, + CONF_DOMAIN, + CONF_ENTITY_ID, + CONF_EVENT, + CONF_PLATFORM, + CONF_TYPE, + CONF_ZONE, +) +from homeassistant.core import CALLBACK_TYPE, HomeAssistant +from homeassistant.helpers import config_validation as cv, entity_registry +from homeassistant.helpers.typing import ConfigType + +from . import DOMAIN + +TRIGGER_TYPES = {"enters", "leaves"} + +TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend( + { + vol.Required(CONF_ENTITY_ID): cv.entity_id, + vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES), + vol.Required(CONF_ZONE): cv.entity_domain(DOMAIN_ZONE), + } +) + + +async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]: + """List device triggers for Device Tracker devices.""" + registry = await entity_registry.async_get_registry(hass) + triggers = [] + + # Get all the integrations entities for this device + for entry in entity_registry.async_entries_for_device(registry, device_id): + if entry.domain != DOMAIN: + continue + + triggers.append( + { + CONF_PLATFORM: "device", + CONF_DEVICE_ID: device_id, + CONF_DOMAIN: DOMAIN, + CONF_ENTITY_ID: entry.entity_id, + CONF_TYPE: "enters", + } + ) + triggers.append( + { + CONF_PLATFORM: "device", + CONF_DEVICE_ID: device_id, + CONF_DOMAIN: DOMAIN, + CONF_ENTITY_ID: entry.entity_id, + CONF_TYPE: "leaves", + } + ) + + return triggers + + +async def async_attach_trigger( + hass: HomeAssistant, + config: ConfigType, + action: AutomationActionType, + automation_info: dict, +) -> CALLBACK_TYPE: + """Attach a trigger.""" + config = TRIGGER_SCHEMA(config) + + if config[CONF_TYPE] == "enters": + event = zone.EVENT_ENTER + else: + event = zone.EVENT_LEAVE + + zone_config = { + CONF_PLATFORM: DOMAIN_ZONE, + CONF_ENTITY_ID: config[CONF_ENTITY_ID], + CONF_ZONE: config[CONF_ZONE], + CONF_EVENT: event, + } + zone_config = zone.TRIGGER_SCHEMA(zone_config) + return await zone.async_attach_trigger( + hass, zone_config, action, automation_info, platform_type="device" + ) + + +async def async_get_trigger_capabilities(hass: HomeAssistant, config: ConfigType): + """List trigger capabilities.""" + zones = { + ent.entity_id: ent.name + for ent in sorted(hass.states.async_all(DOMAIN_ZONE), key=lambda ent: ent.name) + } + return { + "extra_fields": vol.Schema( + { + vol.Required(CONF_ZONE): vol.In(zones), + } + ) + } diff --git a/homeassistant/components/device_tracker/strings.json b/homeassistant/components/device_tracker/strings.json index 58aef884536..5d492ea8e79 100644 --- a/homeassistant/components/device_tracker/strings.json +++ b/homeassistant/components/device_tracker/strings.json @@ -4,6 +4,10 @@ "condition_type": { "is_home": "{entity_name} is home", "is_not_home": "{entity_name} is not home" + }, + "trigger_type": { + "enters": "{entity_name} enters a zone", + "leaves": "{entity_name} leaves a zone" } }, "state": { @@ -12,4 +16,4 @@ "not_home": "[%key:common::state::not_home%]" } } -} +} \ No newline at end of file diff --git a/homeassistant/components/device_tracker/translations/ca.json b/homeassistant/components/device_tracker/translations/ca.json index d2fc2103691..a64eb81f8ff 100644 --- a/homeassistant/components/device_tracker/translations/ca.json +++ b/homeassistant/components/device_tracker/translations/ca.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} \u00e9s a casa", "is_not_home": "{entity_name} no \u00e9s a casa" + }, + "trigger_type": { + "enters": "{entity_name} entri a una zona", + "leaves": "{entity_name} surti d'una zona" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/cs.json b/homeassistant/components/device_tracker/translations/cs.json index ed1923ceb07..1f33d4df2e7 100644 --- a/homeassistant/components/device_tracker/translations/cs.json +++ b/homeassistant/components/device_tracker/translations/cs.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} je doma", "is_not_home": "{entity_name} nen\u00ed doma" + }, + "trigger_type": { + "enters": "{entity_name} vstupuje do z\u00f3ny", + "leaves": "{entity_name} opou\u0161t\u00ed z\u00f3nu" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/en.json b/homeassistant/components/device_tracker/translations/en.json index dad3e1d52b7..753efb0e3be 100644 --- a/homeassistant/components/device_tracker/translations/en.json +++ b/homeassistant/components/device_tracker/translations/en.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} is home", "is_not_home": "{entity_name} is not home" + }, + "trigger_type": { + "enters": "{entity_name} enters a zone", + "leaves": "{entity_name} leaves a zone" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/es.json b/homeassistant/components/device_tracker/translations/es.json index 60bb86fbd27..eccef30e765 100644 --- a/homeassistant/components/device_tracker/translations/es.json +++ b/homeassistant/components/device_tracker/translations/es.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} est\u00e1 en casa", "is_not_home": "{entity_name} no est\u00e1 en casa" + }, + "trigger_type": { + "enters": "{entity_name} entra en una zona", + "leaves": "{entity_name} abandona una zona" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/et.json b/homeassistant/components/device_tracker/translations/et.json index c4f2b6f277d..2a619a0d447 100644 --- a/homeassistant/components/device_tracker/translations/et.json +++ b/homeassistant/components/device_tracker/translations/et.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} on kodus", "is_not_home": "{entity_name} on eemal" + }, + "trigger_type": { + "enters": "{entity_name} siseneb tsooni", + "leaves": "{entity_name} lahkub tsoonist" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/fr.json b/homeassistant/components/device_tracker/translations/fr.json index 14cbd04871c..d5af1475cd1 100644 --- a/homeassistant/components/device_tracker/translations/fr.json +++ b/homeassistant/components/device_tracker/translations/fr.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} est \u00e0 la maison", "is_not_home": "{entity_name} n'est pas \u00e0 la maison" + }, + "trigger_type": { + "enters": "{entity_name} entre dans une zone", + "leaves": "{entity_name} quitte une zone" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/it.json b/homeassistant/components/device_tracker/translations/it.json index 1a59a123072..92ccce1c1c5 100644 --- a/homeassistant/components/device_tracker/translations/it.json +++ b/homeassistant/components/device_tracker/translations/it.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} \u00e8 in casa", "is_not_home": "{entity_name} non \u00e8 in casa" + }, + "trigger_type": { + "enters": "{entity_name} entra in una zona", + "leaves": "{entity_name} lascia una zona" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/no.json b/homeassistant/components/device_tracker/translations/no.json index 56ef663e6c6..f526dce2615 100644 --- a/homeassistant/components/device_tracker/translations/no.json +++ b/homeassistant/components/device_tracker/translations/no.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} er hjemme", "is_not_home": "{entity_name} er ikke hjemme" + }, + "trigger_type": { + "enters": "{entity_name} g\u00e5r inn i en sone", + "leaves": "{entity_name} forlater en sone" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/pl.json b/homeassistant/components/device_tracker/translations/pl.json index 94cc3d97138..c85283ab81b 100644 --- a/homeassistant/components/device_tracker/translations/pl.json +++ b/homeassistant/components/device_tracker/translations/pl.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "urz\u0105dzenie {entity_name} jest w domu", "is_not_home": "urz\u0105dzenie {entity_name} jest poza domem" + }, + "trigger_type": { + "enters": "{entity_name} wejdzie do strefy", + "leaves": "{entity_name} opu\u015bci stref\u0119" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/ru.json b/homeassistant/components/device_tracker/translations/ru.json index 8ea3398e3e2..9efd5b78047 100644 --- a/homeassistant/components/device_tracker/translations/ru.json +++ b/homeassistant/components/device_tracker/translations/ru.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name} \u0434\u043e\u043c\u0430", "is_not_home": "{entity_name} \u043d\u0435 \u0434\u043e\u043c\u0430" + }, + "trigger_type": { + "enters": "{entity_name} \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0437\u043e\u043d\u0443", + "leaves": "{entity_name} \u043f\u043e\u043a\u0438\u0434\u0430\u0435\u0442 \u0437\u043e\u043d\u0443" } }, "state": { diff --git a/homeassistant/components/device_tracker/translations/zh-Hant.json b/homeassistant/components/device_tracker/translations/zh-Hant.json index b1d3e1a1779..e80c32afd01 100644 --- a/homeassistant/components/device_tracker/translations/zh-Hant.json +++ b/homeassistant/components/device_tracker/translations/zh-Hant.json @@ -3,6 +3,10 @@ "condition_type": { "is_home": "{entity_name}\u5728\u5bb6", "is_not_home": "{entity_name}\u4e0d\u5728\u5bb6" + }, + "trigger_type": { + "enters": "{entity_name} \u9032\u5165\u5340\u57df", + "leaves": "{entity_name} \u96e2\u958b\u5340\u57df" } }, "state": { diff --git a/homeassistant/components/devolo_home_control/__init__.py b/homeassistant/components/devolo_home_control/__init__.py index f1f00e9abe7..96d52b57e85 100644 --- a/homeassistant/components/devolo_home_control/__init__.py +++ b/homeassistant/components/devolo_home_control/__init__.py @@ -2,6 +2,7 @@ import asyncio from functools import partial +from devolo_home_control_api.exceptions.gateway import GatewayOfflineError from devolo_home_control_api.homecontrol import HomeControl from devolo_home_control_api.mydevolo import Mydevolo @@ -11,7 +12,7 @@ from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, EVENT_HOMEASSISTAN from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.typing import HomeAssistantType -from .const import CONF_HOMECONTROL, CONF_MYDEVOLO, DOMAIN, PLATFORMS +from .const import CONF_MYDEVOLO, DOMAIN, PLATFORMS async def async_setup(hass, config): @@ -23,11 +24,8 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool """Set up the devolo account from a config entry.""" conf = entry.data hass.data.setdefault(DOMAIN, {}) - try: - mydevolo = Mydevolo.get_instance() - except SyntaxError: - mydevolo = Mydevolo() + mydevolo = Mydevolo() mydevolo.user = conf[CONF_USERNAME] mydevolo.password = conf[CONF_PASSWORD] mydevolo.url = conf[CONF_MYDEVOLO] @@ -41,19 +39,22 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool raise ConfigEntryNotReady gateway_ids = await hass.async_add_executor_job(mydevolo.get_gateway_ids) - gateway_id = gateway_ids[0] try: zeroconf_instance = await zeroconf.async_get_instance(hass) - hass.data[DOMAIN]["homecontrol"] = await hass.async_add_executor_job( - partial( - HomeControl, - gateway_id=gateway_id, - zeroconf_instance=zeroconf_instance, - url=conf[CONF_HOMECONTROL], + hass.data[DOMAIN][entry.entry_id] = {"gateways": [], "listener": None} + for gateway_id in gateway_ids: + hass.data[DOMAIN][entry.entry_id]["gateways"].append( + await hass.async_add_executor_job( + partial( + HomeControl, + gateway_id=gateway_id, + mydevolo_instance=mydevolo, + zeroconf_instance=zeroconf_instance, + ) + ) ) - ) - except ConnectionError as err: + except (ConnectionError, GatewayOfflineError) as err: raise ConfigEntryNotReady from err for platform in PLATFORMS: @@ -62,29 +63,35 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool ) def shutdown(event): - hass.data[DOMAIN]["homecontrol"].websocket_disconnect( - f"websocket disconnect requested by {EVENT_HOMEASSISTANT_STOP}" - ) + for gateway in hass.data[DOMAIN][entry.entry_id]["gateways"]: + gateway.websocket_disconnect( + f"websocket disconnect requested by {EVENT_HOMEASSISTANT_STOP}" + ) # Listen when EVENT_HOMEASSISTANT_STOP is fired - hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, shutdown) + hass.data[DOMAIN][entry.entry_id]["listener"] = hass.bus.async_listen_once( + EVENT_HOMEASSISTANT_STOP, shutdown + ) return True -async def async_unload_entry(hass, config_entry): +async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool: """Unload a config entry.""" unload = all( await asyncio.gather( *[ - hass.config_entries.async_forward_entry_unload(config_entry, platform) + hass.config_entries.async_forward_entry_unload(entry, platform) for platform in PLATFORMS ] ) ) - - await hass.async_add_executor_job( - hass.data[DOMAIN]["homecontrol"].websocket_disconnect + await asyncio.gather( + *[ + hass.async_add_executor_job(gateway.websocket_disconnect) + for gateway in hass.data[DOMAIN][entry.entry_id]["gateways"] + ] ) - del hass.data[DOMAIN]["homecontrol"] + hass.data[DOMAIN][entry.entry_id]["listener"]() + hass.data[DOMAIN].pop(entry.entry_id) return unload diff --git a/homeassistant/components/devolo_home_control/binary_sensor.py b/homeassistant/components/devolo_home_control/binary_sensor.py index 1d581d2c0fb..200b24ac7ff 100644 --- a/homeassistant/components/devolo_home_control/binary_sensor.py +++ b/homeassistant/components/devolo_home_control/binary_sensor.py @@ -28,29 +28,30 @@ async def async_setup_entry( """Get all binary sensor and multi level sensor devices and setup them via config entry.""" entities = [] - for device in hass.data[DOMAIN]["homecontrol"].binary_sensor_devices: - for binary_sensor in device.binary_sensor_property: - entities.append( - DevoloBinaryDeviceEntity( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=binary_sensor, - ) - ) - for device in hass.data[DOMAIN]["homecontrol"].devices.values(): - if hasattr(device, "remote_control_property"): - for remote in device.remote_control_property: - for index in range( - 1, device.remote_control_property[remote].key_count + 1 - ): - entities.append( - DevoloRemoteControl( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=remote, - key=index, - ) + for gateway in hass.data[DOMAIN][entry.entry_id]["gateways"]: + for device in gateway.binary_sensor_devices: + for binary_sensor in device.binary_sensor_property: + entities.append( + DevoloBinaryDeviceEntity( + homecontrol=gateway, + device_instance=device, + element_uid=binary_sensor, ) + ) + for device in gateway.devices.values(): + if hasattr(device, "remote_control_property"): + for remote in device.remote_control_property: + for index in range( + 1, device.remote_control_property[remote].key_count + 1 + ): + entities.append( + DevoloRemoteControl( + homecontrol=gateway, + device_instance=device, + element_uid=remote, + key=index, + ) + ) async_add_entities(entities, False) diff --git a/homeassistant/components/devolo_home_control/climate.py b/homeassistant/components/devolo_home_control/climate.py index 0cc2340dc18..d333a5c7609 100644 --- a/homeassistant/components/devolo_home_control/climate.py +++ b/homeassistant/components/devolo_home_control/climate.py @@ -22,20 +22,21 @@ async def async_setup_entry( """Get all cover devices and setup them via config entry.""" entities = [] - for device in hass.data[DOMAIN]["homecontrol"].multi_level_switch_devices: - for multi_level_switch in device.multi_level_switch_property: - if device.device_model_uid in [ - "devolo.model.Thermostat:Valve", - "devolo.model.Room:Thermostat", - "devolo.model.Eurotronic:Spirit:Device", - ]: - entities.append( - DevoloClimateDeviceEntity( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=multi_level_switch, + for gateway in hass.data[DOMAIN][entry.entry_id]["gateways"]: + for device in gateway.multi_level_switch_devices: + for multi_level_switch in device.multi_level_switch_property: + if device.device_model_uid in [ + "devolo.model.Thermostat:Valve", + "devolo.model.Room:Thermostat", + "devolo.model.Eurotronic:Spirit:Device", + ]: + entities.append( + DevoloClimateDeviceEntity( + homecontrol=gateway, + device_instance=device, + element_uid=multi_level_switch, + ) ) - ) async_add_entities(entities, False) diff --git a/homeassistant/components/devolo_home_control/config_flow.py b/homeassistant/components/devolo_home_control/config_flow.py index cde55ebb4bf..67803ec56be 100644 --- a/homeassistant/components/devolo_home_control/config_flow.py +++ b/homeassistant/components/devolo_home_control/config_flow.py @@ -9,9 +9,7 @@ from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import callback from .const import ( # pylint:disable=unused-import - CONF_HOMECONTROL, CONF_MYDEVOLO, - DEFAULT_MPRM, DEFAULT_MYDEVOLO, DOMAIN, ) @@ -39,24 +37,18 @@ class DevoloHomeControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str, vol.Required(CONF_MYDEVOLO, default=DEFAULT_MYDEVOLO): str, - vol.Required(CONF_HOMECONTROL, default=DEFAULT_MPRM): str, } if user_input is None: return self._show_form(user_input) user = user_input[CONF_USERNAME] password = user_input[CONF_PASSWORD] - try: - mydevolo = Mydevolo.get_instance() - except SyntaxError: - mydevolo = Mydevolo() + mydevolo = Mydevolo() mydevolo.user = user mydevolo.password = password if self.show_advanced_options: mydevolo.url = user_input[CONF_MYDEVOLO] - mprm = user_input[CONF_HOMECONTROL] else: mydevolo.url = DEFAULT_MYDEVOLO - mprm = DEFAULT_MPRM credentials_valid = await self.hass.async_add_executor_job( mydevolo.credentials_valid ) @@ -73,7 +65,6 @@ class DevoloHomeControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): CONF_PASSWORD: password, CONF_USERNAME: user, CONF_MYDEVOLO: mydevolo.url, - CONF_HOMECONTROL: mprm, }, ) diff --git a/homeassistant/components/devolo_home_control/const.py b/homeassistant/components/devolo_home_control/const.py index 08f9f99079e..ea46ea44846 100644 --- a/homeassistant/components/devolo_home_control/const.py +++ b/homeassistant/components/devolo_home_control/const.py @@ -2,7 +2,5 @@ DOMAIN = "devolo_home_control" DEFAULT_MYDEVOLO = "https://www.mydevolo.com" -DEFAULT_MPRM = "https://homecontrol.mydevolo.com" PLATFORMS = ["binary_sensor", "climate", "cover", "light", "sensor", "switch"] CONF_MYDEVOLO = "mydevolo_url" -CONF_HOMECONTROL = "home_control_url" diff --git a/homeassistant/components/devolo_home_control/cover.py b/homeassistant/components/devolo_home_control/cover.py index 46f3df34314..7514a9b7c9f 100644 --- a/homeassistant/components/devolo_home_control/cover.py +++ b/homeassistant/components/devolo_home_control/cover.py @@ -19,16 +19,17 @@ async def async_setup_entry( """Get all cover devices and setup them via config entry.""" entities = [] - for device in hass.data[DOMAIN]["homecontrol"].multi_level_switch_devices: - for multi_level_switch in device.multi_level_switch_property: - if multi_level_switch.startswith("devolo.Blinds"): - entities.append( - DevoloCoverDeviceEntity( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=multi_level_switch, + for gateway in hass.data[DOMAIN][entry.entry_id]["gateways"]: + for device in gateway.multi_level_switch_devices: + for multi_level_switch in device.multi_level_switch_property: + if multi_level_switch.startswith("devolo.Blinds"): + entities.append( + DevoloCoverDeviceEntity( + homecontrol=gateway, + device_instance=device, + element_uid=multi_level_switch, + ) ) - ) async_add_entities(entities, False) diff --git a/homeassistant/components/devolo_home_control/light.py b/homeassistant/components/devolo_home_control/light.py index 9c532be2dc2..2a9be33223f 100644 --- a/homeassistant/components/devolo_home_control/light.py +++ b/homeassistant/components/devolo_home_control/light.py @@ -17,16 +17,17 @@ async def async_setup_entry( """Get all light devices and setup them via config entry.""" entities = [] - for device in hass.data[DOMAIN]["homecontrol"].multi_level_switch_devices: - for multi_level_switch in device.multi_level_switch_property.values(): - if multi_level_switch.switch_type == "dimmer": - entities.append( - DevoloLightDeviceEntity( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=multi_level_switch.element_uid, + for gateway in hass.data[DOMAIN][entry.entry_id]["gateways"]: + for device in gateway.multi_level_switch_devices: + for multi_level_switch in device.multi_level_switch_property.values(): + if multi_level_switch.switch_type == "dimmer": + entities.append( + DevoloLightDeviceEntity( + homecontrol=gateway, + device_instance=device, + element_uid=multi_level_switch.element_uid, + ) ) - ) async_add_entities(entities, False) diff --git a/homeassistant/components/devolo_home_control/manifest.json b/homeassistant/components/devolo_home_control/manifest.json index ce61fa121a4..0ffa991493c 100644 --- a/homeassistant/components/devolo_home_control/manifest.json +++ b/homeassistant/components/devolo_home_control/manifest.json @@ -2,7 +2,7 @@ "domain": "devolo_home_control", "name": "devolo Home Control", "documentation": "https://www.home-assistant.io/integrations/devolo_home_control", - "requirements": ["devolo-home-control-api==0.15.1"], + "requirements": ["devolo-home-control-api==0.16.0"], "after_dependencies": ["zeroconf"], "config_flow": true, "codeowners": ["@2Fake", "@Shutgun"], diff --git a/homeassistant/components/devolo_home_control/sensor.py b/homeassistant/components/devolo_home_control/sensor.py index c5ad9feb88a..e78b4eabeac 100644 --- a/homeassistant/components/devolo_home_control/sensor.py +++ b/homeassistant/components/devolo_home_control/sensor.py @@ -29,35 +29,37 @@ async def async_setup_entry( """Get all sensor devices and setup them via config entry.""" entities = [] - for device in hass.data[DOMAIN]["homecontrol"].multi_level_sensor_devices: - for multi_level_sensor in device.multi_level_sensor_property: - entities.append( - DevoloGenericMultiLevelDeviceEntity( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=multi_level_sensor, - ) - ) - for device in hass.data[DOMAIN]["homecontrol"].devices.values(): - if hasattr(device, "consumption_property"): - for consumption in device.consumption_property: - for consumption_type in ["current", "total"]: - entities.append( - DevoloConsumptionEntity( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=consumption, - consumption=consumption_type, - ) + for gateway in hass.data[DOMAIN][entry.entry_id]["gateways"]: + for device in gateway.multi_level_sensor_devices: + for multi_level_sensor in device.multi_level_sensor_property: + entities.append( + DevoloGenericMultiLevelDeviceEntity( + homecontrol=gateway, + device_instance=device, + element_uid=multi_level_sensor, ) - if hasattr(device, "battery_level"): - entities.append( - DevoloBatteryEntity( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=f"devolo.BatterySensor:{device.uid}", ) - ) + for device in gateway.devices.values(): + if hasattr(device, "consumption_property"): + for consumption in device.consumption_property: + for consumption_type in ["current", "total"]: + entities.append( + DevoloConsumptionEntity( + homecontrol=gateway, + device_instance=device, + element_uid=consumption, + consumption=consumption_type, + ) + ) + if hasattr(device, "battery_level"): + entities.append( + DevoloBatteryEntity( + homecontrol=gateway, + device_instance=device, + element_uid=f"devolo.BatterySensor:{device.uid}", + ) + ) + async_add_entities(entities, False) diff --git a/homeassistant/components/devolo_home_control/strings.json b/homeassistant/components/devolo_home_control/strings.json index 8c73831a229..7624beb531c 100644 --- a/homeassistant/components/devolo_home_control/strings.json +++ b/homeassistant/components/devolo_home_control/strings.json @@ -1,5 +1,4 @@ { - "title": "devolo Home Control", "config": { "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_account%]" @@ -14,8 +13,7 @@ "password": "[%key:common::config_flow::data::password%]", "mydevolo_url": "mydevolo [%key:common::config_flow::data::url%]", "home_control_url": "Home Control [%key:common::config_flow::data::url%]" - }, - "title": "devolo Home Control" + } } } } diff --git a/homeassistant/components/devolo_home_control/switch.py b/homeassistant/components/devolo_home_control/switch.py index 32da37bcc38..b4e070c50c8 100644 --- a/homeassistant/components/devolo_home_control/switch.py +++ b/homeassistant/components/devolo_home_control/switch.py @@ -11,21 +11,22 @@ async def async_setup_entry( hass: HomeAssistantType, entry: ConfigEntry, async_add_entities ) -> None: """Get all devices and setup the switch devices via config entry.""" - devices = hass.data[DOMAIN]["homecontrol"].binary_switch_devices - entities = [] - for device in devices: - for binary_switch in device.binary_switch_property: - # Exclude the binary switch which also has multi_level_switches here, - # because those are implemented as light entities now. - if not hasattr(device, "multi_level_switch_property"): - entities.append( - DevoloSwitch( - homecontrol=hass.data[DOMAIN]["homecontrol"], - device_instance=device, - element_uid=binary_switch, + + for gateway in hass.data[DOMAIN][entry.entry_id]["gateways"]: + for device in gateway.binary_switch_devices: + for binary_switch in device.binary_switch_property: + # Exclude the binary switch which also has multi_level_switches here, + # because those are implemented as light entities now. + if not hasattr(device, "multi_level_switch_property"): + entities.append( + DevoloSwitch( + homecontrol=gateway, + device_instance=device, + element_uid=binary_switch, + ) ) - ) + async_add_entities(entities) diff --git a/homeassistant/components/devolo_home_control/translations/ca.json b/homeassistant/components/devolo_home_control/translations/ca.json index 593c5098014..317e918c48a 100644 --- a/homeassistant/components/devolo_home_control/translations/ca.json +++ b/homeassistant/components/devolo_home_control/translations/ca.json @@ -4,8 +4,7 @@ "already_configured": "El compte ja ha estat configurat" }, "error": { - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Nom d'usuari i/o contrasenya incorrectes." + "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "URL de mydevolo", "password": "Contrasenya", "username": "Correu electr\u00f2nic / ID de devolo" - }, - "title": "Home Control devolo" + } } } - }, - "title": "Home Control devolo" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/cs.json b/homeassistant/components/devolo_home_control/translations/cs.json index 1df8420dd2f..efe2c4d2ce5 100644 --- a/homeassistant/components/devolo_home_control/translations/cs.json +++ b/homeassistant/components/devolo_home_control/translations/cs.json @@ -4,8 +4,7 @@ "already_configured": "\u00da\u010det je ji\u017e nastaven" }, "error": { - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Nespr\u00e1vn\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no nebo heslo." + "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "mydevolo URL", "password": "Heslo", "username": "E-mail / Devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/de.json b/homeassistant/components/devolo_home_control/translations/de.json index 456be47b3d8..112daf582b3 100644 --- a/homeassistant/components/devolo_home_control/translations/de.json +++ b/homeassistant/components/devolo_home_control/translations/de.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Diese Home Control Zentral wird bereits verwendet." }, - "error": { - "invalid_credentials": "Falscher Benutzername und/oder Passwort." - }, "step": { "user": { "data": { @@ -13,10 +10,8 @@ "mydevolo_url": "mydevolo URL", "password": "Passwort", "username": "E-Mail-Adresse / devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/en.json b/homeassistant/components/devolo_home_control/translations/en.json index e5c9f84cab0..10485c94b6f 100644 --- a/homeassistant/components/devolo_home_control/translations/en.json +++ b/homeassistant/components/devolo_home_control/translations/en.json @@ -4,8 +4,7 @@ "already_configured": "Account is already configured" }, "error": { - "invalid_auth": "Invalid authentication", - "invalid_credentials": "Incorrect user name and/or password." + "invalid_auth": "Invalid authentication" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "mydevolo URL", "password": "Password", "username": "Email / devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/es-419.json b/homeassistant/components/devolo_home_control/translations/es-419.json deleted file mode 100644 index eab3a5fddfe..00000000000 --- a/homeassistant/components/devolo_home_control/translations/es-419.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "devolo Home Control" -} \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/es.json b/homeassistant/components/devolo_home_control/translations/es.json index 8030dd5eaf5..ef3b2ae0d6d 100644 --- a/homeassistant/components/devolo_home_control/translations/es.json +++ b/homeassistant/components/devolo_home_control/translations/es.json @@ -4,8 +4,7 @@ "already_configured": "La cuenta ya ha sido configurada" }, "error": { - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_credentials": "Nombre de usuario y/o contrase\u00f1a incorrectos." + "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "URL de mydevolo", "password": "Contrase\u00f1a", "username": "Correo electr\u00f3nico / ID de devolo" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/et.json b/homeassistant/components/devolo_home_control/translations/et.json index c62f5adbd9a..9299c87170a 100644 --- a/homeassistant/components/devolo_home_control/translations/et.json +++ b/homeassistant/components/devolo_home_control/translations/et.json @@ -4,8 +4,7 @@ "already_configured": "Konto on juba seadistatud" }, "error": { - "invalid_auth": "Tuvastamise viga", - "invalid_credentials": "Vale kasutajanimi v\u00f5i salas\u00f5na." + "invalid_auth": "Tuvastamise viga" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "mydevolo URL", "password": "Salas\u00f5na", "username": "E-post / devolo ID" - }, - "title": "" + } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/fr.json b/homeassistant/components/devolo_home_control/translations/fr.json index acc2b171b63..fa8871bd17e 100644 --- a/homeassistant/components/devolo_home_control/translations/fr.json +++ b/homeassistant/components/devolo_home_control/translations/fr.json @@ -4,8 +4,7 @@ "already_configured": "Cette unit\u00e9 centrale Home Control est d\u00e9j\u00e0 utilis\u00e9e." }, "error": { - "invalid_auth": "Authentification invalide", - "invalid_credentials": "Nom d''utilisateur et/ou mot de passe incorrect." + "invalid_auth": "Authentification invalide" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "URL mydevolo", "password": "Mot de passe", "username": "Adresse e-mail / devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/he.json b/homeassistant/components/devolo_home_control/translations/he.json index 0042ba21e31..3007c0e968c 100644 --- a/homeassistant/components/devolo_home_control/translations/he.json +++ b/homeassistant/components/devolo_home_control/translations/he.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_credentials": "\u05e9\u05dd \u05de\u05e9\u05ea\u05de\u05e9 \u05d5/\u05d0\u05d5 \u05d4\u05e1\u05d9\u05e1\u05de\u05d4 \u05dc\u05d0 \u05d7\u05d5\u05e7\u05d9\u05d9\u05dd." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/devolo_home_control/translations/it.json b/homeassistant/components/devolo_home_control/translations/it.json index 8788e3e307a..1dcdb6cbcb0 100644 --- a/homeassistant/components/devolo_home_control/translations/it.json +++ b/homeassistant/components/devolo_home_control/translations/it.json @@ -4,8 +4,7 @@ "already_configured": "L'account \u00e8 gi\u00e0 configurato" }, "error": { - "invalid_auth": "Autenticazione non valida", - "invalid_credentials": "Nome utente e/o password non corretti." + "invalid_auth": "Autenticazione non valida" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "URL di mydevolo", "password": "Password", "username": "E-mail / devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/ko.json b/homeassistant/components/devolo_home_control/translations/ko.json index 6cb8d05f17e..17d4fe28a56 100644 --- a/homeassistant/components/devolo_home_control/translations/ko.json +++ b/homeassistant/components/devolo_home_control/translations/ko.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\uc774 Home Control Central \uc720\ub2db\uc740 \uc774\ubbf8 \uc0ac\uc6a9 \uc911\uc785\ub2c8\ub2e4." }, - "error": { - "invalid_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ub610\ub294 \ube44\ubc00\ubc88\ud638\uac00 \uc77c\uce58\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { @@ -13,10 +10,8 @@ "mydevolo_url": "mydevolo URL", "password": "\ube44\ubc00\ubc88\ud638", "username": "\uc774\uba54\uc77c \uc8fc\uc18c / devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/lb.json b/homeassistant/components/devolo_home_control/translations/lb.json index 0c1946cb126..3943dbd1d5b 100644 --- a/homeassistant/components/devolo_home_control/translations/lb.json +++ b/homeassistant/components/devolo_home_control/translations/lb.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_configured": "D\u00ebs Home Control Zentrale g\u00ebtt scho benotzt." + "already_configured": "Kont ass scho konfigur\u00e9iert" }, "error": { - "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_credentials": "Ong\u00ebltege Benotzernumm an/oder Passwuert" + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "user": { @@ -13,11 +12,9 @@ "home_control_url": "Home Control URL", "mydevolo_url": "mydevolo URL", "password": "Passwuert", - "username": "E-Mail-Address / devolo ID" - }, - "title": "devolo Home Control" + "username": "E-Mail / devolo ID" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/nl.json b/homeassistant/components/devolo_home_control/translations/nl.json index ad344544984..d61f9183cc5 100644 --- a/homeassistant/components/devolo_home_control/translations/nl.json +++ b/homeassistant/components/devolo_home_control/translations/nl.json @@ -3,18 +3,13 @@ "abort": { "already_configured": "Account is al geconfigureerd" }, - "error": { - "invalid_credentials": "Verkeerde gebruikersnaam en/of wachtwoord." - }, "step": { "user": { "data": { "password": "Wachtwoord", "username": "E-mail adres / devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/no.json b/homeassistant/components/devolo_home_control/translations/no.json index 2ec2b0744f2..ec0b9f4c386 100644 --- a/homeassistant/components/devolo_home_control/translations/no.json +++ b/homeassistant/components/devolo_home_control/translations/no.json @@ -4,8 +4,7 @@ "already_configured": "Kontoen er allerede konfigurert" }, "error": { - "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig brukernavn og/eller passord" + "invalid_auth": "Ugyldig godkjenning" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "mydevolo URL", "password": "Passord", "username": "E-post / devolo ID" - }, - "title": "" + } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/pl.json b/homeassistant/components/devolo_home_control/translations/pl.json index d9bf1de55d1..699ad56c85b 100644 --- a/homeassistant/components/devolo_home_control/translations/pl.json +++ b/homeassistant/components/devolo_home_control/translations/pl.json @@ -4,8 +4,7 @@ "already_configured": "Konto jest ju\u017c skonfigurowane" }, "error": { - "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owa nazwa u\u017cytkownika i/lub has\u0142o" + "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "URL mydevolo", "password": "Has\u0142o", "username": "Nazwa u\u017cytkownika/identyfikator devolo" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/pt.json b/homeassistant/components/devolo_home_control/translations/pt.json index 913844eab4e..b8a454fbaba 100644 --- a/homeassistant/components/devolo_home_control/translations/pt.json +++ b/homeassistant/components/devolo_home_control/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_credentials": "Nome de utilizador ou palavra-passe incorretos" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/devolo_home_control/translations/ru.json b/homeassistant/components/devolo_home_control/translations/ru.json index 71cff94add6..d4cf639ffd5 100644 --- a/homeassistant/components/devolo_home_control/translations/ru.json +++ b/homeassistant/components/devolo_home_control/translations/ru.json @@ -4,8 +4,7 @@ "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." }, "error": { - "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\u0439 \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c." + "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "mydevolo URL-\u0430\u0434\u0440\u0435\u0441", "password": "\u041f\u0430\u0440\u043e\u043b\u044c", "username": "\u0410\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b / devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/sv.json b/homeassistant/components/devolo_home_control/translations/sv.json index 7ac5f75d405..48cd7428a78 100644 --- a/homeassistant/components/devolo_home_control/translations/sv.json +++ b/homeassistant/components/devolo_home_control/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_credentials": "Felaktigt anv\u00e4ndarnamn eller l\u00f6senord" - }, "step": { "user": { "data": { @@ -10,10 +7,8 @@ "mydevolo_url": "mydevolo URL", "password": "L\u00f6senord", "username": "E-postadress / devolo-ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/devolo_home_control/translations/zh-Hant.json b/homeassistant/components/devolo_home_control/translations/zh-Hant.json index 3336d67464a..e408e9794ca 100644 --- a/homeassistant/components/devolo_home_control/translations/zh-Hant.json +++ b/homeassistant/components/devolo_home_control/translations/zh-Hant.json @@ -4,8 +4,7 @@ "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u4f7f\u7528\u8005\u540d\u7a31\u53ca/\u6216\u5bc6\u78bc\u932f\u8aa4\u3002" + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { "user": { @@ -14,10 +13,8 @@ "mydevolo_url": "mydevolo \u7db2\u5740", "password": "\u5bc6\u78bc", "username": "\u96fb\u5b50\u90f5\u4ef6 / devolo ID" - }, - "title": "devolo Home Control" + } } } - }, - "title": "devolo Home Control" + } } \ No newline at end of file diff --git a/homeassistant/components/dexcom/strings.json b/homeassistant/components/dexcom/strings.json index bb29f814ee8..5cc2b363665 100644 --- a/homeassistant/components/dexcom/strings.json +++ b/homeassistant/components/dexcom/strings.json @@ -17,7 +17,7 @@ "unknown": "[%key:common::config_flow::error::unknown%]" }, "abort": { - "already_configured_account": "[%key:common::config_flow::abort::already_configured_account%]" + "already_configured": "[%key:common::config_flow::abort::already_configured_account%]" } }, "options": { @@ -29,4 +29,4 @@ } } } -} +} \ No newline at end of file diff --git a/homeassistant/components/dexcom/translations/ca.json b/homeassistant/components/dexcom/translations/ca.json index b92d6b7ab06..e188718a71d 100644 --- a/homeassistant/components/dexcom/translations/ca.json +++ b/homeassistant/components/dexcom/translations/ca.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "El compte ja ha estat configurat" + "already_configured": "El compte ja ha estat configurat" }, "error": { - "account_error": "Autenticaci\u00f3 inv\u00e0lida", "cannot_connect": "Ha fallat la connexi\u00f3", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "session_error": "Ha fallat la connexi\u00f3", "unknown": "Error inesperat" }, "step": { diff --git a/homeassistant/components/dexcom/translations/cs.json b/homeassistant/components/dexcom/translations/cs.json index 3eaed9fcbde..61a00e1c9f8 100644 --- a/homeassistant/components/dexcom/translations/cs.json +++ b/homeassistant/components/dexcom/translations/cs.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "\u00da\u010det je ji\u017e nastaven" + "already_configured": "\u00da\u010det je ji\u017e nastaven" }, "error": { - "account_error": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "session_error": "Nepoda\u0159ilo se p\u0159ipojit", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { @@ -16,7 +14,9 @@ "password": "Heslo", "server": "Server", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" - } + }, + "description": "Zadejte p\u0159ihla\u0161ovac\u00ed \u00fadaje Dexcom Share", + "title": "Nastaven\u00ed integrace Dexcom" } } }, diff --git a/homeassistant/components/dexcom/translations/de.json b/homeassistant/components/dexcom/translations/de.json index 31ded6b7f9e..3b5744ba1ae 100644 --- a/homeassistant/components/dexcom/translations/de.json +++ b/homeassistant/components/dexcom/translations/de.json @@ -1,10 +1,9 @@ { "config": { "abort": { - "already_configured_account": "Account ist bereits konfiguriert" + "already_configured": "Konto ist bereits konfiguriert" }, "error": { - "session_error": "Verbindung nicht m\u00f6glich", "unknown": "Unerwarteter Fehler" }, "step": { diff --git a/homeassistant/components/dexcom/translations/en.json b/homeassistant/components/dexcom/translations/en.json index 92ca2d11859..f7558c31468 100644 --- a/homeassistant/components/dexcom/translations/en.json +++ b/homeassistant/components/dexcom/translations/en.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "Account is already configured" + "already_configured": "Account is already configured" }, "error": { - "account_error": "Invalid authentication", "cannot_connect": "Failed to connect", "invalid_auth": "Invalid authentication", - "session_error": "Failed to connect", "unknown": "Unexpected error" }, "step": { diff --git a/homeassistant/components/dexcom/translations/es.json b/homeassistant/components/dexcom/translations/es.json index 95f80f558b3..934c40be05e 100644 --- a/homeassistant/components/dexcom/translations/es.json +++ b/homeassistant/components/dexcom/translations/es.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "La cuenta ya ha sido configurada" + "already_configured": "La cuenta ya ha sido configurada" }, "error": { - "account_error": "Autenticaci\u00f3n no v\u00e1lida", "cannot_connect": "No se pudo conectar", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "session_error": "No se pudo conectar", "unknown": "Error inesperado" }, "step": { diff --git a/homeassistant/components/dexcom/translations/et.json b/homeassistant/components/dexcom/translations/et.json index d517cab1362..08435e433f4 100644 --- a/homeassistant/components/dexcom/translations/et.json +++ b/homeassistant/components/dexcom/translations/et.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "Konto on juba seadistatud" + "already_configured": "Kasutaja on juba seadistatud" }, "error": { - "account_error": "Tuvastamine nurjus", "cannot_connect": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamise viga", - "session_error": "\u00dchendamine nurjus", "unknown": "Tundmatu viga" }, "step": { @@ -17,6 +15,7 @@ "server": "", "username": "Kasutajanimi" }, + "description": "Sisesta Dexcom Share'i volitused", "title": "Seadista Dexcom'i sidumine" } } diff --git a/homeassistant/components/dexcom/translations/fr.json b/homeassistant/components/dexcom/translations/fr.json index 5ad342c22ff..d10643a3c1e 100644 --- a/homeassistant/components/dexcom/translations/fr.json +++ b/homeassistant/components/dexcom/translations/fr.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "Le compte est d\u00e9j\u00e0 configur\u00e9" + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9" }, "error": { - "account_error": "L'authentification ne'st pas valide", "cannot_connect": "\u00c9chec de connexion", "invalid_auth": "Authentification invalide", - "session_error": "\u00c9chec de connexion", "unknown": "Erreur inattendue" }, "step": { diff --git a/homeassistant/components/dexcom/translations/hu.json b/homeassistant/components/dexcom/translations/hu.json deleted file mode 100644 index 9f2fd5d72f4..00000000000 --- a/homeassistant/components/dexcom/translations/hu.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "abort": { - "already_configured_account": "A fi\u00f3k m\u00e1r konfigur\u00e1lva van" - } - } -} \ No newline at end of file diff --git a/homeassistant/components/dexcom/translations/it.json b/homeassistant/components/dexcom/translations/it.json index 0042c585cd1..b196f9f87ed 100644 --- a/homeassistant/components/dexcom/translations/it.json +++ b/homeassistant/components/dexcom/translations/it.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "L'account \u00e8 gi\u00e0 configurato" + "already_configured": "L'account \u00e8 gi\u00e0 configurato" }, "error": { - "account_error": "Autenticazione non valida", "cannot_connect": "Impossibile connettersi", "invalid_auth": "Autenticazione non valida", - "session_error": "Impossibile connettersi", "unknown": "Errore imprevisto" }, "step": { diff --git a/homeassistant/components/dexcom/translations/ko.json b/homeassistant/components/dexcom/translations/ko.json index 3c422f0a869..35129cbfbde 100644 --- a/homeassistant/components/dexcom/translations/ko.json +++ b/homeassistant/components/dexcom/translations/ko.json @@ -1,11 +1,6 @@ { "config": { - "abort": { - "already_configured_account": "\uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." - }, "error": { - "account_error": "\uc778\uc99d\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "session_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4", "unknown": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" }, "step": { diff --git a/homeassistant/components/dexcom/translations/lb.json b/homeassistant/components/dexcom/translations/lb.json index 2fb803d73ff..86aced8ee11 100644 --- a/homeassistant/components/dexcom/translations/lb.json +++ b/homeassistant/components/dexcom/translations/lb.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "Kont ass scho konfigur\u00e9iert" + "already_configured": "Kont ass scho konfigur\u00e9iert" }, "error": { - "account_error": "Ong\u00eblteg Authentifikatioun", "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "session_error": "Feeler beim verbannen", "unknown": "Onerwaarte" }, "step": { diff --git a/homeassistant/components/dexcom/translations/nl.json b/homeassistant/components/dexcom/translations/nl.json index 4198e0d9fc4..1dd597d28b4 100644 --- a/homeassistant/components/dexcom/translations/nl.json +++ b/homeassistant/components/dexcom/translations/nl.json @@ -1,11 +1,17 @@ { "config": { + "abort": { + "already_configured": "Account is al geconfigureerd" + }, "error": { - "cannot_connect": "Kan geen verbinding maken" + "cannot_connect": "Kan geen verbinding maken", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" }, "step": { "user": { "data": { + "password": "Wachtwoord", "username": "Gebruikersnaam" } } diff --git a/homeassistant/components/dexcom/translations/no.json b/homeassistant/components/dexcom/translations/no.json index 231c9393978..3ec0c755f9e 100644 --- a/homeassistant/components/dexcom/translations/no.json +++ b/homeassistant/components/dexcom/translations/no.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "Kontoen er allerede konfigurert" + "already_configured": "Kontoen er allerede konfigurert" }, "error": { - "account_error": "Ugyldig godkjenning", "cannot_connect": "Tilkobling mislyktes", "invalid_auth": "Ugyldig godkjenning", - "session_error": "Tilkobling mislyktes", "unknown": "Uventet feil" }, "step": { diff --git a/homeassistant/components/dexcom/translations/pl.json b/homeassistant/components/dexcom/translations/pl.json index 3897fbb13f9..7bb726cbe23 100644 --- a/homeassistant/components/dexcom/translations/pl.json +++ b/homeassistant/components/dexcom/translations/pl.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "Konto jest ju\u017c skonfigurowane" + "already_configured": "Konto jest ju\u017c skonfigurowane" }, "error": { - "account_error": "Niepoprawne uwierzytelnienie", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "invalid_auth": "Niepoprawne uwierzytelnienie", - "session_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "unknown": "Nieoczekiwany b\u0142\u0105d" }, "step": { @@ -18,7 +16,7 @@ "username": "Nazwa u\u017cytkownika" }, "description": "Wprowad\u017a dane uwierzytelniaj\u0105ce Dexcom", - "title": "Skonfiguruj integracj\u0119 Dexcom" + "title": "Konfiguracja integracji Dexcom" } } }, diff --git a/homeassistant/components/dexcom/translations/pt.json b/homeassistant/components/dexcom/translations/pt.json index d2b1596b068..af953a1caaa 100644 --- a/homeassistant/components/dexcom/translations/pt.json +++ b/homeassistant/components/dexcom/translations/pt.json @@ -1,11 +1,6 @@ { "config": { - "abort": { - "already_configured_account": "Conta j\u00e1 configurada" - }, "error": { - "account_error": "Autentica\u00e7\u00e3o inv\u00e1lida", - "session_error": "Falha na liga\u00e7\u00e3o", "unknown": "Erro inesperado" }, "step": { diff --git a/homeassistant/components/dexcom/translations/ru.json b/homeassistant/components/dexcom/translations/ru.json index 69b79638100..5b6b3ab24b1 100644 --- a/homeassistant/components/dexcom/translations/ru.json +++ b/homeassistant/components/dexcom/translations/ru.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "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." + "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." }, "error": { - "account_error": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", - "session_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "step": { diff --git a/homeassistant/components/dexcom/translations/tr.json b/homeassistant/components/dexcom/translations/tr.json new file mode 100644 index 00000000000..80638d181b2 --- /dev/null +++ b/homeassistant/components/dexcom/translations/tr.json @@ -0,0 +1,7 @@ +{ + "config": { + "abort": { + "already_configured": "Hesap zaten konfig\u00fcre edilmi\u015fi durumda" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/dexcom/translations/zh-Hans.json b/homeassistant/components/dexcom/translations/zh-Hans.json index 7fd407af3aa..09bb1410d01 100644 --- a/homeassistant/components/dexcom/translations/zh-Hans.json +++ b/homeassistant/components/dexcom/translations/zh-Hans.json @@ -1,9 +1,7 @@ { "config": { "error": { - "account_error": "\u8ba4\u8bc1\u65e0\u6548", "cannot_connect": "\u8fde\u63a5\u5931\u8d25", - "session_error": "\u8fde\u63a5\u5931\u8d25", "unknown": "\u672a\u77e5\u9519\u8bef" }, "step": { diff --git a/homeassistant/components/dexcom/translations/zh-Hant.json b/homeassistant/components/dexcom/translations/zh-Hant.json index 656e082f7c4..3763905160c 100644 --- a/homeassistant/components/dexcom/translations/zh-Hant.json +++ b/homeassistant/components/dexcom/translations/zh-Hant.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured_account": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "account_error": "\u9a57\u8b49\u78bc\u7121\u6548", "cannot_connect": "\u9023\u7dda\u5931\u6557", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "session_error": "\u9023\u7dda\u5931\u6557", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "step": { diff --git a/homeassistant/components/dialogflow/strings.json b/homeassistant/components/dialogflow/strings.json index f17491a7528..0e7aa952c1a 100644 --- a/homeassistant/components/dialogflow/strings.json +++ b/homeassistant/components/dialogflow/strings.json @@ -8,7 +8,7 @@ }, "abort": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive Dialogflow messages." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup [webhook integration of Dialogflow]({dialogflow_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/dialogflow/translations/bg.json b/homeassistant/components/dialogflow/translations/bg.json index 069545d93c8..cc8faa1f0fd 100644 --- a/homeassistant/components/dialogflow/translations/bg.json +++ b/homeassistant/components/dialogflow/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 Dialogflow.", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u0441\u044a\u0431\u0438\u0442\u0438\u044f \u0434\u043e Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 [\u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0442\u0430 webhook \u0432 Dialogflow]({dialogflow_url}). \n\n \u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: \n\n - URL: ` {webhook_url} ` \n - Method: POST\n - Content Type: application/json\n\n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438." }, diff --git a/homeassistant/components/dialogflow/translations/ca.json b/homeassistant/components/dialogflow/translations/ca.json index bc62fe1f555..dad18be0f6a 100644 --- a/homeassistant/components/dialogflow/translations/ca.json +++ b/homeassistant/components/dialogflow/translations/ca.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de Dialogflow.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar esdeveniments a Home Assistant, haur\u00e0s de configurar la [integraci\u00f3 webhook de Dialogflow]({dialogflow_url}). \n\n Completa la seg\u00fcent informaci\u00f3: \n\n- URL: `{webhook_url}` \n- M\u00e8tode: POST \n- Tipus de contingut: application/json\n\nConsulta la [documentaci\u00f3]({docs_url}) per a m\u00e9s detalls." diff --git a/homeassistant/components/dialogflow/translations/cs.json b/homeassistant/components/dialogflow/translations/cs.json index 409d63070f7..c77008de3c3 100644 --- a/homeassistant/components/dialogflow/translations/cs.json +++ b/homeassistant/components/dialogflow/translations/cs.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "not_internet_accessible": "V\u00e1\u0161 Home Asistent mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy od Dialogflow.", - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "create_entry": { - "default": "Chcete-li odeslat ud\u00e1losti do aplikace Home Assistant, budete muset nastavit [integraci Dialogflow]({dialogflow_url}). \n\n Vypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: `{webhook_url}' \n - Metoda: POST \n - Typ obsahu: application/json\n\n Podrobn\u011bj\u0161\u00ed informace naleznete v [dokumentaci]({docs_url})." + "default": "Chcete-li odeslat ud\u00e1losti do Home Assistant, budete muset nastavit [integraci Dialogflow]({dialogflow_url}). \n\nVypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: `{webhook_url}' \n - Metoda: POST \n - Typ obsahu: application/json\n\nPodrobn\u011bj\u0161\u00ed informace naleznete v [dokumentaci]({docs_url})." }, "step": { "user": { diff --git a/homeassistant/components/dialogflow/translations/da.json b/homeassistant/components/dialogflow/translations/da.json index bcab485a51a..4b30f794867 100644 --- a/homeassistant/components/dialogflow/translations/da.json +++ b/homeassistant/components/dialogflow/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage Dialogflow-meddelelser", - "one_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning" - }, "create_entry": { "default": "For at sende h\u00e6ndelser til Home Assistant skal du konfigurere [webhook-integration med Dialogflow]({dialogflow_url}).\n\n Udfyld f\u00f8lgende oplysninger: \n\n - Webadresse: `{webhook_url}`\n - Metode: POST\n - Indholdstype: application/json\n\nSe [dokumentationen]({docs_url}) for yderligere oplysninger." }, diff --git a/homeassistant/components/dialogflow/translations/de.json b/homeassistant/components/dialogflow/translations/de.json index cc65084d5ae..f1853107cc2 100644 --- a/homeassistant/components/dialogflow/translations/de.json +++ b/homeassistant/components/dialogflow/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Ihre Home Assistant-Instanz muss \u00fcber das Internet erreichbar sein, um Dialogflow-Nachrichten empfangen zu k\u00f6nnen.", - "one_instance_allowed": "Nur eine einzige Instanz ist notwendig." - }, "create_entry": { "default": "Um Ereignisse an den Home Assistant zu senden, musst du [Webhook-Integration von Dialogflow]({dialogflow_url}) einrichten. \n\nF\u00fclle die folgenden Informationen aus: \n\n - URL: ` {webhook_url} ` \n - Methode: POST \n - Inhaltstyp: application / json \n\nWeitere Informationen findest du in der [Dokumentation]({docs_url})." }, diff --git a/homeassistant/components/dialogflow/translations/en.json b/homeassistant/components/dialogflow/translations/en.json index f78843fd503..31b7f1f8880 100644 --- a/homeassistant/components/dialogflow/translations/en.json +++ b/homeassistant/components/dialogflow/translations/en.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive Dialogflow messages.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup [webhook integration of Dialogflow]({dialogflow_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/dialogflow/translations/es-419.json b/homeassistant/components/dialogflow/translations/es-419.json index 1aa3d23cb7e..d8d230cbf45 100644 --- a/homeassistant/components/dialogflow/translations/es-419.json +++ b/homeassistant/components/dialogflow/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Dialogflow.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar eventos a Home Assistant, deber\u00e1 configurar [integraci\u00f3n de webhook de Dialogflow] ( {dialogflow_url} ). \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n - Tipo de contenido: aplicaci\u00f3n / json \n\n Vea [la documentaci\u00f3n] ( {docs_url} ) para m\u00e1s detalles." }, diff --git a/homeassistant/components/dialogflow/translations/es.json b/homeassistant/components/dialogflow/translations/es.json index 542cbe3d022..ca2370f9086 100644 --- a/homeassistant/components/dialogflow/translations/es.json +++ b/homeassistant/components/dialogflow/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Tu instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Dialogflow.", - "one_instance_allowed": "S\u00f3lo se necesita una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar eventos a Home Assistant, necesitas configurar [Integraci\u00f3n de flujos de dialogo de webhook]({dialogflow_url}).\n\nRellena la siguiente informaci\u00f3n:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nVer [Documentaci\u00f3n]({docs_url}) para m\u00e1s detalles." diff --git a/homeassistant/components/dialogflow/translations/et.json b/homeassistant/components/dialogflow/translations/et.json index fafda5352ec..f0b6c3eade4 100644 --- a/homeassistant/components/dialogflow/translations/et.json +++ b/homeassistant/components/dialogflow/translations/et.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Dialogflow teavituste vastuv\u00f5tmiseks peab teie Home Assistant olema Interneti kaudu ligip\u00e4\u00e4setav.", - "one_instance_allowed": "Vaja on ainult \u00fchte \u00fcksust.", - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." }, "create_entry": { "default": "S\u00fcndmuste saatmiseks Home Assistantile peate seadistama [Dialogflow'i veebihaagii integreerimine] ( {dialogflow_url} ). \n\n Sisestage j\u00e4rgmine teave: \n\n - URL: \" {webhook_url} \" \n - Meetod: POST \n - Sisu t\u00fc\u00fcp: rakendus / json \n\n Lisateavet leiate [dokumentatsioonist] ( {docs_url} )." diff --git a/homeassistant/components/dialogflow/translations/fr.json b/homeassistant/components/dialogflow/translations/fr.json index 85ace2c378e..1eb34e21000 100644 --- a/homeassistant/components/dialogflow/translations/fr.json +++ b/homeassistant/components/dialogflow/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance de Home Assistant doit \u00eatre accessible depuis Internet pour recevoir les messages Dialogflow.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez configurer [Webhooks avec Dialogflow] ( {dialogflow_url} ). \n\n Remplissez les informations suivantes: \n\n - URL: ` {webhook_url} ` \n - M\u00e9thode: POST \n - Type de contenu: application / json \n\n Voir [la documentation] ( {docs_url} ) pour savoir comment configurer les automatisations pour g\u00e9rer les donn\u00e9es entrantes." diff --git a/homeassistant/components/dialogflow/translations/hu.json b/homeassistant/components/dialogflow/translations/hu.json index d44e7f60cc6..638adb4ae12 100644 --- a/homeassistant/components/dialogflow/translations/hu.json +++ b/homeassistant/components/dialogflow/translations/hu.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A Home Assistant rendszerednek el\u00e9rhet\u0151nek kell lennie az internetr\u0151l a Dialogflow \u00fczenetek fogad\u00e1s\u00e1hoz.", - "one_instance_allowed": "Csak egyetlen konfigur\u00e1ci\u00f3 sz\u00fcks\u00e9ges." - }, "step": { "user": { "description": "Biztosan be szeretn\u00e9d \u00e1ll\u00edtani az Dialogflowt?", diff --git a/homeassistant/components/dialogflow/translations/it.json b/homeassistant/components/dialogflow/translations/it.json index a318633d4e4..8df625d2cc3 100644 --- a/homeassistant/components/dialogflow/translations/it.json +++ b/homeassistant/components/dialogflow/translations/it.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi da Dialogflow.", - "one_instance_allowed": "\u00c8 necessaria una sola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare eventi a Home Assistant, dovrai configurare [l'integrazione webhook di Dialogflow]({dialogflow_url})\n\n Compila le seguenti informazioni: \n\n - URL: `{webhook_url}` \n - Method: POST \n - Content Type: application/json \n\n Vedi [la documentazione]({docs_url}) for ulteriori dettagli." diff --git a/homeassistant/components/dialogflow/translations/ko.json b/homeassistant/components/dialogflow/translations/ko.json index f9ee10ceee7..7afeb6da74c 100644 --- a/homeassistant/components/dialogflow/translations/ko.json +++ b/homeassistant/components/dialogflow/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Dialogflow \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c\ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\ub824\uba74 [Dialogflow \uc6f9 \ud6c5]({dialogflow_url}) \uc744 \uc124\uc815\ud574\uc57c\ud569\ub2c8\ub2e4. \n\n\ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694:\n\n - URL: `{webhook_url}`\n - Method: POST\n - Content Type: application/json\n \n\uc790\uc138\ud55c \uc815\ubcf4\ub294 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/dialogflow/translations/lb.json b/homeassistant/components/dialogflow/translations/lb.json index d64fa8bd2e7..85d5d30128b 100644 --- a/homeassistant/components/dialogflow/translations/lb.json +++ b/homeassistant/components/dialogflow/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir Dialogflow Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { diff --git a/homeassistant/components/dialogflow/translations/nl.json b/homeassistant/components/dialogflow/translations/nl.json index fed695b4f0d..7cccf8ecb9b 100644 --- a/homeassistant/components/dialogflow/translations/nl.json +++ b/homeassistant/components/dialogflow/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Uw Home Assistant instantie moet toegankelijk zijn vanaf het internet om Dialogflow-berichten te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/dialogflow/translations/no.json b/homeassistant/components/dialogflow/translations/no.json index 1dc94a53d7e..af11f5c1c63 100644 --- a/homeassistant/components/dialogflow/translations/no.json +++ b/homeassistant/components/dialogflow/translations/no.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Din Home Assistant forekomst m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta Dialogflow meldinger.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du sette opp [webhook integrasjon av Dialogflow]({dialogflow_url}). \n\nFyll ut f\u00f8lgende informasjon: \n\n- URL: `{webhook_url}` \n- Metode: POST\n- Innholdstype: application/json\n\nSe [dokumentasjonen]({docs_url}) for ytterligere detaljer." diff --git a/homeassistant/components/dialogflow/translations/pl.json b/homeassistant/components/dialogflow/translations/pl.json index 510e60edb0e..031c69c6eca 100644 --- a/homeassistant/components/dialogflow/translations/pl.json +++ b/homeassistant/components/dialogflow/translations/pl.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty Dialogflow", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant, musisz skonfigurowa\u0107 [Dialogflow Webhook]({dialogflow_url}). \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n - Typ zawarto\u015bci: application/json\n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}), by pozna\u0107 szczeg\u00f3\u0142y." }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 Dialogflow?", + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", "title": "Konfiguracja Dialogflow Webhook" } } diff --git a/homeassistant/components/dialogflow/translations/pt-BR.json b/homeassistant/components/dialogflow/translations/pt-BR.json index 3d4ad4ca34b..45aadbd1730 100644 --- a/homeassistant/components/dialogflow/translations/pt-BR.json +++ b/homeassistant/components/dialogflow/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia do Home Assistant precisa estar acess\u00edvel na Internet para receber mensagens da Dialogflow.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, voc\u00ea precisar\u00e1 configurar [Integra\u00e7\u00e3o do webhook da Dialogflow] ( {dialogflow_url} ). \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n - Tipo de Conte\u00fado: application / json \n\n Veja [a documenta\u00e7\u00e3o] ( {docs_url} ) para mais detalhes." }, diff --git a/homeassistant/components/dialogflow/translations/pt.json b/homeassistant/components/dialogflow/translations/pt.json index e6ed255e6c0..09ab0e6711c 100644 --- a/homeassistant/components/dialogflow/translations/pt.json +++ b/homeassistant/components/dialogflow/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A sua inst\u00e2ncia Home Assistant precisa de ser acess\u00edvel a partir da internet para receber mensagens Dialogflow.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, \u00e9 necess\u00e1rio configurar o [Dialogflow Webhook] ({dialogflow_url}). \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: `{webhook_url}`\n - M\u00e9todo: POST \n - Tipo de Conte\u00fado: application/json\n\n Veja [a documenta\u00e7\u00e3o] ({docs_url}) para obter mais detalhes." }, diff --git a/homeassistant/components/dialogflow/translations/ru.json b/homeassistant/components/dialogflow/translations/ru.json index 7e0d0087ec7..de1e10b7e49 100644 --- a/homeassistant/components/dialogflow/translations/ru.json +++ b/homeassistant/components/dialogflow/translations/ru.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 Dialogflow.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Webhook \u0434\u043b\u044f [Dialogflow]({dialogflow_url}).\n\n\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\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 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438." diff --git a/homeassistant/components/dialogflow/translations/sl.json b/homeassistant/components/dialogflow/translations/sl.json index 742302dcd17..c28512f6a06 100644 --- a/homeassistant/components/dialogflow/translations/sl.json +++ b/homeassistant/components/dialogflow/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u010ce \u017eelite prejemati sporo\u010dila dialogflow, mora biti Home Assistant dostopen prek interneta.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "Za po\u0161iljanje dogodkov Home Assistant-u, boste morali nastaviti [webhook z Dialogflow]({twilio_url}).\n\nIzpolnite naslednje informacije:\n\n- URL: `{webhook_url}`\n- Metoda: POST\n- Vrsta vsebine: application/x-www-form-urlencoded\n\nGlej [dokumentacijo]({docs_url}) za nadaljna navodila." }, diff --git a/homeassistant/components/dialogflow/translations/sv.json b/homeassistant/components/dialogflow/translations/sv.json index bd3ae17ae74..9642b4b7bec 100644 --- a/homeassistant/components/dialogflow/translations/sv.json +++ b/homeassistant/components/dialogflow/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant instans m\u00e5ste vara tillg\u00e4nglig fr\u00e5n internet f\u00f6r att ta emot Dialogflow meddelanden.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du konfigurera [webhook funktionen i Dialogflow]({dialogflow_url}).\n\n Fyll i f\u00f6ljande information:\n \n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSe [dokumentation]({docs_url}) om hur du konfigurerar detta f\u00f6r mer information." }, diff --git a/homeassistant/components/dialogflow/translations/zh-Hans.json b/homeassistant/components/dialogflow/translations/zh-Hans.json index 8ae8cb6f78e..ae414f99e55 100644 --- a/homeassistant/components/dialogflow/translations/zh-Hans.json +++ b/homeassistant/components/dialogflow/translations/zh-Hans.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u63a5\u5165\u4e92\u8054\u7f51\u4ee5\u63a5\u6536 Dialogflow \u6d88\u606f\u3002", - "one_instance_allowed": "\u4ec5\u9700\u4e00\u4e2a\u5b9e\u4f8b" - }, "create_entry": { "default": "\u8981\u5411 Home Assistant \u53d1\u9001\u4e8b\u4ef6\uff0c\u60a8\u9700\u8981\u914d\u7f6e [Dialogflow \u7684 Webhook \u96c6\u6210]({dialogflow_url})\u3002\n\n\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\u8bf7\u53c2\u9605[\u6587\u6863]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u591a\u4fe1\u606f\u3002" }, diff --git a/homeassistant/components/dialogflow/translations/zh-Hant.json b/homeassistant/components/dialogflow/translations/zh-Hant.json index c03cfbfd72d..ab790dafe9b 100644 --- a/homeassistant/components/dialogflow/translations/zh-Hant.json +++ b/homeassistant/components/dialogflow/translations/zh-Hant.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u8a2d\u5099\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 Dialogflow \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u7269\u4ef6\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u8a2d\u5b9a [webhook integration of Dialogflow]({dialogflow_url})\u3002\n\n\u8acb\u586b\u5beb\u4e0b\u5217\u8cc7\u8a0a\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\u8acb\u53c3\u95b1 [\u6587\u4ef6]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u8a73\u7d30\u8cc7\u6599\u3002" diff --git a/homeassistant/components/directv/__init__.py b/homeassistant/components/directv/__init__.py index af27d19cfb0..59682178d40 100644 --- a/homeassistant/components/directv/__init__.py +++ b/homeassistant/components/directv/__init__.py @@ -4,9 +4,8 @@ from datetime import timedelta 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 @@ from .const import ( 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 @@ SCAN_INTERVAL = timedelta(seconds=30) 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 d84c3925ac4..cae0e62b1be 100644 --- a/homeassistant/components/directv/config_flow.py +++ b/homeassistant/components/directv/config_flow.py @@ -47,12 +47,6 @@ class DirecTVConfigFlow(ConfigFlow, domain=DOMAIN): """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/homeassistant/components/directv/translations/nl.json b/homeassistant/components/directv/translations/nl.json index 26b6e65e811..2024368daf6 100644 --- a/homeassistant/components/directv/translations/nl.json +++ b/homeassistant/components/directv/translations/nl.json @@ -10,6 +10,10 @@ "flow_title": "DirecTV: {name}", "step": { "ssdp_confirm": { + "data": { + "one": "Leeg", + "other": "Leeg" + }, "description": "Wilt u {name} instellen?" }, "user": { diff --git a/homeassistant/components/doorbird/translations/cs.json b/homeassistant/components/doorbird/translations/cs.json index 865850d2085..fea0647ec85 100644 --- a/homeassistant/components/doorbird/translations/cs.json +++ b/homeassistant/components/doorbird/translations/cs.json @@ -2,6 +2,7 @@ "config": { "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", + "link_local_address": "Propojen\u00ed m\u00edstn\u00edch adres nen\u00ed podporov\u00e1no", "not_doorbird_device": "Toto za\u0159\u00edzen\u00ed nen\u00ed DoorBird" }, "error": { @@ -27,7 +28,8 @@ "init": { "data": { "events": "Seznam ud\u00e1lost\u00ed odd\u011blen\u00fdch \u010d\u00e1rkami." - } + }, + "description": "Zadejte n\u00e1zvy ud\u00e1lost\u00ed odd\u011blen\u00e9 \u010d\u00e1rkou, kter\u00e9 chcete sledovat. Po jejich zad\u00e1n\u00ed je pomoc\u00ed aplikace DoorBird p\u0159i\u0159a\u010fte ke konkr\u00e9tn\u00ed ud\u00e1losti. Viz dokumentace na https://www.home-assistant.io/integrations/doorbird/#events. P\u0159\u00edklad: nekdo_stiskl_tlacitko, pohyb" } } } diff --git a/homeassistant/components/doorbird/translations/et.json b/homeassistant/components/doorbird/translations/et.json index 017e290021d..2d967a09cda 100644 --- a/homeassistant/components/doorbird/translations/et.json +++ b/homeassistant/components/doorbird/translations/et.json @@ -10,10 +10,12 @@ "invalid_auth": "Tuvastamine nurjus", "unknown": "Tundmatu viga" }, + "flow_title": "", "step": { "user": { "data": { "host": "", + "name": "Seadme nimi", "password": "Salas\u00f5na", "username": "Kasutajanimi" }, diff --git a/homeassistant/components/doorbird/translations/lb.json b/homeassistant/components/doorbird/translations/lb.json index d7ffd9577dd..c7cb7234fea 100644 --- a/homeassistant/components/doorbird/translations/lb.json +++ b/homeassistant/components/doorbird/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "D\u00ebse DoorBird ass scho konfigur\u00e9iert", + "already_configured": "Apparat ass scho konfigur\u00e9iert", "link_local_address": "Lokal Link Adressen ginn net \u00ebnnerst\u00ebtzt", "not_doorbird_device": "D\u00ebsen Apparat ass kee DoorBird" }, diff --git a/homeassistant/components/doorbird/translations/nl.json b/homeassistant/components/doorbird/translations/nl.json index 2bf97d687ab..625367484b0 100644 --- a/homeassistant/components/doorbird/translations/nl.json +++ b/homeassistant/components/doorbird/translations/nl.json @@ -6,7 +6,9 @@ "not_doorbird_device": "Dit apparaat is geen DoorBird" }, "error": { - "cannot_connect": "Verbinding mislukt, probeer het opnieuw" + "cannot_connect": "Verbinding mislukt, probeer het opnieuw", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" }, "flow_title": "DoorBird {name} ({host})", "step": { @@ -14,6 +16,7 @@ "data": { "host": "Host (IP-adres)", "name": "Apparaatnaam", + "password": "Wachtwoord", "username": "Gebruikersnaam" }, "title": "Maak verbinding met de DoorBird" diff --git a/homeassistant/components/doorbird/util.py b/homeassistant/components/doorbird/util.py index 7db9063580d..55974bc1866 100644 --- a/homeassistant/components/doorbird/util.py +++ b/homeassistant/components/doorbird/util.py @@ -11,9 +11,32 @@ def get_mac_address_from_doorstation_info(doorstation_info): def get_doorstation_by_token(hass, token): - """Get doorstation by slug.""" - for config_entry_id in hass.data[DOMAIN]: - doorstation = hass.data[DOMAIN][config_entry_id][DOOR_STATION] + """Get doorstation by token.""" + return _get_doorstation_by_attr(hass, "token", token) - if token == doorstation.token: + +def get_doorstation_by_slug(hass, slug): + """Get doorstation by slug.""" + return _get_doorstation_by_attr(hass, "slug", slug) + + +def _get_doorstation_by_attr(hass, attr, val): + for entry in hass.data[DOMAIN].values(): + if DOOR_STATION not in entry: + continue + + doorstation = entry[DOOR_STATION] + + if getattr(doorstation, attr) == val: return doorstation + + return None + + +def get_all_doorstations(hass): + """Get all doorstations.""" + return [ + entry[DOOR_STATION] + for entry in hass.data[DOMAIN].values() + if DOOR_STATION in entry + ] diff --git a/homeassistant/components/dsmr/__init__.py b/homeassistant/components/dsmr/__init__.py index 01c98496de2..50823bb1d29 100644 --- a/homeassistant/components/dsmr/__init__.py +++ b/homeassistant/components/dsmr/__init__.py @@ -5,7 +5,7 @@ from asyncio import CancelledError from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from .const import DATA_TASK, DOMAIN, PLATFORMS +from .const import DATA_LISTENER, DATA_TASK, DOMAIN, PLATFORMS async def async_setup(hass, config: dict): @@ -23,12 +23,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): hass.config_entries.async_forward_entry_setup(entry, platform) ) + listener = entry.add_update_listener(async_update_options) + hass.data[DOMAIN][entry.entry_id][DATA_LISTENER] = listener + return True async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unload a config entry.""" task = hass.data[DOMAIN][entry.entry_id][DATA_TASK] + listener = hass.data[DOMAIN][entry.entry_id][DATA_LISTENER] # Cancel the reconnect task task.cancel() @@ -46,6 +50,13 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): ) ) if unload_ok: + listener() + hass.data[DOMAIN].pop(entry.entry_id) return unload_ok + + +async def async_update_options(hass: HomeAssistant, config_entry: ConfigEntry): + """Update options.""" + await hass.config_entries.async_reload(config_entry.entry_id) diff --git a/homeassistant/components/dsmr/config_flow.py b/homeassistant/components/dsmr/config_flow.py index 724f9393fbf..912deb7ffea 100644 --- a/homeassistant/components/dsmr/config_flow.py +++ b/homeassistant/components/dsmr/config_flow.py @@ -8,14 +8,18 @@ from async_timeout import timeout from dsmr_parser import obis_references as obis_ref from dsmr_parser.clients.protocol import create_dsmr_reader, create_tcp_dsmr_reader import serial +import voluptuous as vol from homeassistant import config_entries, core, exceptions from homeassistant.const import CONF_HOST, CONF_PORT +from homeassistant.core import callback from .const import ( # pylint:disable=unused-import CONF_DSMR_VERSION, CONF_SERIAL_ID, CONF_SERIAL_ID_GAS, + CONF_TIME_BETWEEN_UPDATE, + DEFAULT_TIME_BETWEEN_UPDATE, DOMAIN, ) @@ -115,6 +119,12 @@ class DSMRFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH + @staticmethod + @callback + def async_get_options_flow(config_entry): + """Get the options flow for this handler.""" + return DSMROptionFlowHandler(config_entry) + def _abort_if_host_port_configured( self, port: str, @@ -174,6 +184,33 @@ class DSMRFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): return self.async_create_entry(title=name, data=data) +class DSMROptionFlowHandler(config_entries.OptionsFlow): + """Handle options.""" + + def __init__(self, config_entry): + """Initialize options flow.""" + self.config_entry = config_entry + + async def async_step_init(self, user_input=None): + """Manage the options.""" + if user_input is not None: + return self.async_create_entry(title="", data=user_input) + + return self.async_show_form( + step_id="init", + data_schema=vol.Schema( + { + vol.Optional( + CONF_TIME_BETWEEN_UPDATE, + default=self.config_entry.options.get( + CONF_TIME_BETWEEN_UPDATE, DEFAULT_TIME_BETWEEN_UPDATE + ), + ): vol.All(vol.Coerce(int), vol.Range(min=0)), + } + ), + ) + + class CannotConnect(exceptions.HomeAssistantError): """Error to indicate we cannot connect.""" diff --git a/homeassistant/components/dsmr/const.py b/homeassistant/components/dsmr/const.py index ed5f8bf0ed7..da804857845 100644 --- a/homeassistant/components/dsmr/const.py +++ b/homeassistant/components/dsmr/const.py @@ -7,6 +7,7 @@ PLATFORMS = ["sensor"] CONF_DSMR_VERSION = "dsmr_version" CONF_RECONNECT_INTERVAL = "reconnect_interval" CONF_PRECISION = "precision" +CONF_TIME_BETWEEN_UPDATE = "time_between_update" CONF_SERIAL_ID = "serial_id" CONF_SERIAL_ID_GAS = "serial_id_gas" @@ -15,9 +16,14 @@ DEFAULT_DSMR_VERSION = "2.2" DEFAULT_PORT = "/dev/ttyUSB0" DEFAULT_PRECISION = 3 DEFAULT_RECONNECT_INTERVAL = 30 +DEFAULT_TIME_BETWEEN_UPDATE = 30 +DATA_LISTENER = "listener" DATA_TASK = "task" +DEVICE_NAME_ENERGY = "Energy Meter" +DEVICE_NAME_GAS = "Gas Meter" + ICON_GAS = "mdi:fire" ICON_POWER = "mdi:flash" ICON_POWER_FAILURE = "mdi:flash-off" diff --git a/homeassistant/components/dsmr/sensor.py b/homeassistant/components/dsmr/sensor.py index 7b9f9bab6f1..cc1877fb5bb 100644 --- a/homeassistant/components/dsmr/sensor.py +++ b/homeassistant/components/dsmr/sensor.py @@ -1,8 +1,10 @@ """Support for Dutch Smart Meter (also known as Smartmeter or P1 port).""" import asyncio from asyncio import CancelledError +from datetime import timedelta from functools import partial import logging +from typing import Dict from dsmr_parser import obis_references as obis_ref from dsmr_parser.clients.protocol import create_dsmr_reader, create_tcp_dsmr_reader @@ -21,16 +23,23 @@ from homeassistant.core import CoreState, callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.util import Throttle from .const import ( CONF_DSMR_VERSION, CONF_PRECISION, CONF_RECONNECT_INTERVAL, + CONF_SERIAL_ID, + CONF_SERIAL_ID_GAS, + CONF_TIME_BETWEEN_UPDATE, DATA_TASK, DEFAULT_DSMR_VERSION, DEFAULT_PORT, DEFAULT_PRECISION, DEFAULT_RECONNECT_INTERVAL, + DEFAULT_TIME_BETWEEN_UPDATE, + DEVICE_NAME_ENERGY, + DEVICE_NAME_GAS, DOMAIN, ICON_GAS, ICON_POWER, @@ -66,10 +75,8 @@ async def async_setup_entry( hass: HomeAssistantType, entry: ConfigEntry, async_add_entities ) -> None: """Set up the DSMR sensor.""" - # Suppress logging - logging.getLogger("dsmr_parser").setLevel(logging.ERROR) - config = entry.data + options = entry.options dsmr_version = config[CONF_DSMR_VERSION] @@ -106,24 +113,45 @@ async def async_setup_entry( ] # Generate device entities - devices = [DSMREntity(name, obis, config) for name, obis in obis_mapping] + devices = [ + DSMREntity(name, DEVICE_NAME_ENERGY, config[CONF_SERIAL_ID], obis, config) + for name, obis in obis_mapping + ] # Protocol version specific obis - if dsmr_version in ("4", "5"): - gas_obis = obis_ref.HOURLY_GAS_METER_READING - elif dsmr_version in ("5B",): - gas_obis = obis_ref.BELGIUM_HOURLY_GAS_METER_READING - else: - gas_obis = obis_ref.GAS_METER_READING + if CONF_SERIAL_ID_GAS in config: + if dsmr_version in ("4", "5"): + gas_obis = obis_ref.HOURLY_GAS_METER_READING + elif dsmr_version in ("5B",): + gas_obis = obis_ref.BELGIUM_HOURLY_GAS_METER_READING + else: + gas_obis = obis_ref.GAS_METER_READING - # Add gas meter reading and derivative for usage - devices += [ - DSMREntity("Gas Consumption", gas_obis, config), - DerivativeDSMREntity("Hourly Gas Consumption", gas_obis, config), - ] + # Add gas meter reading and derivative for usage + devices += [ + DSMREntity( + "Gas Consumption", + DEVICE_NAME_GAS, + config[CONF_SERIAL_ID_GAS], + gas_obis, + config, + ), + DerivativeDSMREntity( + "Hourly Gas Consumption", + DEVICE_NAME_GAS, + config[CONF_SERIAL_ID_GAS], + gas_obis, + config, + ), + ] async_add_entities(devices) + min_time_between_updates = timedelta( + seconds=options.get(CONF_TIME_BETWEEN_UPDATE, DEFAULT_TIME_BETWEEN_UPDATE) + ) + + @Throttle(min_time_between_updates) def update_entities_telegram(telegram): """Update entities with latest telegram and trigger state update.""" # Make all device entities aware of new telegram @@ -209,18 +237,22 @@ async def async_setup_entry( class DSMREntity(Entity): """Entity reading values from DSMR telegram.""" - def __init__(self, name, obis, config): + def __init__(self, name, device_name, device_serial, obis, config): """Initialize entity.""" self._name = name self._obis = obis self._config = config self.telegram = {} + self._device_name = device_name + self._device_serial = device_serial + self._unique_id = f"{device_serial}_{name}".replace(" ", "_") + @callback def update_data(self, telegram): """Update data.""" self.telegram = telegram - if self.hass: + if self.hass and self._obis in self.telegram: self.async_write_ha_state() def get_dsmr_object_attr(self, attribute): @@ -273,6 +305,19 @@ class DSMREntity(Entity): """Return the unit of measurement of this entity, if any.""" return self.get_dsmr_object_attr("unit") + @property + def unique_id(self) -> str: + """Return a unique ID.""" + return self._unique_id + + @property + def device_info(self) -> Dict[str, any]: + """Return the device information.""" + return { + "identifiers": {(DOMAIN, self._device_serial)}, + "name": self._device_name, + } + @property def force_update(self): """Force update.""" diff --git a/homeassistant/components/dsmr/strings.json b/homeassistant/components/dsmr/strings.json index bc498971960..57d38f78feb 100644 --- a/homeassistant/components/dsmr/strings.json +++ b/homeassistant/components/dsmr/strings.json @@ -5,5 +5,15 @@ "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "Minimum time between entity updates [s]" + }, + "title": "DSMR Options" + } + } } } diff --git a/homeassistant/components/dsmr/translations/ca.json b/homeassistant/components/dsmr/translations/ca.json index 14e637f5f98..a876776fea2 100644 --- a/homeassistant/components/dsmr/translations/ca.json +++ b/homeassistant/components/dsmr/translations/ca.json @@ -3,5 +3,15 @@ "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat" } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "Temps m\u00ednim entre actualitzacions d'entitats [s]" + }, + "title": "Opcions de DSMR" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/dsmr/translations/cs.json b/homeassistant/components/dsmr/translations/cs.json index 33006d6761b..9b38d280bdf 100644 --- a/homeassistant/components/dsmr/translations/cs.json +++ b/homeassistant/components/dsmr/translations/cs.json @@ -3,5 +3,15 @@ "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "Minim\u00e1ln\u00ed doba mezi aktualizacemi entit (v sekund\u00e1ch)" + }, + "title": "Mo\u017enosti DSMR" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/dsmr/translations/en.json b/homeassistant/components/dsmr/translations/en.json index 1344d2f6988..159ede41b4e 100644 --- a/homeassistant/components/dsmr/translations/en.json +++ b/homeassistant/components/dsmr/translations/en.json @@ -3,5 +3,15 @@ "abort": { "already_configured": "Device is already configured" } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "Minimum time between entity updates [s]" + }, + "title": "DSMR Options" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/dsmr/translations/es.json b/homeassistant/components/dsmr/translations/es.json index e8e23bf8343..364953d39d6 100644 --- a/homeassistant/components/dsmr/translations/es.json +++ b/homeassistant/components/dsmr/translations/es.json @@ -3,5 +3,15 @@ "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado" } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "Tiempo m\u00ednimo entre actualizaciones de entidad [s]" + }, + "title": "Opciones DSMR" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/dsmr/translations/et.json b/homeassistant/components/dsmr/translations/et.json index b610820f45e..67f37f26586 100644 --- a/homeassistant/components/dsmr/translations/et.json +++ b/homeassistant/components/dsmr/translations/et.json @@ -11,5 +11,15 @@ "one": "\u00fcks", "other": "mitu" } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "Minimaalne aeg olemi v\u00e4rskenduste vahel [s]" + }, + "title": "DSMR-i valikud" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/dsmr/translations/nl.json b/homeassistant/components/dsmr/translations/nl.json index 8b2702b6708..41edcd176da 100644 --- a/homeassistant/components/dsmr/translations/nl.json +++ b/homeassistant/components/dsmr/translations/nl.json @@ -2,6 +2,14 @@ "config": { "abort": { "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "one": "Leeg", + "other": "Leeg" + }, + "step": { + "one": "Leeg", + "other": "Leeg" } } } \ No newline at end of file diff --git a/homeassistant/components/dsmr/translations/no.json b/homeassistant/components/dsmr/translations/no.json index 6ba5a1f3978..e51520bf730 100644 --- a/homeassistant/components/dsmr/translations/no.json +++ b/homeassistant/components/dsmr/translations/no.json @@ -3,5 +3,15 @@ "abort": { "already_configured": "Enheten er allerede konfigurert" } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "Minimum tid mellom entitetsoppdateringer [s]" + }, + "title": "DSMR alternativer" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/dsmr/translations/pl.json b/homeassistant/components/dsmr/translations/pl.json index e0a493fc047..e8b8bf617f0 100644 --- a/homeassistant/components/dsmr/translations/pl.json +++ b/homeassistant/components/dsmr/translations/pl.json @@ -15,5 +15,15 @@ "one": "jeden", "other": "inne" } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "Minimalny czas mi\u0119dzy aktualizacjami encji [s]" + }, + "title": "Opcje DSMR" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/dsmr/translations/ru.json b/homeassistant/components/dsmr/translations/ru.json index 4ad85f691be..3bf0cf9f06f 100644 --- a/homeassistant/components/dsmr/translations/ru.json +++ b/homeassistant/components/dsmr/translations/ru.json @@ -3,5 +3,15 @@ "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." } + }, + "options": { + "step": { + "init": { + "data": { + "time_between_update": "\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f (\u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445)" + }, + "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 DSMR" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/dunehd/translations/cs.json b/homeassistant/components/dunehd/translations/cs.json index 231ff6055b6..b52eb3d2cdf 100644 --- a/homeassistant/components/dunehd/translations/cs.json +++ b/homeassistant/components/dunehd/translations/cs.json @@ -13,6 +13,7 @@ "data": { "host": "Hostitel" }, + "description": "Nastaven\u00ed integrace Dune HD. Pokud m\u00e1te probl\u00e9my s nastaven\u00edm, p\u0159ejd\u011bte na: https://www.home-assistant.io/integrations/dunehd \n\nUjist\u011bte se, \u017ee je v\u00e1\u0161 p\u0159ehr\u00e1va\u010d zapnut\u00fd.", "title": "Dune HD" } } diff --git a/homeassistant/components/dunehd/translations/nl.json b/homeassistant/components/dunehd/translations/nl.json new file mode 100644 index 00000000000..91325588b13 --- /dev/null +++ b/homeassistant/components/dunehd/translations/nl.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "already_configured": "Apparaat is al geconfigureerd", + "cannot_connect": "Kon niet verbinden" + }, + "step": { + "user": { + "data": { + "host": "Host" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/dyson/sensor.py b/homeassistant/components/dyson/sensor.py index f26d83de45d..1629d0fa06b 100644 --- a/homeassistant/components/dyson/sensor.py +++ b/homeassistant/components/dyson/sensor.py @@ -13,6 +13,8 @@ SENSOR_UNITS = { "air_quality": None, "dust": None, "filter_life": TIME_HOURS, + "carbon_filter_state": PERCENTAGE, + "hepa_filter_state": PERCENTAGE, "humidity": PERCENTAGE, } @@ -20,6 +22,8 @@ SENSOR_ICONS = { "air_quality": "mdi:fan", "dust": "mdi:cloud", "filter_life": "mdi:filter-outline", + "carbon_filter_state": "mdi:filter-outline", + "hepa_filter_state": "mdi:filter-outline", "humidity": "mdi:water-percent", "temperature": "mdi:thermometer", } @@ -48,6 +52,17 @@ def setup_platform(hass, config, add_entities, discovery_info=None): new_entities.append(DysonTemperatureSensor(device, unit)) if f"{device.serial}-humidity" not in device_ids: new_entities.append(DysonHumiditySensor(device)) + + # For PureCool+Humidify devices, a single filter exists, called "Combi Filter". + # It's reported with the HEPA state, while the Carbon state is set to INValid. + if device.state and device.state.carbon_filter_state == "INV": + if f"{device.serial}-hepa_filter_state" not in device_ids: + new_entities.append(DysonHepaFilterLifeSensor(device, "Combi")) + else: + if f"{device.serial}-hepa_filter_state" not in device_ids: + new_entities.append(DysonHepaFilterLifeSensor(device)) + if f"{device.serial}-carbon_filter_state" not in device_ids: + new_entities.append(DysonCarbonFilterLifeSensor(device)) elif isinstance(device, DysonPureCoolLink): new_entities.append(DysonFilterLifeSensor(device)) new_entities.append(DysonDustSensor(device)) @@ -126,6 +141,38 @@ class DysonFilterLifeSensor(DysonSensor): return None +class DysonCarbonFilterLifeSensor(DysonSensor): + """Representation of Dyson Carbon Filter Life sensor (in percent).""" + + def __init__(self, device): + """Create a new Dyson Carbon Filter Life sensor.""" + super().__init__(device, "carbon_filter_state") + self._name = f"{self._device.name} Carbon Filter Remaining Life" + + @property + def state(self): + """Return filter life remaining in percent.""" + if self._device.state: + return int(self._device.state.carbon_filter_state) + return None + + +class DysonHepaFilterLifeSensor(DysonSensor): + """Representation of Dyson HEPA (or Combi) Filter Life sensor (in percent).""" + + def __init__(self, device, filter_type="HEPA"): + """Create a new Dyson Filter Life sensor.""" + super().__init__(device, "hepa_filter_state") + self._name = f"{self._device.name} {filter_type} Filter Remaining Life" + + @property + def state(self): + """Return filter life remaining in percent.""" + if self._device.state: + return int(self._device.state.hepa_filter_state) + return None + + class DysonDustSensor(DysonSensor): """Representation of Dyson Dust sensor (lower is better).""" diff --git a/homeassistant/components/eafm/translations/nl.json b/homeassistant/components/eafm/translations/nl.json new file mode 100644 index 00000000000..8b2702b6708 --- /dev/null +++ b/homeassistant/components/eafm/translations/nl.json @@ -0,0 +1,7 @@ +{ + "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/ecobee/translations/bg.json b/homeassistant/components/ecobee/translations/bg.json index 773bc6bd11f..01aeb223573 100644 --- a/homeassistant/components/ecobee/translations/bg.json +++ b/homeassistant/components/ecobee/translations/bg.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "\u0422\u0430\u0437\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u043e \u043a\u043e\u043f\u0438\u0435 \u043d\u0430 ecobee." - }, "error": { "pin_request_failed": "\u0413\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0438\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u041f\u0418\u041d \u043e\u0442 ecobee; \u043c\u043e\u043b\u044f, \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u0442\u0435 \u0434\u0430\u043b\u0438 API \u043a\u043b\u044e\u0447\u044a\u0442 \u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d.", "token_request_failed": "\u0413\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0438\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0434\u043e\u0432\u0435 \u043e\u0442 ecobee; \u043c\u043e\u043b\u044f, \u043e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e." diff --git a/homeassistant/components/ecobee/translations/ca.json b/homeassistant/components/ecobee/translations/ca.json index 8b20669c76b..46d42d0774b 100644 --- a/homeassistant/components/ecobee/translations/ca.json +++ b/homeassistant/components/ecobee/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "Aquesta integraci\u00f3 nom\u00e9s admet una sola inst\u00e0ncia ecobee.", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "error": { diff --git a/homeassistant/components/ecobee/translations/cs.json b/homeassistant/components/ecobee/translations/cs.json index 9e105bebbd6..cad19eff739 100644 --- a/homeassistant/components/ecobee/translations/cs.json +++ b/homeassistant/components/ecobee/translations/cs.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "Tato integrace v sou\u010dasn\u00e9 dob\u011b podporuje pouze jednu instanci ekobee.", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "step": { diff --git a/homeassistant/components/ecobee/translations/da.json b/homeassistant/components/ecobee/translations/da.json index 27af2cc0987..84848cf6be8 100644 --- a/homeassistant/components/ecobee/translations/da.json +++ b/homeassistant/components/ecobee/translations/da.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "Denne integration underst\u00f8tter i \u00f8jeblikket kun en ecobee-instans." - }, "error": { "pin_request_failed": "Fejl ved anmodning om pinkode fra ecobee. Kontroller at API-n\u00f8glen er korrekt.", "token_request_failed": "Fejl ved anmodning om tokens fra ecobee. Pr\u00f8v igen." diff --git a/homeassistant/components/ecobee/translations/de.json b/homeassistant/components/ecobee/translations/de.json index 2348edc9182..bc65fddebdd 100644 --- a/homeassistant/components/ecobee/translations/de.json +++ b/homeassistant/components/ecobee/translations/de.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "Diese Integration unterst\u00fctzt derzeit nur eine Ecobee-Instanz." - }, "error": { "pin_request_failed": "Fehler beim Anfordern der PIN von ecobee; Bitte \u00fcberpr\u00fcfe, ob der API-Schl\u00fcssel korrekt ist.", "token_request_failed": "Fehler beim Anfordern eines Token von ecobee; Bitte versuche es erneut." diff --git a/homeassistant/components/ecobee/translations/en.json b/homeassistant/components/ecobee/translations/en.json index 024ac774133..1dfcc2f6a19 100644 --- a/homeassistant/components/ecobee/translations/en.json +++ b/homeassistant/components/ecobee/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "This integration currently supports only one ecobee instance.", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "error": { diff --git a/homeassistant/components/ecobee/translations/es-419.json b/homeassistant/components/ecobee/translations/es-419.json index 50eab590a1c..78d41c2c0fc 100644 --- a/homeassistant/components/ecobee/translations/es-419.json +++ b/homeassistant/components/ecobee/translations/es-419.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "Esta integraci\u00f3n actualmente solo admite una instancia de ecobee." - }, "error": { "pin_request_failed": "Error al solicitar PIN de ecobee; verifique que la clave API sea correcta.", "token_request_failed": "Error al solicitar tokens de ecobee; Int\u00e9ntelo de nuevo." diff --git a/homeassistant/components/ecobee/translations/es.json b/homeassistant/components/ecobee/translations/es.json index 88fbf9ed335..f4980f46bbb 100644 --- a/homeassistant/components/ecobee/translations/es.json +++ b/homeassistant/components/ecobee/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "Esta integraci\u00f3n actualmente solo admite una instancia de ecobee.", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "error": { diff --git a/homeassistant/components/ecobee/translations/et.json b/homeassistant/components/ecobee/translations/et.json index 484e56f6ccc..46c332a5356 100644 --- a/homeassistant/components/ecobee/translations/et.json +++ b/homeassistant/components/ecobee/translations/et.json @@ -1,11 +1,11 @@ { "config": { "abort": { - "one_instance_only": "See sidumine toetab praegu ainult \u00fchte ecobee \u00fcksust.", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "error": { - "pin_request_failed": "Viga ecobee'lt PIN-koodi taotlemisel. Palun veendu, et API v\u00f5ti on \u00f5ige." + "pin_request_failed": "Viga ecobee'lt PIN-koodi taotlemisel. Palun veendu, et API v\u00f5ti on \u00f5ige.", + "token_request_failed": "Viga ecobee-lt m\u00e4rgendite taotlemisel. Palun proovi uuesti." }, "step": { "authorize": { diff --git a/homeassistant/components/ecobee/translations/fr.json b/homeassistant/components/ecobee/translations/fr.json index 46e56ce8a16..cfb307053da 100644 --- a/homeassistant/components/ecobee/translations/fr.json +++ b/homeassistant/components/ecobee/translations/fr.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "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/ecobee/translations/hu.json b/homeassistant/components/ecobee/translations/hu.json index 4910991e738..bd620bc9685 100644 --- a/homeassistant/components/ecobee/translations/hu.json +++ b/homeassistant/components/ecobee/translations/hu.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "Ez az integr\u00e1ci\u00f3 jelenleg csak egy ecobee p\u00e9ld\u00e1nyt t\u00e1mogat." - }, "error": { "pin_request_failed": "Hiba t\u00f6rt\u00e9nt a PIN-k\u00f3d ecobee-t\u0151l t\u00f6rt\u00e9n\u0151 k\u00e9r\u00e9sekor; ellen\u0151rizze, hogy az API-kulcs helyes-e.", "token_request_failed": "Hiba t\u00f6rt\u00e9nt a tokenek ecobee-t\u0151l t\u00f6rt\u00e9n\u0151 ig\u00e9nyl\u00e9se k\u00f6zben; pr\u00f3b\u00e1lkozzon \u00fajra." diff --git a/homeassistant/components/ecobee/translations/it.json b/homeassistant/components/ecobee/translations/it.json index b2436622010..74e8ae6258b 100644 --- a/homeassistant/components/ecobee/translations/it.json +++ b/homeassistant/components/ecobee/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "Questa integrazione supporta attualmente una sola istanza ecobee.", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "error": { diff --git a/homeassistant/components/ecobee/translations/ko.json b/homeassistant/components/ecobee/translations/ko.json index 9666f572d8b..8be4c28bfbb 100644 --- a/homeassistant/components/ecobee/translations/ko.json +++ b/homeassistant/components/ecobee/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "\uc774 \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\ub294 \ud604\uc7ac \ud558\ub098\uc758 ecobee \uc778\uc2a4\ud134\uc2a4\ub9cc \uc9c0\uc6d0\ud569\ub2c8\ub2e4." - }, "error": { "pin_request_failed": "ecobee \ub85c\ubd80\ud130 PIN \uc694\uccad\uc5d0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4; API \ud0a4\uac00 \uc62c\ubc14\ub978\uc9c0 \ud655\uc778\ud574\uc8fc\uc138\uc694.", "token_request_failed": "ecobee \ub85c\ubd80\ud130 \ud1a0\ud070 \uc694\uccad\uc5d0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4; \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694." diff --git a/homeassistant/components/ecobee/translations/lb.json b/homeassistant/components/ecobee/translations/lb.json index adcee0b0849..1769da0253b 100644 --- a/homeassistant/components/ecobee/translations/lb.json +++ b/homeassistant/components/ecobee/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "one_instance_only": "D\u00ebs Integratioun \u00ebnnerst\u00ebtzt n\u00ebmmen eng ecobee Instanz." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { "pin_request_failed": "Feeler beim ufroe vum PIN vun ecobee; iwwerpr\u00e9ift op den API Schl\u00ebssel korrekt ass.", diff --git a/homeassistant/components/ecobee/translations/nl.json b/homeassistant/components/ecobee/translations/nl.json index 9bb62c258c8..62405b05ff1 100644 --- a/homeassistant/components/ecobee/translations/nl.json +++ b/homeassistant/components/ecobee/translations/nl.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "Deze integratie ondersteunt momenteel slechts \u00e9\u00e9n ecobee-instantie." - }, "error": { "pin_request_failed": "Fout bij het aanvragen van pincode bij ecobee; Controleer of de API-sleutel correct is.", "token_request_failed": "Fout bij het aanvragen van tokens bij ecobee; probeer het opnieuw." diff --git a/homeassistant/components/ecobee/translations/no.json b/homeassistant/components/ecobee/translations/no.json index 6a7acc77aec..f3c2eceee44 100644 --- a/homeassistant/components/ecobee/translations/no.json +++ b/homeassistant/components/ecobee/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "Denne integrasjonen st\u00f8tter forel\u00f8pig bare \u00e9n ecobee-forekomst.", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "error": { diff --git a/homeassistant/components/ecobee/translations/pl.json b/homeassistant/components/ecobee/translations/pl.json index 924ebf1d813..52b28f91a95 100644 --- a/homeassistant/components/ecobee/translations/pl.json +++ b/homeassistant/components/ecobee/translations/pl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "Komponent obs\u0142uguje tylko jedn\u0105 instancj\u0119 ecobee", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "error": { diff --git a/homeassistant/components/ecobee/translations/pt-BR.json b/homeassistant/components/ecobee/translations/pt-BR.json index 8b970c140be..921319f55d0 100644 --- a/homeassistant/components/ecobee/translations/pt-BR.json +++ b/homeassistant/components/ecobee/translations/pt-BR.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "Essa integra\u00e7\u00e3o atualmente suporta apenas uma inst\u00e2ncia ecobee." - }, "error": { "token_request_failed": "Erro ao solicitar tokens da ecobee; Por favor, tente novamente." }, diff --git a/homeassistant/components/ecobee/translations/ru.json b/homeassistant/components/ecobee/translations/ru.json index f9c12b5b3a3..f983a80b389 100644 --- a/homeassistant/components/ecobee/translations/ru.json +++ b/homeassistant/components/ecobee/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "\u042d\u0442\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 ecobee.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "error": { diff --git a/homeassistant/components/ecobee/translations/sl.json b/homeassistant/components/ecobee/translations/sl.json index ee84a98cf34..80a864d16eb 100644 --- a/homeassistant/components/ecobee/translations/sl.json +++ b/homeassistant/components/ecobee/translations/sl.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "Ta integracija trenutno podpira samo en primerek ecobee." - }, "error": { "pin_request_failed": "Napaka pri zahtevi PIN-a od ecobee; preverite, ali je klju\u010d API pravilen.", "token_request_failed": "Napaka pri zahtevanju \u017eetonov od ecobeeja; prosim poskusite ponovno." diff --git a/homeassistant/components/ecobee/translations/sv.json b/homeassistant/components/ecobee/translations/sv.json index 4bfb4e0ec12..d78d5ba521e 100644 --- a/homeassistant/components/ecobee/translations/sv.json +++ b/homeassistant/components/ecobee/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_only": "Denna integration st\u00f6der f\u00f6r n\u00e4rvarande endast en ecobee-instans." - }, "error": { "pin_request_failed": "Fel vid beg\u00e4ran av PIN-kod fr\u00e5n ecobee. kontrollera API-nyckeln \u00e4r korrekt.", "token_request_failed": "Fel vid beg\u00e4ran av tokens fr\u00e5n ecobee; v\u00e4nligen f\u00f6rs\u00f6k igen." diff --git a/homeassistant/components/ecobee/translations/zh-Hans.json b/homeassistant/components/ecobee/translations/zh-Hans.json new file mode 100644 index 00000000000..baf8c980cb7 --- /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/ecobee/translations/zh-Hant.json b/homeassistant/components/ecobee/translations/zh-Hant.json index 64d8d32da15..54cad2049fd 100644 --- a/homeassistant/components/ecobee/translations/zh-Hant.json +++ b/homeassistant/components/ecobee/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_only": "\u6b64\u6574\u5408\u76ee\u524d\u50c5\u652f\u63f4\u4e00\u7d44 ecobee \u8a2d\u5099\u3002", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "error": { diff --git a/homeassistant/components/eight_sleep/manifest.json b/homeassistant/components/eight_sleep/manifest.json index b8be5757df9..1de572d1410 100644 --- a/homeassistant/components/eight_sleep/manifest.json +++ b/homeassistant/components/eight_sleep/manifest.json @@ -2,6 +2,6 @@ "domain": "eight_sleep", "name": "Eight Sleep", "documentation": "https://www.home-assistant.io/integrations/eight_sleep", - "requirements": ["pyeight==0.1.4"], + "requirements": ["pyeight==0.1.5"], "codeowners": ["@mezz64"] } diff --git a/homeassistant/components/elgato/translations/ca.json b/homeassistant/components/elgato/translations/ca.json index 04cf0488dc6..f662da3b0cc 100644 --- a/homeassistant/components/elgato/translations/ca.json +++ b/homeassistant/components/elgato/translations/ca.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar amb el dispositiu Elgato Key Light." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar amb el dispositiu Elgato Key Light." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/cs.json b/homeassistant/components/elgato/translations/cs.json index 8da0e6ccb79..c95c7d98aad 100644 --- a/homeassistant/components/elgato/translations/cs.json +++ b/homeassistant/components/elgato/translations/cs.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed Elgato Key Light se nezda\u0159ilo." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed Elgato Key Light se nezda\u0159ilo." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { @@ -19,6 +17,7 @@ "description": "Nastavte Elgato Key Light k integraci s Home Assistant." }, "zeroconf_confirm": { + "description": "Chcete p\u0159idat Elgato Key Light se s\u00e9riov\u00fdm \u010d\u00edslem `{serial_number}` do Home Assistant?", "title": "Objeven\u00e9 za\u0159\u00edzen\u00ed Elgato Key Light" } } diff --git a/homeassistant/components/elgato/translations/da.json b/homeassistant/components/elgato/translations/da.json index 172b3b9b806..74dddda9212 100644 --- a/homeassistant/components/elgato/translations/da.json +++ b/homeassistant/components/elgato/translations/da.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Denne Elgato Key Light-enhed er allerede konfigureret.", - "connection_error": "Kunne ikke oprette forbindelse til Elgato Key Light-enheden." - }, - "error": { - "connection_error": "Kunne ikke oprette forbindelse til Elgato Key Light-enheden." + "already_configured": "Denne Elgato Key Light-enhed er allerede konfigureret." }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/de.json b/homeassistant/components/elgato/translations/de.json index 1ceac4a246c..4d10424216e 100644 --- a/homeassistant/components/elgato/translations/de.json +++ b/homeassistant/components/elgato/translations/de.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Dieses Elgato Key Light-Ger\u00e4t ist bereits konfiguriert.", - "connection_error": "Verbindung zum Elgato Key Light-Ger\u00e4t fehlgeschlagen." - }, - "error": { - "connection_error": "Verbindung zum Elgato Key Light-Ger\u00e4t fehlgeschlagen." + "already_configured": "Dieses Elgato Key Light-Ger\u00e4t ist bereits konfiguriert." }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/en.json b/homeassistant/components/elgato/translations/en.json index 607ab996406..7866631db42 100644 --- a/homeassistant/components/elgato/translations/en.json +++ b/homeassistant/components/elgato/translations/en.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Device is already configured", - "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect to Elgato Key Light device." + "cannot_connect": "Failed to connect" }, "error": { - "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect to Elgato Key Light device." + "cannot_connect": "Failed to connect" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/es-419.json b/homeassistant/components/elgato/translations/es-419.json index 4482d630bd8..b7bf5a9441c 100644 --- a/homeassistant/components/elgato/translations/es-419.json +++ b/homeassistant/components/elgato/translations/es-419.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Este dispositivo Elgato Key Light ya est\u00e1 configurado.", - "connection_error": "No se pudo conectar al dispositivo Elgato Key Light." - }, - "error": { - "connection_error": "No se pudo conectar al dispositivo Elgato Key Light." + "already_configured": "Este dispositivo Elgato Key Light ya est\u00e1 configurado." }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/es.json b/homeassistant/components/elgato/translations/es.json index 3509c135bb0..940272f5562 100644 --- a/homeassistant/components/elgato/translations/es.json +++ b/homeassistant/components/elgato/translations/es.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Este dispositivo Elgato Key Light ya est\u00e1 configurado.", - "cannot_connect": "No se pudo conectar", - "connection_error": "No se pudo conectar al dispositivo Elgato Key Light." + "cannot_connect": "No se pudo conectar" }, "error": { - "cannot_connect": "No se pudo conectar", - "connection_error": "No se pudo conectar al dispositivo Elgato Key Light." + "cannot_connect": "No se pudo conectar" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/et.json b/homeassistant/components/elgato/translations/et.json index 1e7316beb2b..61357ccb601 100644 --- a/homeassistant/components/elgato/translations/et.json +++ b/homeassistant/components/elgato/translations/et.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "Elgato Key Light seadmega \u00fchenduse loomine nurjus." + "cannot_connect": "\u00dchendamine nurjus" }, "error": { - "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "Elgato Key Light seadmega \u00fchenduse loomine nurjus." + "cannot_connect": "\u00dchendamine nurjus" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/fr.json b/homeassistant/components/elgato/translations/fr.json index 7e054716625..ccc325c84e2 100644 --- a/homeassistant/components/elgato/translations/fr.json +++ b/homeassistant/components/elgato/translations/fr.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Cet appareil Elgato Key Light est d\u00e9j\u00e0 configur\u00e9.", - "cannot_connect": "\u00c9chec de connexion", - "connection_error": "Impossible de se connecter au p\u00e9riph\u00e9rique Elgato Key Light." + "cannot_connect": "\u00c9chec de connexion" }, "error": { - "cannot_connect": "\u00c9chec de connexion", - "connection_error": "Impossible de se connecter au p\u00e9riph\u00e9rique Elgato Key Light." + "cannot_connect": "\u00c9chec de connexion" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/hu.json b/homeassistant/components/elgato/translations/hu.json index 54461a8c553..dcfcb155d12 100644 --- a/homeassistant/components/elgato/translations/hu.json +++ b/homeassistant/components/elgato/translations/hu.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Ez az Elgato Key Light eszk\u00f6z m\u00e1r konfigur\u00e1lva van.", - "connection_error": "Nem siker\u00fclt csatlakozni az Elgato Key Light eszk\u00f6zh\u00f6z." + "already_configured": "Ez az Elgato Key Light eszk\u00f6z m\u00e1r konfigur\u00e1lva van." }, "step": { "user": { diff --git a/homeassistant/components/elgato/translations/it.json b/homeassistant/components/elgato/translations/it.json index 2f1f2130a0b..00c0937e008 100644 --- a/homeassistant/components/elgato/translations/it.json +++ b/homeassistant/components/elgato/translations/it.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi al dispositivo Elgato Key Light." + "cannot_connect": "Impossibile connettersi" }, "error": { - "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi al dispositivo Elgato Key Light." + "cannot_connect": "Impossibile connettersi" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/ko.json b/homeassistant/components/elgato/translations/ko.json index 3e24c487850..d11b106e28b 100644 --- a/homeassistant/components/elgato/translations/ko.json +++ b/homeassistant/components/elgato/translations/ko.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Elgato Key Light \uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "connection_error": "Elgato Key Light \uae30\uae30\uc5d0 \uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4." - }, - "error": { - "connection_error": "Elgato Key Light \uae30\uae30\uc5d0 \uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4." + "already_configured": "Elgato Key Light \uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/lb.json b/homeassistant/components/elgato/translations/lb.json index 35aa4aaaa64..07a026e67e0 100644 --- a/homeassistant/components/elgato/translations/lb.json +++ b/homeassistant/components/elgato/translations/lb.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured": "D\u00ebsen Elgato Key Light Apparat ass scho konfigur\u00e9iert.", - "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen mam Elgato key Light Apparat." + "already_configured": "Apparat ass scho konfigur\u00e9iert", + "cannot_connect": "Feeler beim verbannen" }, "error": { - "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen mam Elgato key Light Apparat." + "cannot_connect": "Feeler beim verbannen" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/nl.json b/homeassistant/components/elgato/translations/nl.json index dadb6b63c39..81035cc898f 100644 --- a/homeassistant/components/elgato/translations/nl.json +++ b/homeassistant/components/elgato/translations/nl.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Dit Elgato Key Light apparaat is al geconfigureerd.", - "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met het Elgato Key Light apparaat." + "cannot_connect": "Kan geen verbinding maken" }, "error": { - "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met het Elgato Key Light apparaat." + "cannot_connect": "Kan geen verbinding maken" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/no.json b/homeassistant/components/elgato/translations/no.json index b8946898247..8a44fd67972 100644 --- a/homeassistant/components/elgato/translations/no.json +++ b/homeassistant/components/elgato/translations/no.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Enheten er allerede konfigurert", - "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kunne ikke koble til Elgato Key Light-enheten." + "cannot_connect": "Tilkobling mislyktes" }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kunne ikke koble til Elgato Key Light-enheten." + "cannot_connect": "Tilkobling mislyktes" }, "flow_title": "", "step": { diff --git a/homeassistant/components/elgato/translations/pl.json b/homeassistant/components/elgato/translations/pl.json index 1ba836cbfce..8d36d06f501 100644 --- a/homeassistant/components/elgato/translations/pl.json +++ b/homeassistant/components/elgato/translations/pl.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z urz\u0105dzeniem Elgato Key Light" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z urz\u0105dzeniem Elgato Key Light" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/ru.json b/homeassistant/components/elgato/translations/ru.json index b790d2fa66b..7a4cefe2797 100644 --- a/homeassistant/components/elgato/translations/ru.json +++ b/homeassistant/components/elgato/translations/ru.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443 Elgato Key Light." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443 Elgato Key Light." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/sl.json b/homeassistant/components/elgato/translations/sl.json index 16094c361f0..1007d717e11 100644 --- a/homeassistant/components/elgato/translations/sl.json +++ b/homeassistant/components/elgato/translations/sl.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Ta naprava Elgato Key Light je \u017ee nastavljena.", - "connection_error": "Povezava z napravo Elgato Key Light ni uspela." - }, - "error": { - "connection_error": "Povezava z napravo Elgato Key Light ni uspela." + "already_configured": "Ta naprava Elgato Key Light je \u017ee nastavljena." }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/sv.json b/homeassistant/components/elgato/translations/sv.json index b338716a92f..4ed0161b0e3 100644 --- a/homeassistant/components/elgato/translations/sv.json +++ b/homeassistant/components/elgato/translations/sv.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Den h\u00e4r Elgato Key Light-enheten \u00e4r redan konfigurerad.", - "connection_error": "Det gick inte att ansluta till Elgato Key Light-enheten." - }, - "error": { - "connection_error": "Det gick inte att ansluta till Elgato Key Light-enheten." + "already_configured": "Den h\u00e4r Elgato Key Light-enheten \u00e4r redan konfigurerad." }, "flow_title": "Elgato Key Light: {serial_number}", "step": { diff --git a/homeassistant/components/elgato/translations/zh-Hant.json b/homeassistant/components/elgato/translations/zh-Hant.json index 2ddd8e6b23e..e25b4cd7c8f 100644 --- a/homeassistant/components/elgato/translations/zh-Hant.json +++ b/homeassistant/components/elgato/translations/zh-Hant.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "Elgato Key \u7167\u660e\u8a2d\u5099\u9023\u7dda\u5931\u6557\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "Elgato Key \u7167\u660e\u8a2d\u5099\u9023\u7dda\u5931\u6557\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "flow_title": "Elgato Key \u7167\u660e\uff1a{serial_number}", "step": { diff --git a/homeassistant/components/elkm1/__init__.py b/homeassistant/components/elkm1/__init__.py index 146a9a21fb8..e33e1722edf 100644 --- a/homeassistant/components/elkm1/__init__.py +++ b/homeassistant/components/elkm1/__init__.py @@ -249,18 +249,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): for keypad in elk.keypads: # pylint: disable=no-member keypad.add_callback(_element_changed) - if not await async_wait_for_elk_to_sync(elk, SYNC_TIMEOUT): - _LOGGER.error( - "Timed out after %d seconds while trying to sync with ElkM1 at %s", - SYNC_TIMEOUT, - conf[CONF_HOST], - ) - elk.disconnect() - raise ConfigEntryNotReady - - if elk.invalid_auth: - _LOGGER.error("Authentication failed for ElkM1") - return False + try: + if not await async_wait_for_elk_to_sync(elk, SYNC_TIMEOUT, conf[CONF_HOST]): + return False + except asyncio.TimeoutError as exc: + raise ConfigEntryNotReady from exc hass.data[DOMAIN][entry.entry_id] = { "elk": elk, @@ -312,16 +305,40 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): return unload_ok -async def async_wait_for_elk_to_sync(elk, timeout): - """Wait until the elk system has finished sync.""" +async def async_wait_for_elk_to_sync(elk, timeout, conf_host): + """Wait until the elk has finished sync. Can fail login or timeout.""" + + def login_status(succeeded): + nonlocal success + + success = succeeded + if succeeded: + _LOGGER.debug("ElkM1 login succeeded") + else: + elk.disconnect() + _LOGGER.error("ElkM1 login failed; invalid username or password") + event.set() + + def sync_complete(): + event.set() + + success = True + event = asyncio.Event() + elk.add_handler("login", login_status) + elk.add_handler("sync_complete", sync_complete) try: with async_timeout.timeout(timeout): - await elk.sync_complete() - return True + await event.wait() except asyncio.TimeoutError: + _LOGGER.error( + "Timed out after %d seconds while trying to sync with ElkM1 at %s", + timeout, + conf_host, + ) elk.disconnect() + raise - return False + return success def _create_elk_services(hass): diff --git a/homeassistant/components/elkm1/config_flow.py b/homeassistant/components/elkm1/config_flow.py index 419e4df7552..0248025795b 100644 --- a/homeassistant/components/elkm1/config_flow.py +++ b/homeassistant/components/elkm1/config_flow.py @@ -1,4 +1,5 @@ """Config flow for Elk-M1 Control integration.""" +import asyncio import logging from urllib.parse import urlparse @@ -65,20 +66,7 @@ async def validate_input(data): ) elk.connect() - timed_out = False - if not await async_wait_for_elk_to_sync(elk, VALIDATE_TIMEOUT): - _LOGGER.error( - "Timed out after %d seconds while trying to sync with ElkM1 at %s", - VALIDATE_TIMEOUT, - url, - ) - timed_out = True - - elk.disconnect() - - if timed_out: - raise CannotConnect - if elk.invalid_auth: + if not await async_wait_for_elk_to_sync(elk, VALIDATE_TIMEOUT, url): raise InvalidAuth device_name = data[CONF_PREFIX] if data[CONF_PREFIX] else "ElkM1" @@ -116,7 +104,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): try: info = await validate_input(user_input) - except CannotConnect: + except asyncio.TimeoutError: errors["base"] = "cannot_connect" except InvalidAuth: errors["base"] = "invalid_auth" @@ -161,9 +149,5 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): return urlparse(url).hostname in existing_hosts -class CannotConnect(exceptions.HomeAssistantError): - """Error to indicate we cannot connect.""" - - class InvalidAuth(exceptions.HomeAssistantError): """Error to indicate there is invalid auth.""" diff --git a/homeassistant/components/elkm1/manifest.json b/homeassistant/components/elkm1/manifest.json index 0e6fdcfa40c..769e5c37dd7 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.4"], + "requirements": ["elkm1-lib==0.8.8"], "codeowners": ["@gwww", "@bdraco"], "config_flow": true } diff --git a/homeassistant/components/elkm1/translations/cs.json b/homeassistant/components/elkm1/translations/cs.json index e3d4fef45de..2b84b802b6b 100644 --- a/homeassistant/components/elkm1/translations/cs.json +++ b/homeassistant/components/elkm1/translations/cs.json @@ -1,5 +1,9 @@ { "config": { + "abort": { + "address_already_configured": "ElkM1 s touto adresou je ji\u017e nastaven", + "already_configured": "ElkM1 s t\u00edmto prefixem je ji\u017e nastaven" + }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", @@ -9,7 +13,9 @@ "user": { "data": { "password": "Heslo", + "prefix": "Jedine\u010dn\u00fd prefix (ponechte pr\u00e1zdn\u00e9, pokud m\u00e1te pouze jeden ElkM1).", "protocol": "Protokol", + "temperature_unit": "Jednotka teploty pou\u017e\u00edvan\u00e1 ElkM1.", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" }, "title": "P\u0159ipojen\u00ed k ovlada\u010di Elk-M1" diff --git a/homeassistant/components/elkm1/translations/et.json b/homeassistant/components/elkm1/translations/et.json index 49a9a1dce8c..7ced75e0a2b 100644 --- a/homeassistant/components/elkm1/translations/et.json +++ b/homeassistant/components/elkm1/translations/et.json @@ -19,7 +19,8 @@ "temperature_unit": "ElkM1'i temperatuuri\u00fchik.", "username": "Kasutajanimi" }, - "description": "Aadressistring peab olema kujul \"aadress[:port]\" \"secure\" ja \"non-secure\" puhul. N\u00e4ide: \"192.168.1.1\". Port on valikuline ja vaikimisi 2101 \"secure\" ja 2601 \"non-secure puhul\". Jadaprotokolli puhul peab aadress olema kujul \"tty[:baud]\". N\u00e4ide: \"/dev/ttyS1\". Baud on valikuline ja vaikimisi 115200." + "description": "Aadressistring peab olema kujul \"aadress[:port]\" \"secure\" ja \"non-secure\" puhul. N\u00e4ide: \"192.168.1.1\". Port on valikuline ja vaikimisi 2101 \"secure\" ja 2601 \"non-secure puhul\". Jadaprotokolli puhul peab aadress olema kujul \"tty[:baud]\". N\u00e4ide: \"/dev/ttyS1\". Baud on valikuline ja vaikimisi 115200.", + "title": "\u00dchendu Elk-M1 Control" } } } diff --git a/homeassistant/components/elkm1/translations/lb.json b/homeassistant/components/elkm1/translations/lb.json index e6bbb060152..084b4a1347f 100644 --- a/homeassistant/components/elkm1/translations/lb.json +++ b/homeassistant/components/elkm1/translations/lb.json @@ -5,7 +5,7 @@ "already_configured": "Een ElkM1 mat d\u00ebsem Prefix ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, diff --git a/homeassistant/components/elkm1/translations/pl.json b/homeassistant/components/elkm1/translations/pl.json index def260b4bd9..b9c0322af20 100644 --- a/homeassistant/components/elkm1/translations/pl.json +++ b/homeassistant/components/elkm1/translations/pl.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "address_already_configured": "ElkM1 z tym adresem jest ju\u017c skonfigurowany", + "address_already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane z tym adresem", "already_configured": "ElkM1 z tym prefiksem jest ju\u017c skonfigurowany" }, "error": { diff --git a/homeassistant/components/emulated_roku/translations/bg.json b/homeassistant/components/emulated_roku/translations/bg.json index 6c1725a16b1..a1a0fd75c60 100644 --- a/homeassistant/components/emulated_roku/translations/bg.json +++ b/homeassistant/components/emulated_roku/translations/bg.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "\u0418\u043c\u0435\u0442\u043e \u0432\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/ca.json b/homeassistant/components/emulated_roku/translations/ca.json index efc1d250448..559bad6dd3e 100644 --- a/homeassistant/components/emulated_roku/translations/ca.json +++ b/homeassistant/components/emulated_roku/translations/ca.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "El dispositiu ja est\u00e0 configurat", - "name_exists": "El nom ja existeix" + "already_configured": "El dispositiu ja est\u00e0 configurat" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/cs.json b/homeassistant/components/emulated_roku/translations/cs.json index 156c71040a0..c84810814ed 100644 --- a/homeassistant/components/emulated_roku/translations/cs.json +++ b/homeassistant/components/emulated_roku/translations/cs.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "name_exists": "Jm\u00e9no ji\u017e existuje" + "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/da.json b/homeassistant/components/emulated_roku/translations/da.json index fbaf0d676c1..a9592ac9301 100644 --- a/homeassistant/components/emulated_roku/translations/da.json +++ b/homeassistant/components/emulated_roku/translations/da.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "Navnet findes allerede" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/de.json b/homeassistant/components/emulated_roku/translations/de.json index 1277fef44f2..a0bfd9f83aa 100644 --- a/homeassistant/components/emulated_roku/translations/de.json +++ b/homeassistant/components/emulated_roku/translations/de.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Ger\u00e4t ist bereits konfiguriert", - "name_exists": "Name existiert bereits" + "already_configured": "Ger\u00e4t ist bereits konfiguriert" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/en.json b/homeassistant/components/emulated_roku/translations/en.json index a8ee5f38e77..d646873f5e1 100644 --- a/homeassistant/components/emulated_roku/translations/en.json +++ b/homeassistant/components/emulated_roku/translations/en.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Device is already configured", - "name_exists": "Name already exists" + "already_configured": "Device is already configured" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/es-419.json b/homeassistant/components/emulated_roku/translations/es-419.json index 9aa7ff0bc92..0d4b4bc9a0f 100644 --- a/homeassistant/components/emulated_roku/translations/es-419.json +++ b/homeassistant/components/emulated_roku/translations/es-419.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "El nombre ya existe" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/es.json b/homeassistant/components/emulated_roku/translations/es.json index 1e3ef31e6ae..572a45c44cb 100644 --- a/homeassistant/components/emulated_roku/translations/es.json +++ b/homeassistant/components/emulated_roku/translations/es.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "name_exists": "El nombre ya existe" + "already_configured": "El dispositivo ya est\u00e1 configurado" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/et.json b/homeassistant/components/emulated_roku/translations/et.json index bfbecff709f..239081ff7a2 100644 --- a/homeassistant/components/emulated_roku/translations/et.json +++ b/homeassistant/components/emulated_roku/translations/et.json @@ -1,16 +1,19 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "name_exists": "Nimi on juba kasutusel" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud" }, "step": { "user": { "data": { + "advertise_ip": "Avalda IP aadress", + "advertise_port": "Avalda port", "host_ip": "", + "listen_port": "Kuula porti", "name": "Nimi", "upnp_bind_multicast": "Seo multicast (jah/ei)" - } + }, + "title": "M\u00e4\u00e4ra serveri seaded" } } }, diff --git a/homeassistant/components/emulated_roku/translations/fi.json b/homeassistant/components/emulated_roku/translations/fi.json index c3ad7765899..0f4691fe300 100644 --- a/homeassistant/components/emulated_roku/translations/fi.json +++ b/homeassistant/components/emulated_roku/translations/fi.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "Nimi on jo olemassa" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/fr.json b/homeassistant/components/emulated_roku/translations/fr.json index 56abe3465d9..cc613785ead 100644 --- a/homeassistant/components/emulated_roku/translations/fr.json +++ b/homeassistant/components/emulated_roku/translations/fr.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "name_exists": "Ce nom est d\u00e9j\u00e0 utilis\u00e9" + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/hu.json b/homeassistant/components/emulated_roku/translations/hu.json index ce182a3f00d..3d490ddbfeb 100644 --- a/homeassistant/components/emulated_roku/translations/hu.json +++ b/homeassistant/components/emulated_roku/translations/hu.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "A n\u00e9v m\u00e1r l\u00e9tezik" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/it.json b/homeassistant/components/emulated_roku/translations/it.json index b0bb5366ea2..6d734e7b1ba 100644 --- a/homeassistant/components/emulated_roku/translations/it.json +++ b/homeassistant/components/emulated_roku/translations/it.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "name_exists": "Il nome \u00e8 gi\u00e0 esistente" + "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/ko.json b/homeassistant/components/emulated_roku/translations/ko.json index d2f8d425a39..e9d1d134af2 100644 --- a/homeassistant/components/emulated_roku/translations/ko.json +++ b/homeassistant/components/emulated_roku/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "\uc774\ub984\uc774 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/lb.json b/homeassistant/components/emulated_roku/translations/lb.json index 94ff88f9715..9d4a4ad7505 100644 --- a/homeassistant/components/emulated_roku/translations/lb.json +++ b/homeassistant/components/emulated_roku/translations/lb.json @@ -1,12 +1,12 @@ { "config": { "abort": { - "name_exists": "Numm g\u00ebtt et schonn" + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "step": { "user": { "data": { - "advertise_ip": "IP annonc\u00e9ieren", + "advertise_ip": "IP Adresse annonc\u00e9ieren", "advertise_port": "Port annonc\u00e9ieren", "host_ip": "IP vum Apparat", "listen_port": "Port lauschteren", diff --git a/homeassistant/components/emulated_roku/translations/nl.json b/homeassistant/components/emulated_roku/translations/nl.json index 16c6ad1e512..54d544faee8 100644 --- a/homeassistant/components/emulated_roku/translations/nl.json +++ b/homeassistant/components/emulated_roku/translations/nl.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "name_exists": "Naam bestaat al" + "already_configured": "Apparaat is al geconfigureerd" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/no.json b/homeassistant/components/emulated_roku/translations/no.json index f63f7432721..8967731d0e5 100644 --- a/homeassistant/components/emulated_roku/translations/no.json +++ b/homeassistant/components/emulated_roku/translations/no.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Enheten er allerede konfigurert", - "name_exists": "Navnet eksisterer allerede" + "already_configured": "Enheten er allerede konfigurert" }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/pl.json b/homeassistant/components/emulated_roku/translations/pl.json index 7b66687e79e..bd09cc528c8 100644 --- a/homeassistant/components/emulated_roku/translations/pl.json +++ b/homeassistant/components/emulated_roku/translations/pl.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "name_exists": "Nazwa ju\u017c istnieje" + "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" }, "step": { "user": { @@ -14,7 +13,7 @@ "name": "Nazwa", "upnp_bind_multicast": "Powi\u0105\u017c multicast (prawda/fa\u0142sz)" }, - "title": "Zdefiniuj konfiguracj\u0119 serwera" + "title": "Definiowanie konfiguracji serwera" } } }, diff --git a/homeassistant/components/emulated_roku/translations/pt-BR.json b/homeassistant/components/emulated_roku/translations/pt-BR.json index b4111a184e9..b04554fd41e 100644 --- a/homeassistant/components/emulated_roku/translations/pt-BR.json +++ b/homeassistant/components/emulated_roku/translations/pt-BR.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "O nome j\u00e1 existe" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/pt.json b/homeassistant/components/emulated_roku/translations/pt.json index 8cfcefde448..8c9b894c4b7 100644 --- a/homeassistant/components/emulated_roku/translations/pt.json +++ b/homeassistant/components/emulated_roku/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "Nome j\u00e1 existe" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/ru.json b/homeassistant/components/emulated_roku/translations/ru.json index e2db2f51f46..2d4c4a7d935 100644 --- a/homeassistant/components/emulated_roku/translations/ru.json +++ b/homeassistant/components/emulated_roku/translations/ru.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "name_exists": "\u042d\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f." + "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." }, "step": { "user": { diff --git a/homeassistant/components/emulated_roku/translations/sl.json b/homeassistant/components/emulated_roku/translations/sl.json index 467d1139ea3..8b18837420d 100644 --- a/homeassistant/components/emulated_roku/translations/sl.json +++ b/homeassistant/components/emulated_roku/translations/sl.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "Ime \u017ee obstaja" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/sv.json b/homeassistant/components/emulated_roku/translations/sv.json index ec12f514293..ddf62b50df1 100644 --- a/homeassistant/components/emulated_roku/translations/sv.json +++ b/homeassistant/components/emulated_roku/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "Namnet finns redan" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/zh-Hans.json b/homeassistant/components/emulated_roku/translations/zh-Hans.json index cf413a3ef1f..ce8c75f0fb8 100644 --- a/homeassistant/components/emulated_roku/translations/zh-Hans.json +++ b/homeassistant/components/emulated_roku/translations/zh-Hans.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "name_exists": "\u540d\u79f0\u5df2\u5b58\u5728" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/emulated_roku/translations/zh-Hant.json b/homeassistant/components/emulated_roku/translations/zh-Hant.json index dc95575e04c..8c4ac5a0d73 100644 --- a/homeassistant/components/emulated_roku/translations/zh-Hant.json +++ b/homeassistant/components/emulated_roku/translations/zh-Hant.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "name_exists": "\u8a72\u540d\u7a31\u5df2\u5b58\u5728" + "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "step": { "user": { diff --git a/homeassistant/components/enigma2/media_player.py b/homeassistant/components/enigma2/media_player.py index b0d46d76b7b..8bb0486cd24 100644 --- a/homeassistant/components/enigma2/media_player.py +++ b/homeassistant/components/enigma2/media_player.py @@ -133,6 +133,11 @@ class Enigma2Device(MediaPlayerEntity): return STATE_PLAYING return STATE_OFF if self.e2_box.in_standby else STATE_ON + @property + def available(self): + """Return True if the device is available.""" + return not self.e2_box.is_offline + @property def supported_features(self): """Flag of media commands that are supported.""" diff --git a/homeassistant/components/enocean/strings.json b/homeassistant/components/enocean/strings.json index 633c97e51af..2b7aa3b37a5 100644 --- a/homeassistant/components/enocean/strings.json +++ b/homeassistant/components/enocean/strings.json @@ -1,7 +1,5 @@ { - "title": "EnOcean", "config": { - "flow_title": "ENOcean setup", "step": { "detect": { "title": "Select the path to you ENOcean dongle", diff --git a/homeassistant/components/enocean/translations/ca.json b/homeassistant/components/enocean/translations/ca.json index 5875089de70..cfae28cc630 100644 --- a/homeassistant/components/enocean/translations/ca.json +++ b/homeassistant/components/enocean/translations/ca.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "No s'ha trobat cap dongle v\u00e0lid en aquesta ruta" }, - "flow_title": "Configuraci\u00f3 d'ENOcean", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "Introdueix la ruta del dongle ENOcean" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/cs.json b/homeassistant/components/enocean/translations/cs.json index 2972ccbae64..19f5d1e1587 100644 --- a/homeassistant/components/enocean/translations/cs.json +++ b/homeassistant/components/enocean/translations/cs.json @@ -3,6 +3,5 @@ "abort": { "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/de.json b/homeassistant/components/enocean/translations/de.json index eb98e1fb2b9..ea9858f470e 100644 --- a/homeassistant/components/enocean/translations/de.json +++ b/homeassistant/components/enocean/translations/de.json @@ -2,8 +2,6 @@ "config": { "abort": { "single_instance_allowed": "Schon konfiguriert. Nur eine einzige Konfiguration m\u00f6glich." - }, - "flow_title": "ENOcean-Einrichtung" - }, - "title": "EnOcean" + } + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/en.json b/homeassistant/components/enocean/translations/en.json index 36d76a614e8..dd2d3fa57a4 100644 --- a/homeassistant/components/enocean/translations/en.json +++ b/homeassistant/components/enocean/translations/en.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "No valid dongle found for this path" }, - "flow_title": "ENOcean setup", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "Enter the path to you ENOcean dongle" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/es.json b/homeassistant/components/enocean/translations/es.json index b0f01af2a3b..2bcc1074a23 100644 --- a/homeassistant/components/enocean/translations/es.json +++ b/homeassistant/components/enocean/translations/es.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "No se ha encontrado ninguna mochila v\u00e1lida en esta ruta" }, - "flow_title": "Configuraci\u00f3n de ENOcean", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "Introduce la ruta a tu mochila ENOcean" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/et.json b/homeassistant/components/enocean/translations/et.json index 19ff43ed084..df3d53f949f 100644 --- a/homeassistant/components/enocean/translations/et.json +++ b/homeassistant/components/enocean/translations/et.json @@ -1,20 +1,25 @@ { "config": { "abort": { + "invalid_dongle_path": "Vigane USB-seadme rada", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, + "error": { + "invalid_dongle_path": "Selle raja jaoks ei leitud kehtivat seadet" + }, "step": { "detect": { "data": { "path": "USB-seadme asukoha rada" - } + }, + "title": "Vali ENOcean seadme rada" }, "manual": { "data": { "path": "USB-seadme asukoha rada" - } + }, + "title": "Sisesta ENOcean seadme rada" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/fr.json b/homeassistant/components/enocean/translations/fr.json index fe1956dbfc3..d2eda66257e 100644 --- a/homeassistant/components/enocean/translations/fr.json +++ b/homeassistant/components/enocean/translations/fr.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "Aucune cl\u00e9 valide trouv\u00e9e pour ce lien" }, - "flow_title": "Configuration d'ENOcean", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "Entrez le lien vers votre cl\u00e9 ENOcean" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/it.json b/homeassistant/components/enocean/translations/it.json index 857269a6ae1..09ed78b4b91 100644 --- a/homeassistant/components/enocean/translations/it.json +++ b/homeassistant/components/enocean/translations/it.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "Nessun dongle valido trovato per questo percorso" }, - "flow_title": "Configurazione di ENOcean", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "Inserisci il percorso per il tuo dongle ENOcean" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/ko.json b/homeassistant/components/enocean/translations/ko.json index 4bff9d71bf8..ba109ed58c0 100644 --- a/homeassistant/components/enocean/translations/ko.json +++ b/homeassistant/components/enocean/translations/ko.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "\uc774 \uacbd\ub85c\uc5d0 \uc720\ud6a8\ud55c \ub3d9\uae00\uc774 \uc5c6\uc2b5\ub2c8\ub2e4" }, - "flow_title": "ENOcean \uc124\uc815\ud558\uae30", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "ENOcean \ub3d9\uae00 \uacbd\ub85c \uc785\ub825\ud558\uae30" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/lb.json b/homeassistant/components/enocean/translations/lb.json index 58d131203b4..97f3bb0e27f 100644 --- a/homeassistant/components/enocean/translations/lb.json +++ b/homeassistant/components/enocean/translations/lb.json @@ -1,12 +1,12 @@ { "config": { "abort": { - "invalid_dongle_path": "Ong\u00eblte Dongle Pad" + "invalid_dongle_path": "Ong\u00eblte Dongle Pad", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { "invalid_dongle_path": "Kee g\u00ebltege Dongle an d\u00ebsem Pad fonnt" }, - "flow_title": "ENOcean Konfiguratioun", "step": { "detect": { "data": { @@ -21,6 +21,5 @@ "title": "G\u00ebff de Pad zu dengem ENOcean Dongle an" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/no.json b/homeassistant/components/enocean/translations/no.json index a3fc35edcc8..775443d8f5f 100644 --- a/homeassistant/components/enocean/translations/no.json +++ b/homeassistant/components/enocean/translations/no.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "Ingen gyldig dongle funnet for denne banen" }, - "flow_title": "ENOcean oppsett", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "Angi banen til din ENOcean dongle" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/pl.json b/homeassistant/components/enocean/translations/pl.json index 5f770418fef..78de599b0bb 100644 --- a/homeassistant/components/enocean/translations/pl.json +++ b/homeassistant/components/enocean/translations/pl.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "Nie znaleziono urz\u0105dzenia pod wskazan\u0105 \u015bcie\u017ck\u0105" }, - "flow_title": "Konfiguracja ENOcean", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "Podaj \u015bcie\u017ck\u0119 urz\u0105dzenia ENOcean" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/pt.json b/homeassistant/components/enocean/translations/pt.json index 4bca8a1319e..25538aa0036 100644 --- a/homeassistant/components/enocean/translations/pt.json +++ b/homeassistant/components/enocean/translations/pt.json @@ -2,8 +2,6 @@ "config": { "abort": { "single_instance_allowed": "J\u00e1 configurado. Apenas uma \u00fanica configura\u00e7\u00e3o \u00e9 poss\u00edvel." - }, - "flow_title": "Configura\u00e7\u00e3o ENOcean" - }, - "title": "EnOcean" + } + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/ru.json b/homeassistant/components/enocean/translations/ru.json index 1477c1d9b06..469c9a57ede 100644 --- a/homeassistant/components/enocean/translations/ru.json +++ b/homeassistant/components/enocean/translations/ru.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "\u041d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u043f\u0443\u0442\u0438." }, - "flow_title": "ENOcean", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "ENOcean" } } - }, - "title": "ENOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/sl.json b/homeassistant/components/enocean/translations/sl.json index da0df2714c9..9015d2f1e14 100644 --- a/homeassistant/components/enocean/translations/sl.json +++ b/homeassistant/components/enocean/translations/sl.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "Za to pot ni bilo mogo\u010de najti veljavnega klju\u010da" }, - "flow_title": "ENOcean nastavitev", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "Vnesite pot do va\u0161ega ENOcean klju\u010dka" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enocean/translations/zh-Hant.json b/homeassistant/components/enocean/translations/zh-Hant.json index 5b71e627f5f..bc51c7f0bbc 100644 --- a/homeassistant/components/enocean/translations/zh-Hant.json +++ b/homeassistant/components/enocean/translations/zh-Hant.json @@ -7,7 +7,6 @@ "error": { "invalid_dongle_path": "\u6b64\u8def\u5f91\u7121\u6709\u6548\u8a2d\u5099" }, - "flow_title": "ENOcean \u8a2d\u5b9a", "step": { "detect": { "data": { @@ -22,6 +21,5 @@ "title": "\u8f38\u5165 ENOcean \u8a2d\u5099\u8def\u5f91" } } - }, - "title": "EnOcean" + } } \ No newline at end of file diff --git a/homeassistant/components/enphase_envoy/manifest.json b/homeassistant/components/enphase_envoy/manifest.json index 0b4fbaf88ee..183a53284a0 100644 --- a/homeassistant/components/enphase_envoy/manifest.json +++ b/homeassistant/components/enphase_envoy/manifest.json @@ -2,6 +2,6 @@ "domain": "enphase_envoy", "name": "Enphase Envoy", "documentation": "https://www.home-assistant.io/integrations/enphase_envoy", - "requirements": ["envoy_reader==0.16.1"], + "requirements": ["envoy_reader==0.16.2"], "codeowners": [] } diff --git a/homeassistant/components/environment_canada/camera.py b/homeassistant/components/environment_canada/camera.py index 87677e85065..66079ac73ff 100644 --- a/homeassistant/components/environment_canada/camera.py +++ b/homeassistant/components/environment_canada/camera.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( vol.Optional(CONF_STATION): cv.matches_regex(r"^C[A-Z]{4}$|^[A-Z]{3}$"), vol.Inclusive(CONF_LATITUDE, "latlon"): cv.latitude, vol.Inclusive(CONF_LONGITUDE, "latlon"): cv.longitude, - vol.Optional(CONF_PRECIP_TYPE): ["RAIN", "SNOW"], + vol.Optional(CONF_PRECIP_TYPE): vol.In(["RAIN", "SNOW"]), } ) diff --git a/homeassistant/components/environment_canada/manifest.json b/homeassistant/components/environment_canada/manifest.json index f89a7eb3e55..2a51c6ffd83 100644 --- a/homeassistant/components/environment_canada/manifest.json +++ b/homeassistant/components/environment_canada/manifest.json @@ -2,6 +2,6 @@ "domain": "environment_canada", "name": "Environment Canada", "documentation": "https://www.home-assistant.io/integrations/environment_canada", - "requirements": ["env_canada==0.2.0"], + "requirements": ["env_canada==0.2.4"], "codeowners": ["@michaeldavie"] } diff --git a/homeassistant/components/environment_canada/sensor.py b/homeassistant/components/environment_canada/sensor.py index afd75956a9f..a8772909f68 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/epson/__init__.py b/homeassistant/components/epson/__init__.py index eed342f77f9..c7278ed2cc9 100644 --- a/homeassistant/components/epson/__init__.py +++ b/homeassistant/components/epson/__init__.py @@ -1 +1,70 @@ -"""The epson component.""" +"""The epson integration.""" +import asyncio +import logging + +from epson_projector import Projector +from epson_projector.const import POWER, STATE_UNAVAILABLE as EPSON_STATE_UNAVAILABLE + +from homeassistant.components.media_player import DOMAIN as MEDIA_PLAYER_PLATFORM +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_HOST, CONF_PORT +from homeassistant.core import HomeAssistant +from homeassistant.helpers.aiohttp_client import async_get_clientsession + +from .const import DOMAIN +from .exceptions import CannotConnect + +PLATFORMS = [MEDIA_PLAYER_PLATFORM] + +_LOGGER = logging.getLogger(__name__) + + +async def validate_projector(hass: HomeAssistant, host, port): + """Validate the given host and port allows us to connect.""" + epson_proj = Projector( + host=host, + websession=async_get_clientsession(hass, verify_ssl=False), + port=port, + ) + _power = await epson_proj.get_property(POWER) + if not _power or _power == EPSON_STATE_UNAVAILABLE: + raise CannotConnect + return epson_proj + + +async def async_setup(hass: HomeAssistant, config: dict): + """Set up the epson component.""" + hass.data.setdefault(DOMAIN, {}) + return True + + +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): + """Set up epson from a config entry.""" + try: + projector = await validate_projector( + hass, entry.data[CONF_HOST], entry.data[CONF_PORT] + ) + except CannotConnect: + _LOGGER.warning("Cannot connect to projector %s", entry.data[CONF_HOST]) + return False + hass.data[DOMAIN][entry.entry_id] = projector + for component in PLATFORMS: + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(entry, component) + ) + return True + + +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): + """Unload a config entry.""" + unload_ok = all( + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(entry, component) + for component in PLATFORMS + ] + ) + ) + if unload_ok: + hass.data[DOMAIN].pop(entry.entry_id) + return unload_ok diff --git a/homeassistant/components/epson/config_flow.py b/homeassistant/components/epson/config_flow.py new file mode 100644 index 00000000000..6f6d7b2247f --- /dev/null +++ b/homeassistant/components/epson/config_flow.py @@ -0,0 +1,46 @@ +"""Config flow for epson integration.""" +import voluptuous as vol + +from homeassistant import config_entries +from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT + +from . import validate_projector +from .const import DOMAIN +from .exceptions import CannotConnect + +DATA_SCHEMA = vol.Schema( + { + vol.Required(CONF_HOST): str, + vol.Required(CONF_NAME, default=DOMAIN): str, + vol.Required(CONF_PORT, default=80): int, + } +) + + +class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): + """Handle a config flow for epson.""" + + VERSION = 1 + CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL + + 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 initial step.""" + errors = {} + if user_input is not None: + try: + await validate_projector( + self.hass, user_input[CONF_HOST], user_input[CONF_PORT] + ) + except CannotConnect: + errors["base"] = "cannot_connect" + else: + return self.async_create_entry( + title=user_input.pop(CONF_NAME), data=user_input + ) + return self.async_show_form( + step_id="user", data_schema=DATA_SCHEMA, errors=errors + ) diff --git a/homeassistant/components/epson/const.py b/homeassistant/components/epson/const.py index 23f3b081d01..cb227047f45 100644 --- a/homeassistant/components/epson/const.py +++ b/homeassistant/components/epson/const.py @@ -1,10 +1,8 @@ -"""Constants for the Epson projector component.""" +"""Constants for the epson integration.""" + DOMAIN = "epson" SERVICE_SELECT_CMODE = "select_cmode" ATTR_CMODE = "cmode" -DATA_EPSON = "epson" DEFAULT_NAME = "EPSON Projector" - -SUPPORT_CMODE = 33001 diff --git a/homeassistant/components/epson/exceptions.py b/homeassistant/components/epson/exceptions.py new file mode 100644 index 00000000000..d781a74f7c1 --- /dev/null +++ b/homeassistant/components/epson/exceptions.py @@ -0,0 +1,6 @@ +"""The errors of Epson integration.""" +from homeassistant import exceptions + + +class CannotConnect(exceptions.HomeAssistantError): + """Error to indicate we cannot connect.""" diff --git a/homeassistant/components/epson/manifest.json b/homeassistant/components/epson/manifest.json index 909efd5893e..809bcf1d651 100644 --- a/homeassistant/components/epson/manifest.json +++ b/homeassistant/components/epson/manifest.json @@ -1,7 +1,8 @@ { "domain": "epson", "name": "Epson", + "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/epson", - "requirements": ["epson-projector==0.1.3"], - "codeowners": [] -} + "requirements": ["epson-projector==0.2.3"], + "codeowners": ["@pszafer"] +} \ No newline at end of file diff --git a/homeassistant/components/epson/media_player.py b/homeassistant/components/epson/media_player.py index 235caa8d1a3..24ed62067f9 100644 --- a/homeassistant/components/epson/media_player.py +++ b/homeassistant/components/epson/media_player.py @@ -1,7 +1,6 @@ """Support for Epson projector.""" import logging -import epson_projector as epson from epson_projector.const import ( BACK, BUSY, @@ -18,6 +17,7 @@ from epson_projector.const import ( POWER, SOURCE, SOURCE_LIST, + STATE_UNAVAILABLE as EPSON_STATE_UNAVAILABLE, TURN_OFF, TURN_ON, VOL_DOWN, @@ -36,26 +36,12 @@ from homeassistant.components.media_player.const import ( SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_STEP, ) -from homeassistant.const import ( - ATTR_ENTITY_ID, - CONF_HOST, - CONF_NAME, - CONF_PORT, - CONF_SSL, - STATE_OFF, - STATE_ON, -) -from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.config_entries import SOURCE_IMPORT +from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, STATE_OFF, STATE_ON +from homeassistant.helpers import entity_platform import homeassistant.helpers.config_validation as cv -from .const import ( - ATTR_CMODE, - DATA_EPSON, - DEFAULT_NAME, - DOMAIN, - SERVICE_SELECT_CMODE, - SUPPORT_CMODE, -) +from .const import ATTR_CMODE, DEFAULT_NAME, DOMAIN, SERVICE_SELECT_CMODE _LOGGER = logging.getLogger(__name__) @@ -63,86 +49,72 @@ SUPPORT_EPSON = ( SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_SELECT_SOURCE - | SUPPORT_CMODE | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_STEP | SUPPORT_NEXT_TRACK | SUPPORT_PREVIOUS_TRACK ) -MEDIA_PLAYER_SCHEMA = vol.Schema({ATTR_ENTITY_ID: cv.comp_entity_ids}) - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PORT, default=80): cv.port, - vol.Optional(CONF_SSL, default=False): cv.boolean, } ) +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up the Epson projector from a config entry.""" + unique_id = config_entry.entry_id + projector = hass.data[DOMAIN][unique_id] + projector_entity = EpsonProjectorMediaPlayer( + projector, config_entry.title, unique_id + ) + async_add_entities([projector_entity], True) + platform = entity_platform.current_platform.get() + platform.async_register_entity_service( + SERVICE_SELECT_CMODE, + {vol.Required(ATTR_CMODE): vol.All(cv.string, vol.Any(*CMODE_LIST_SET))}, + SERVICE_SELECT_CMODE, + ) + + async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): - """Set up the Epson media player platform.""" - if DATA_EPSON not in hass.data: - hass.data[DATA_EPSON] = [] - - name = config.get(CONF_NAME) - host = config.get(CONF_HOST) - port = config.get(CONF_PORT) - ssl = config[CONF_SSL] - - epson_proj = EpsonProjector( - async_get_clientsession(hass, verify_ssl=False), name, host, port, ssl - ) - - hass.data[DATA_EPSON].append(epson_proj) - async_add_entities([epson_proj], update_before_add=True) - - async def async_service_handler(service): - """Handle for services.""" - entity_ids = service.data.get(ATTR_ENTITY_ID) - if entity_ids: - devices = [ - device - for device in hass.data[DATA_EPSON] - if device.entity_id in entity_ids - ] - else: - devices = hass.data[DATA_EPSON] - for device in devices: - if service.service == SERVICE_SELECT_CMODE: - cmode = service.data.get(ATTR_CMODE) - await device.select_cmode(cmode) - device.async_schedule_update_ha_state(True) - - epson_schema = MEDIA_PLAYER_SCHEMA.extend( - {vol.Required(ATTR_CMODE): vol.All(cv.string, vol.Any(*CMODE_LIST_SET))} - ) - hass.services.async_register( - DOMAIN, SERVICE_SELECT_CMODE, async_service_handler, schema=epson_schema + """Set up the Epson projector.""" + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=config + ) ) -class EpsonProjector(MediaPlayerEntity): +class EpsonProjectorMediaPlayer(MediaPlayerEntity): """Representation of Epson Projector Device.""" - def __init__(self, websession, name, host, port, encryption): + def __init__(self, projector, name, unique_id): """Initialize entity to control Epson projector.""" self._name = name - self._projector = epson.Projector(host, websession=websession, port=port) + self._projector = projector + self._available = False self._cmode = None self._source_list = list(DEFAULT_SOURCES.values()) self._source = None self._volume = None self._state = None + self._unique_id = unique_id async def async_update(self): """Update state of device.""" - is_turned_on = await self._projector.get_property(POWER) - _LOGGER.debug("Project turn on/off status: %s", is_turned_on) - if is_turned_on and is_turned_on == EPSON_CODES[POWER]: + power_state = await self._projector.get_property(POWER) + _LOGGER.debug("Projector status: %s", power_state) + if not power_state or power_state == EPSON_STATE_UNAVAILABLE: + self._available = False + return + self._available = True + if power_state == EPSON_CODES[POWER]: self._state = STATE_ON + self._source_list = list(DEFAULT_SOURCES.values()) cmode = await self._projector.get_property(CMODE) self._cmode = CMODE_LIST.get(cmode, self._cmode) source = await self._projector.get_property(SOURCE) @@ -150,7 +122,7 @@ class EpsonProjector(MediaPlayerEntity): volume = await self._projector.get_property(VOLUME) if volume: self._volume = volume - elif is_turned_on == BUSY: + elif power_state == BUSY: self._state = STATE_ON else: self._state = STATE_OFF @@ -160,11 +132,21 @@ class EpsonProjector(MediaPlayerEntity): """Return the name of the device.""" return self._name + @property + def unique_id(self): + """Return unique ID.""" + return self._unique_id + @property def state(self): """Return the state of the device.""" return self._state + @property + def available(self): + """Return if projector is available.""" + return self._available + @property def supported_features(self): """Flag media player features that are supported.""" diff --git a/homeassistant/components/epson/strings.json b/homeassistant/components/epson/strings.json new file mode 100644 index 00000000000..263d7984aae --- /dev/null +++ b/homeassistant/components/epson/strings.json @@ -0,0 +1,16 @@ +{ + "config": { + "step": { + "user": { + "data": { + "host": "[%key:common::config_flow::data::host%]", + "name": "[%key:common::config_flow::data::name%]", + "port": "[%key:common::config_flow::data::port%]" + } + } + }, + "error": { + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" + } + } +} diff --git a/homeassistant/components/epson/translations/ca.json b/homeassistant/components/epson/translations/ca.json new file mode 100644 index 00000000000..46e6311ef05 --- /dev/null +++ b/homeassistant/components/epson/translations/ca.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "Ha fallat la connexi\u00f3" + }, + "step": { + "user": { + "data": { + "host": "Amfitri\u00f3", + "name": "Nom", + "port": "Port" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/cs.json b/homeassistant/components/epson/translations/cs.json new file mode 100644 index 00000000000..31b0e41118c --- /dev/null +++ b/homeassistant/components/epson/translations/cs.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" + }, + "step": { + "user": { + "data": { + "host": "Hostitel", + "name": "Jm\u00e9no", + "port": "Port" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/en.json b/homeassistant/components/epson/translations/en.json new file mode 100644 index 00000000000..bb914282c44 --- /dev/null +++ b/homeassistant/components/epson/translations/en.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "Failed to connect" + }, + "step": { + "user": { + "data": { + "host": "Host", + "name": "Name", + "port": "Port" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/es.json b/homeassistant/components/epson/translations/es.json new file mode 100644 index 00000000000..e1d40ef981b --- /dev/null +++ b/homeassistant/components/epson/translations/es.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "No se pudo conectar" + }, + "step": { + "user": { + "data": { + "host": "Host", + "name": "Nombre", + "port": "Puerto" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/et.json b/homeassistant/components/epson/translations/et.json new file mode 100644 index 00000000000..1fb510c37a4 --- /dev/null +++ b/homeassistant/components/epson/translations/et.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "\u00dchendamine nurjus" + }, + "step": { + "user": { + "data": { + "host": "Host", + "name": "Nimi", + "port": "Port" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/fr.json b/homeassistant/components/epson/translations/fr.json new file mode 100644 index 00000000000..cfc37079379 --- /dev/null +++ b/homeassistant/components/epson/translations/fr.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "Echec de la connection" + }, + "step": { + "user": { + "data": { + "host": "H\u00f4te", + "name": "Nom", + "port": "Port" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/it.json b/homeassistant/components/epson/translations/it.json new file mode 100644 index 00000000000..233a004fe0c --- /dev/null +++ b/homeassistant/components/epson/translations/it.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "Impossibile connettersi" + }, + "step": { + "user": { + "data": { + "host": "Host", + "name": "Nome", + "port": "Porta" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/no.json b/homeassistant/components/epson/translations/no.json new file mode 100644 index 00000000000..0b164f050f4 --- /dev/null +++ b/homeassistant/components/epson/translations/no.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "Tilkobling mislyktes" + }, + "step": { + "user": { + "data": { + "host": "Vert", + "name": "Navn", + "port": "Port" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/pl.json b/homeassistant/components/epson/translations/pl.json new file mode 100644 index 00000000000..7a3ea98a0e9 --- /dev/null +++ b/homeassistant/components/epson/translations/pl.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" + }, + "step": { + "user": { + "data": { + "host": "Nazwa hosta lub adres IP", + "name": "Nazwa", + "port": "Port" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/ru.json b/homeassistant/components/epson/translations/ru.json new file mode 100644 index 00000000000..d60b7c60c84 --- /dev/null +++ b/homeassistant/components/epson/translations/ru.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." + }, + "step": { + "user": { + "data": { + "host": "\u0425\u043e\u0441\u0442", + "name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435", + "port": "\u041f\u043e\u0440\u0442" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/epson/translations/zh-Hant.json b/homeassistant/components/epson/translations/zh-Hant.json new file mode 100644 index 00000000000..9ff2143ed9d --- /dev/null +++ b/homeassistant/components/epson/translations/zh-Hant.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "cannot_connect": "\u9023\u7dda\u5931\u6557" + }, + "step": { + "user": { + "data": { + "host": "\u4e3b\u6a5f\u7aef", + "name": "\u540d\u7a31", + "port": "\u901a\u8a0a\u57e0" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/eq3btsmart/climate.py b/homeassistant/components/eq3btsmart/climate.py index 6eb0276c314..737b3fe357a 100644 --- a/homeassistant/components/eq3btsmart/climate.py +++ b/homeassistant/components/eq3btsmart/climate.py @@ -136,7 +136,7 @@ class EQ3BTSmartThermostat(ClimateEntity): @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 @@ class EQ3BTSmartThermostat(ClimateEntity): 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/esphome/entry_data.py b/homeassistant/components/esphome/entry_data.py index 8f273b682ff..54da1ed5562 100644 --- a/homeassistant/components/esphome/entry_data.py +++ b/homeassistant/components/esphome/entry_data.py @@ -31,6 +31,8 @@ if TYPE_CHECKING: 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 @@ class RuntimeEntryData: 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): diff --git a/homeassistant/components/esphome/translations/bg.json b/homeassistant/components/esphome/translations/bg.json index 2b96f4264e8..1a92f62cbb6 100644 --- a/homeassistant/components/esphome/translations/bg.json +++ b/homeassistant/components/esphome/translations/bg.json @@ -5,7 +5,6 @@ }, "error": { "connection_error": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 ESP. \u041c\u043e\u043b\u044f, \u0443\u0432\u0435\u0440\u0435\u0442\u0435 \u0441\u0435, \u0447\u0435 \u0432\u0430\u0448\u0438\u044f\u0442 YAML \u0444\u0430\u0439\u043b \u0441\u044a\u0434\u044a\u0440\u0436\u0430 \u0440\u0435\u0434 \"api:\".", - "invalid_password": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0430 \u043f\u0430\u0440\u043e\u043b\u0430!", "resolve_error": "\u041d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043e\u0442\u043a\u0440\u0438\u0435 \u0430\u0434\u0440\u0435\u0441\u044a\u0442 \u043d\u0430 ESP. \u0410\u043a\u043e \u0442\u0430\u0437\u0438 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u043e\u0434\u044a\u043b\u0436\u0430\u0432\u0430, \u0437\u0430\u0434\u0430\u0439\u0442\u0435 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u043d IP \u0430\u0434\u0440\u0435\u0441: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/ca.json b/homeassistant/components/esphome/translations/ca.json index 79b705db0d8..25374cbbd00 100644 --- a/homeassistant/components/esphome/translations/ca.json +++ b/homeassistant/components/esphome/translations/ca.json @@ -7,7 +7,6 @@ "error": { "connection_error": "No s'ha pogut connectar amb ESP. Verifica que l'arxiu YAML cont\u00e9 la l\u00ednia 'api:'.", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_password": "Contrasenya inv\u00e0lida!", "resolve_error": "No s'ha pogut trobar l'adre\u00e7a de l'ESP. Si l'error persisteix, configura una adre\u00e7a IP est\u00e0tica: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/cs.json b/homeassistant/components/esphome/translations/cs.json index e34ca009aca..9a451a8537f 100644 --- a/homeassistant/components/esphome/translations/cs.json +++ b/homeassistant/components/esphome/translations/cs.json @@ -7,7 +7,6 @@ "error": { "connection_error": "Nelze se p\u0159ipojit k ESP. Zkontrolujte, zda va\u0161e YAML konfigurace obsahuje \u0159\u00e1dek 'api:'.", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_password": "Neplatn\u00e9 heslo", "resolve_error": "Nelze naj\u00edt IP adresu uzlu ESP. Pokud tato chyba p\u0159etrv\u00e1v\u00e1, nastavte statickou adresu IP: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", @@ -19,7 +18,7 @@ "description": "Zadejte heslo, kter\u00e9 jste nastavili ve va\u0161\u00ed konfiguraci pro {name} ." }, "discovery_confirm": { - "description": "Chcete do domovsk\u00e9ho asistenta p\u0159idat uzel ESPHome `{name}`?", + "description": "Chcete p\u0159idat uzel ESPHome `{name}` do Home Assistant?", "title": "Nalezen uzel ESPHome" }, "user": { diff --git a/homeassistant/components/esphome/translations/da.json b/homeassistant/components/esphome/translations/da.json index db4cdc72fca..7ff1ee797e2 100644 --- a/homeassistant/components/esphome/translations/da.json +++ b/homeassistant/components/esphome/translations/da.json @@ -5,7 +5,6 @@ }, "error": { "connection_error": "Kan ikke oprette forbindelse til ESP. S\u00f8rg for, at din YAML-fil indeholder en 'api:' linje.", - "invalid_password": "Ugyldig adgangskode!", "resolve_error": "Kan ikke finde adressen p\u00e5 ESP. Hvis denne fejl forts\u00e6tter skal du angive en statisk IP-adresse: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/de.json b/homeassistant/components/esphome/translations/de.json index 978ff5e52d9..826574cb7e0 100644 --- a/homeassistant/components/esphome/translations/de.json +++ b/homeassistant/components/esphome/translations/de.json @@ -6,7 +6,6 @@ }, "error": { "connection_error": "Keine Verbindung zum ESP m\u00f6glich. Achte darauf, dass deine YAML-Datei eine Zeile 'api:' enth\u00e4lt.", - "invalid_password": "Ung\u00fcltiges Passwort!", "resolve_error": "Adresse des ESP kann nicht aufgel\u00f6st werden. Wenn dieser Fehler weiterhin besteht, lege eine statische IP-Adresse fest: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/en.json b/homeassistant/components/esphome/translations/en.json index 71e81083b6c..d70c984b532 100644 --- a/homeassistant/components/esphome/translations/en.json +++ b/homeassistant/components/esphome/translations/en.json @@ -7,7 +7,6 @@ "error": { "connection_error": "Can't connect to ESP. Please make sure your YAML file contains an 'api:' line.", "invalid_auth": "Invalid authentication", - "invalid_password": "Invalid password!", "resolve_error": "Can't resolve address of the ESP. If this error persists, please set a static IP address: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/es-419.json b/homeassistant/components/esphome/translations/es-419.json index c5da73a7fbf..a92939b1f91 100644 --- a/homeassistant/components/esphome/translations/es-419.json +++ b/homeassistant/components/esphome/translations/es-419.json @@ -6,7 +6,6 @@ }, "error": { "connection_error": "No se puede conectar a ESP. Aseg\u00farese de que su archivo YAML contenga una l\u00ednea 'api:'.", - "invalid_password": "\u00a1Contrase\u00f1a invalida!", "resolve_error": "No se puede resolver la direcci\u00f3n de la ESP. Si este error persiste, configure una direcci\u00f3n IP est\u00e1tica: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/es.json b/homeassistant/components/esphome/translations/es.json index 5ab2ef3b01e..9c4b3f52406 100644 --- a/homeassistant/components/esphome/translations/es.json +++ b/homeassistant/components/esphome/translations/es.json @@ -7,7 +7,6 @@ "error": { "connection_error": "No se puede conectar a ESP. Aseg\u00farate de que tu archivo YAML contenga una l\u00ednea 'api:'.", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_password": "\u00a1Contrase\u00f1a incorrecta!", "resolve_error": "No se puede resolver la direcci\u00f3n de ESP. Si el error persiste, configura una direcci\u00f3n IP est\u00e1tica: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/et.json b/homeassistant/components/esphome/translations/et.json index 58f86d9ffe7..18f69b7207b 100644 --- a/homeassistant/components/esphome/translations/et.json +++ b/homeassistant/components/esphome/translations/et.json @@ -5,24 +5,28 @@ "already_in_progress": "Seadistamine on juba k\u00e4imas" }, "error": { + "connection_error": "ESP-ga ei saa \u00fchendust luua. Veendu, et YAML-fail sisaldab rida 'api:'.", "invalid_auth": "Tuvastamise viga", - "invalid_password": "Vale salas\u00f5na!" + "resolve_error": "ESP aadressi ei \u00f5nnestu lahendada. Kui see viga p\u00fcsib, m\u00e4\u00e4ra staatiline IP-aadress: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", "step": { "authenticate": { "data": { "password": "Salas\u00f5na" - } + }, + "description": "Sisesta {name} seadistamises m\u00e4\u00e4ratud parool." }, "discovery_confirm": { - "description": "Kas soovid lisada ESPHome'i s\u00f5lme '{name}' Home Assistant-ile?" + "description": "Kas soovid lisada ESPHome'i s\u00f5lme '{name}' Home Assistant-ile?", + "title": "Avastastud ESPHome'i s\u00f5lm" }, "user": { "data": { "host": "", "port": "Port" - } + }, + "description": "Sisesta oma [ESPHome](https://esphomelib.com/) s\u00f5lme \u00fchenduse s\u00e4tted." } } } diff --git a/homeassistant/components/esphome/translations/fi.json b/homeassistant/components/esphome/translations/fi.json index 8b9525132ec..4d3df17cdd2 100644 --- a/homeassistant/components/esphome/translations/fi.json +++ b/homeassistant/components/esphome/translations/fi.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "ESP on jo m\u00e4\u00e4ritetty" }, - "error": { - "invalid_password": "Virheellinen salasana!" - }, "flow_title": "ESPHome: {name}", "step": { "user": { diff --git a/homeassistant/components/esphome/translations/fr.json b/homeassistant/components/esphome/translations/fr.json index 1a63d8083d7..0b977815f6b 100644 --- a/homeassistant/components/esphome/translations/fr.json +++ b/homeassistant/components/esphome/translations/fr.json @@ -6,7 +6,7 @@ }, "error": { "connection_error": "Impossible de se connecter \u00e0 ESP. Assurez-vous que votre fichier YAML contient une ligne 'api:'.", - "invalid_password": "Mot de passe invalide !", + "invalid_auth": "Authentification 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" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/hu.json b/homeassistant/components/esphome/translations/hu.json index 19691a94891..46cb3228edb 100644 --- a/homeassistant/components/esphome/translations/hu.json +++ b/homeassistant/components/esphome/translations/hu.json @@ -5,7 +5,6 @@ }, "error": { "connection_error": "Nem lehet csatlakozni az ESP-hez. K\u00e9rlek gy\u0151z\u0151dj meg r\u00f3la, hogy a YAML f\u00e1jl tartalmaz egy \"api:\" sort.", - "invalid_password": "\u00c9rv\u00e9nytelen jelsz\u00f3!", "resolve_error": "Az ESP c\u00edme nem oldhat\u00f3 fel. Ha a hiba tov\u00e1bbra is fenn\u00e1ll, k\u00e9rlek, \u00e1ll\u00edts be egy statikus IP-c\u00edmet: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/it.json b/homeassistant/components/esphome/translations/it.json index 4095b3bd107..c21d8da7166 100644 --- a/homeassistant/components/esphome/translations/it.json +++ b/homeassistant/components/esphome/translations/it.json @@ -7,7 +7,6 @@ "error": { "connection_error": "Impossibile connettersi ad ESP. Assicurati che il tuo file YAML contenga una riga \"api:\".", "invalid_auth": "Autenticazione non valida", - "invalid_password": "Password non valida!", "resolve_error": "Impossibile risolvere l'indirizzo dell'ESP. Se questo errore persiste, impostare un indirizzo IP statico: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/ko.json b/homeassistant/components/esphome/translations/ko.json index b3278416350..82b9490757b 100644 --- a/homeassistant/components/esphome/translations/ko.json +++ b/homeassistant/components/esphome/translations/ko.json @@ -6,7 +6,6 @@ }, "error": { "connection_error": "ESP \uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. YAML \ud30c\uc77c\uc5d0 'api:' \ub97c \uad6c\uc131\ud588\ub294\uc9c0 \ud655\uc778\ud574\uc8fc\uc138\uc694.", - "invalid_password": "\uc798\ubabb\ub41c \ube44\ubc00\ubc88\ud638", "resolve_error": "ESP \uc758 \uc8fc\uc18c\ub97c \ud655\uc778\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. \uc774 \uc624\ub958\uac00 \uacc4\uc18d \ubc1c\uc0dd\ud558\uba74 \uace0\uc815 IP \uc8fc\uc18c\ub97c \uc124\uc815\ud574\uc8fc\uc138\uc694: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/lb.json b/homeassistant/components/esphome/translations/lb.json index f7969c6ab71..ef45041b2fb 100644 --- a/homeassistant/components/esphome/translations/lb.json +++ b/homeassistant/components/esphome/translations/lb.json @@ -1,12 +1,12 @@ { "config": { "abort": { - "already_configured": "ESP ass scho konfigur\u00e9iert", + "already_configured": "Apparat ass scho konfigur\u00e9iert", "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaang." }, "error": { "connection_error": "Keng Verbindung zum ESP. Iwwerpr\u00e9ift d'Pr\u00e4sens vun der Zeil api: am YAML Fichier.", - "invalid_password": "Ong\u00ebltegt Passwuert!", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", "resolve_error": "Kann d'Adresse vum ESP net opl\u00e9isen. Falls d\u00ebse Problem weiderhi besteet dann defin\u00e9iert eng statesch IP Adresse:\nhttps://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/nl.json b/homeassistant/components/esphome/translations/nl.json index 2ba68398603..f32dbd1723e 100644 --- a/homeassistant/components/esphome/translations/nl.json +++ b/homeassistant/components/esphome/translations/nl.json @@ -1,11 +1,12 @@ { "config": { "abort": { - "already_configured": "ESP is al geconfigureerd" + "already_configured": "ESP is al geconfigureerd", + "already_in_progress": "De configuratiestroom is al begonnen" }, "error": { "connection_error": "Kan geen verbinding maken met ESP. Zorg ervoor dat uw YAML-bestand een regel 'api:' bevat.", - "invalid_password": "Ongeldig wachtwoord!", + "invalid_auth": "Ongeldige authenticatie", "resolve_error": "Kan het adres van de ESP niet vinden. Als deze fout aanhoudt, stel dan een statisch IP-adres in: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/no.json b/homeassistant/components/esphome/translations/no.json index fd510fb0488..5d831d7aaa2 100644 --- a/homeassistant/components/esphome/translations/no.json +++ b/homeassistant/components/esphome/translations/no.json @@ -7,7 +7,6 @@ "error": { "connection_error": "Kan ikke koble til ESP. Kontroller at YAML filen din inneholder en \"api:\" linje.", "invalid_auth": "Ugyldig godkjenning", - "invalid_password": "Ugyldig passord!", "resolve_error": "Kan ikke l\u00f8se adressen til ESP. Hvis denne feilen vedvarer, vennligst [sett en statisk IP-adresse](https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips)" }, "flow_title": "", diff --git a/homeassistant/components/esphome/translations/pl.json b/homeassistant/components/esphome/translations/pl.json index 248de87e1da..1866b372eb4 100644 --- a/homeassistant/components/esphome/translations/pl.json +++ b/homeassistant/components/esphome/translations/pl.json @@ -5,9 +5,8 @@ "already_in_progress": "Konfiguracja jest ju\u017c w toku" }, "error": { - "connection_error": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z ESP. Upewnij si\u0119, \u017ce Tw\u00f3j plik YAML zawiera lini\u0119 'api:'.", + "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z ESP. Upewnij si\u0119, \u017ce Tw\u00f3j plik YAML zawiera lini\u0119 'api:'.", "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_password": "Nieprawid\u0142owe has\u0142o!", "resolve_error": "Nie mo\u017cna rozpozna\u0107 adresu ESP. Je\u015bli ten b\u0142\u0105d b\u0119dzie si\u0119 powtarza\u0142, nale\u017cy ustawi\u0107 statyczny adres IP: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/pt-BR.json b/homeassistant/components/esphome/translations/pt-BR.json index df7f51ccd51..cb050046d50 100644 --- a/homeassistant/components/esphome/translations/pt-BR.json +++ b/homeassistant/components/esphome/translations/pt-BR.json @@ -5,7 +5,6 @@ }, "error": { "connection_error": "N\u00e3o \u00e9 poss\u00edvel conectar-se ao ESP. Por favor, verifique se o seu arquivo YAML cont\u00e9m uma linha 'api:'.", - "invalid_password": "Senha inv\u00e1lida!", "resolve_error": "N\u00e3o \u00e9 poss\u00edvel resolver o endere\u00e7o do ESP. Se este erro persistir, por favor, defina um endere\u00e7o IP est\u00e1tico: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/pt.json b/homeassistant/components/esphome/translations/pt.json index 7522fa94f96..e010af99a0b 100644 --- a/homeassistant/components/esphome/translations/pt.json +++ b/homeassistant/components/esphome/translations/pt.json @@ -5,7 +5,6 @@ }, "error": { "connection_error": "N\u00e3o \u00e9 poss\u00edvel conectar-se ao ESP. Por favor, verifique se o seu arquivo YAML cont\u00e9m uma linha 'api:'.", - "invalid_password": "Palavra-passe inv\u00e1lida", "resolve_error": "N\u00e3o \u00e9 poss\u00edvel resolver o endere\u00e7o do ESP. Se este erro persistir, defina um endere\u00e7o IP est\u00e1tico: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "step": { diff --git a/homeassistant/components/esphome/translations/ru.json b/homeassistant/components/esphome/translations/ru.json index 70b64cc48ba..bcbe9148854 100644 --- a/homeassistant/components/esphome/translations/ru.json +++ b/homeassistant/components/esphome/translations/ru.json @@ -7,7 +7,6 @@ "error": { "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a ESP. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0412\u0430\u0448 YAML-\u0444\u0430\u0439\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0442\u0440\u043e\u043a\u0443 'api:'.", "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_password": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c!", "resolve_error": "\u041d\u0435 \u0443\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0430\u0434\u0440\u0435\u0441 ESP. \u0415\u0441\u043b\u0438 \u044d\u0442\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442\u0441\u044f, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 IP-\u0430\u0434\u0440\u0435\u0441: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips." }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/sl.json b/homeassistant/components/esphome/translations/sl.json index b16a5cd4226..a82800e502f 100644 --- a/homeassistant/components/esphome/translations/sl.json +++ b/homeassistant/components/esphome/translations/sl.json @@ -1,12 +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_password": "Neveljavno geslo!", + "invalid_auth": "Neveljavna avtentikacija", "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" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/sv.json b/homeassistant/components/esphome/translations/sv.json index 5b57dc18617..d979ff4821c 100644 --- a/homeassistant/components/esphome/translations/sv.json +++ b/homeassistant/components/esphome/translations/sv.json @@ -5,7 +5,6 @@ }, "error": { "connection_error": "Kan inte ansluta till ESP. Se till att din YAML-fil inneh\u00e5ller en 'api:' line.", - "invalid_password": "Ogiltigt l\u00f6senord!", "resolve_error": "Det g\u00e5r inte att hitta IP-adressen f\u00f6r ESP med DNS-namnet. Om det h\u00e4r felet kvarst\u00e5r anger du en statisk IP-adress: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/th.json b/homeassistant/components/esphome/translations/th.json index f7596ba4dd9..948431482a4 100644 --- a/homeassistant/components/esphome/translations/th.json +++ b/homeassistant/components/esphome/translations/th.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_password": "\u0e23\u0e2b\u0e31\u0e2a\u0e1c\u0e48\u0e32\u0e19\u0e44\u0e21\u0e48\u0e16\u0e39\u0e01\u0e15\u0e49\u0e2d\u0e07!" - }, "step": { "authenticate": { "data": { diff --git a/homeassistant/components/esphome/translations/uk.json b/homeassistant/components/esphome/translations/uk.json index f30ac672d4d..d17ec64e548 100644 --- a/homeassistant/components/esphome/translations/uk.json +++ b/homeassistant/components/esphome/translations/uk.json @@ -5,7 +5,6 @@ }, "error": { "connection_error": "\u041d\u0435 \u0432\u0434\u0430\u0454\u0442\u044c\u0441\u044f \u043f\u0456\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u0438\u0441\u044f \u0434\u043e ESP. \u041f\u0435\u0440\u0435\u043a\u043e\u043d\u0430\u0439\u0442\u0435\u0441\u044f, \u0449\u043e \u0444\u0430\u0439\u043b YAML \u043c\u0456\u0441\u0442\u0438\u0442\u044c \u0440\u044f\u0434\u043e\u043a \"api:\".", - "invalid_password": "\u041d\u0435\u0432\u0456\u0440\u043d\u0438\u0439 \u043f\u0430\u0440\u043e\u043b\u044c!", "resolve_error": "\u041d\u0435\u043c\u043e\u0436\u043b\u0438\u0432\u043e \u043e\u0442\u0440\u0438\u043c\u0430\u0442\u0438 \u0430\u0434\u0440\u0435\u0441\u0443 ESP. \u042f\u043a\u0449\u043e \u0446\u044f \u043f\u043e\u043c\u0438\u043b\u043a\u0430 \u043d\u0435 \u0437\u043d\u0438\u043a\u0430\u0454, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0456\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u0443 IP-\u0430\u0434\u0440\u0435\u0441\u0443: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "step": { diff --git a/homeassistant/components/esphome/translations/zh-Hans.json b/homeassistant/components/esphome/translations/zh-Hans.json index 012e4f266d3..b1911b90fde 100644 --- a/homeassistant/components/esphome/translations/zh-Hans.json +++ b/homeassistant/components/esphome/translations/zh-Hans.json @@ -7,7 +7,6 @@ "error": { "connection_error": "\u65e0\u6cd5\u8fde\u63a5\u5230 ESP\u3002\u8bf7\u786e\u8ba4\u60a8\u7684 YAML \u6587\u4ef6\u4e2d\u5305\u542b 'api:' \u884c\u3002", "invalid_auth": "\u8eab\u4efd\u8ba4\u8bc1\u65e0\u6548", - "invalid_password": "\u5bc6\u7801\u65e0\u6548\uff01", "resolve_error": "\u65e0\u6cd5\u89e3\u6790 ESP \u7684\u5730\u5740\u3002\u5982\u679c\u6b64\u9519\u8bef\u6301\u7eed\u5b58\u5728\uff0c\u8bf7\u8bbe\u7f6e\u9759\u6001IP\u5730\u5740\uff1ahttps://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome: {name}", diff --git a/homeassistant/components/esphome/translations/zh-Hant.json b/homeassistant/components/esphome/translations/zh-Hant.json index 785c68a7667..a60ef4fdebf 100644 --- a/homeassistant/components/esphome/translations/zh-Hant.json +++ b/homeassistant/components/esphome/translations/zh-Hant.json @@ -7,7 +7,6 @@ "error": { "connection_error": "\u7121\u6cd5\u9023\u7dda\u81f3 ESP\uff0c\u8acb\u78ba\u5b9a\u60a8\u7684 YAML \u6a94\u6848\u5305\u542b\u300capi:\u300d\u8a2d\u5b9a\u5217\u3002", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_password": "\u5bc6\u78bc\u7121\u6548\uff01", "resolve_error": "\u7121\u6cd5\u89e3\u6790 ESP \u4f4d\u5740\uff0c\u5047\u5982\u6b64\u932f\u8aa4\u6301\u7e8c\u767c\u751f\uff0c\u8acb\u53c3\u8003\u8aaa\u660e\u8a2d\u5b9a\u70ba\u975c\u614b\u56fa\u5b9a IP \uff1a https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, "flow_title": "ESPHome\uff1a{name}", diff --git a/homeassistant/components/essent/sensor.py b/homeassistant/components/essent/sensor.py index e3ce1ccaafa..3ac7af315b7 100644 --- a/homeassistant/components/essent/sensor.py +++ b/homeassistant/components/essent/sensor.py @@ -27,7 +27,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): meters = [] for meter in essent.retrieve_meters(): data = essent.retrieve_meter_data(meter) - for tariff in data["values"]["LVR"].keys(): + for tariff in data["values"]["LVR"]: meters.append( EssentMeter( essent, diff --git a/homeassistant/components/evohome/__init__.py b/homeassistant/components/evohome/__init__.py index 818744f7d05..958750c4dcb 100644 --- a/homeassistant/components/evohome/__init__.py +++ b/homeassistant/components/evohome/__init__.py @@ -140,8 +140,8 @@ def _handle_exception(err) -> bool: except evohomeasync2.AuthenticationError: _LOGGER.error( "Failed to authenticate with the vendor's server. " - "Check your network and the vendor's service status page. " - "Also check that your username and password are correct. " + "Check your username and password. NB: Some special password characters " + "that work correctly via the website will not work via the web API. " "Message is: %s", err, ) @@ -422,20 +422,20 @@ class EvoBroker: await self._store.async_save(app_storage) - async def call_client_api(self, api_function, refresh=True) -> Any: - """Call a client API.""" + async def call_client_api(self, api_function, update_state=True) -> Any: + """Call a client API and update the broker state if required.""" try: result = await api_function except (aiohttp.ClientError, evohomeasync2.AuthenticationError) as err: if not _handle_exception(err): return - if refresh: - self.hass.helpers.event.async_call_later(1, self.async_update) + if update_state: # wait a moment for system to quiesce before updating state + self.hass.helpers.event.async_call_later(1, self._update_v2_api_state) return result - async def _update_v1(self, *args, **kwargs) -> None: + async def _update_v1_api_temps(self, *args, **kwargs) -> None: """Get the latest high-precision temperatures of the default Location.""" def get_session_id(client_v1) -> Optional[str]: @@ -476,7 +476,7 @@ class EvoBroker: if session_id != get_session_id(self.client_v1): await self.save_auth_tokens() - async def _update_v2(self, *args, **kwargs) -> None: + async def _update_v2_api_state(self, *args, **kwargs) -> None: """Get the latest modes, temperatures, setpoints of a Location.""" access_token = self.client.access_token @@ -500,13 +500,10 @@ class EvoBroker: operating mode of the Controller and the current temp of its children (e.g. Zones, DHW controller). """ - await self._update_v2() - if self.client_v1: - await self._update_v1() + await self._update_v1_api_temps() - # inform the evohome devices that state data has been updated - async_dispatcher_send(self.hass, DOMAIN) + await self._update_v2_api_state() class EvoDevice(Entity): @@ -690,7 +687,7 @@ class EvoChild(EvoDevice): return # avoid unnecessary I/O - there's nothing to update self._schedule = await self._evo_broker.call_client_api( - self._evo_device.schedule(), refresh=False + self._evo_device.schedule(), update_state=False ) _LOGGER.debug("Schedule['%s'] = %s", self.name, self._schedule) diff --git a/homeassistant/components/feedreader/__init__.py b/homeassistant/components/feedreader/__init__.py index 548654c11c0..b4d8c1ff75e 100644 --- a/homeassistant/components/feedreader/__init__.py +++ b/homeassistant/components/feedreader/__init__.py @@ -142,7 +142,7 @@ class FeedManager: def _update_and_fire_entry(self, entry): """Update last_entry_timestamp and fire entry.""" # Check if the entry has a published date. - if "published_parsed" in entry.keys() and entry.published_parsed: + if "published_parsed" in entry and entry.published_parsed: # We are lucky, `published_parsed` data available, let's make use of # it to publish only new available entries since the last run self._has_published_parsed = True @@ -166,7 +166,7 @@ class FeedManager: self._last_entry_timestamp = datetime.utcfromtimestamp(0).timetuple() for entry in self._feed.entries: if self._firstrun or ( - "published_parsed" in entry.keys() + "published_parsed" in entry and entry.published_parsed > self._last_entry_timestamp ): self._update_and_fire_entry(entry) diff --git a/homeassistant/components/ffmpeg/__init__.py b/homeassistant/components/ffmpeg/__init__.py index 70ea74dde3f..bf44828cdb0 100644 --- a/homeassistant/components/ffmpeg/__init__.py +++ b/homeassistant/components/ffmpeg/__init__.py @@ -1,7 +1,9 @@ """Support for FFmpeg.""" +import asyncio import re +from typing import Optional -from haffmpeg.tools import FFVersion +from haffmpeg.tools import IMAGE_JPEG, FFVersion, ImageFrame import voluptuous as vol from homeassistant.const import ( @@ -17,6 +19,7 @@ from homeassistant.helpers.dispatcher import ( async_dispatcher_send, ) from homeassistant.helpers.entity import Entity +from homeassistant.helpers.typing import HomeAssistantType DOMAIN = "ffmpeg" @@ -86,6 +89,21 @@ async def async_setup(hass, config): return True +async def async_get_image( + hass: HomeAssistantType, + input_source: str, + output_format: str = IMAGE_JPEG, + extra_cmd: Optional[str] = None, +): + """Get an image from a frame of an RTSP stream.""" + manager = hass.data[DATA_FFMPEG] + ffmpeg = ImageFrame(manager.binary, loop=hass.loop) + image = await asyncio.shield( + ffmpeg.get_image(input_source, output_format=output_format, extra_cmd=extra_cmd) + ) + return image + + class FFmpegManager: """Helper for ha-ffmpeg.""" diff --git a/homeassistant/components/ffmpeg/camera.py b/homeassistant/components/ffmpeg/camera.py index 729c51cf949..6aea28d6509 100644 --- a/homeassistant/components/ffmpeg/camera.py +++ b/homeassistant/components/ffmpeg/camera.py @@ -1,8 +1,7 @@ """Support for Cameras with FFmpeg as decoder.""" -import asyncio from haffmpeg.camera import CameraMjpeg -from haffmpeg.tools import IMAGE_JPEG, ImageFrame +from haffmpeg.tools import IMAGE_JPEG import voluptuous as vol from homeassistant.components.camera import PLATFORM_SCHEMA, SUPPORT_STREAM, Camera @@ -10,7 +9,7 @@ from homeassistant.const import CONF_NAME from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream import homeassistant.helpers.config_validation as cv -from . import CONF_EXTRA_ARGUMENTS, CONF_INPUT, DATA_FFMPEG +from . import CONF_EXTRA_ARGUMENTS, CONF_INPUT, DATA_FFMPEG, async_get_image DEFAULT_NAME = "FFmpeg" DEFAULT_ARGUMENTS = "-pred 1" @@ -52,15 +51,12 @@ class FFmpegCamera(Camera): async def async_camera_image(self): """Return a still image response from the camera.""" - - ffmpeg = ImageFrame(self._manager.binary, loop=self.hass.loop) - - image = await asyncio.shield( - ffmpeg.get_image( - self._input, output_format=IMAGE_JPEG, extra_cmd=self._extra_arguments - ) + return await async_get_image( + self.hass, + self._input, + output_format=IMAGE_JPEG, + extra_cmd=self._extra_arguments, ) - return image async def handle_async_mjpeg_stream(self, request): """Generate an HTTP MJPEG stream from the camera.""" diff --git a/homeassistant/components/fibaro/__init__.py b/homeassistant/components/fibaro/__init__.py index 6b56b146a9c..51e31cf27ad 100644 --- a/homeassistant/components/fibaro/__init__.py +++ b/homeassistant/components/fibaro/__init__.py @@ -164,7 +164,7 @@ class FibaroController: for change in state.get("changes", []): try: dev_id = change.pop("id") - if dev_id not in self._device_map.keys(): + if dev_id not in self._device_map: continue device = self._device_map[dev_id] for property_name, value in change.items(): diff --git a/homeassistant/components/firmata/translations/de.json b/homeassistant/components/firmata/translations/de.json new file mode 100644 index 00000000000..530c3b3a4ad --- /dev/null +++ b/homeassistant/components/firmata/translations/de.json @@ -0,0 +1,7 @@ +{ + "config": { + "abort": { + "cannot_connect": "Verbindung fehlgeschlagen" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/flick_electric/strings.json b/homeassistant/components/flick_electric/strings.json index a37a803fb6a..a20b5059ef7 100644 --- a/homeassistant/components/flick_electric/strings.json +++ b/homeassistant/components/flick_electric/strings.json @@ -1,5 +1,4 @@ { - "title": "Flick Electric", "config": { "step": { "user": { diff --git a/homeassistant/components/flick_electric/translations/ca.json b/homeassistant/components/flick_electric/translations/ca.json index 5bc9684d3b2..74fd0e79708 100644 --- a/homeassistant/components/flick_electric/translations/ca.json +++ b/homeassistant/components/flick_electric/translations/ca.json @@ -19,6 +19,5 @@ "title": "Credencials d'inici de sessi\u00f3 de Flick" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/cs.json b/homeassistant/components/flick_electric/translations/cs.json index bf5db1bd68f..6653b76bcd2 100644 --- a/homeassistant/components/flick_electric/translations/cs.json +++ b/homeassistant/components/flick_electric/translations/cs.json @@ -11,12 +11,12 @@ "step": { "user": { "data": { + "client_id": "ID klienta (voliteln\u00e9)", "password": "Heslo", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" }, "title": "P\u0159ihla\u0161ovac\u00ed \u00fadaje k Flick" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/de.json b/homeassistant/components/flick_electric/translations/de.json index d63283fe36b..b69e8de8f7c 100644 --- a/homeassistant/components/flick_electric/translations/de.json +++ b/homeassistant/components/flick_electric/translations/de.json @@ -16,6 +16,5 @@ } } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/en.json b/homeassistant/components/flick_electric/translations/en.json index 4a3e4c8fbe6..ecade0c677b 100644 --- a/homeassistant/components/flick_electric/translations/en.json +++ b/homeassistant/components/flick_electric/translations/en.json @@ -19,6 +19,5 @@ "title": "Flick Login Credentials" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/es.json b/homeassistant/components/flick_electric/translations/es.json index 3642dd0b4d5..435ead31d9a 100644 --- a/homeassistant/components/flick_electric/translations/es.json +++ b/homeassistant/components/flick_electric/translations/es.json @@ -19,6 +19,5 @@ "title": "Credenciales de Inicio de Sesi\u00f3n de Flick" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/et.json b/homeassistant/components/flick_electric/translations/et.json index 11f5060ff69..738fbaaef01 100644 --- a/homeassistant/components/flick_electric/translations/et.json +++ b/homeassistant/components/flick_electric/translations/et.json @@ -11,11 +11,13 @@ "step": { "user": { "data": { + "client_id": "Kliendi ID (valikuline)", + "client_secret": "Kliendi salas\u00f5na (valikuline)", "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "Flick'i sisselogimisandmeid" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/fi.json b/homeassistant/components/flick_electric/translations/fi.json index 9be2c5dbf94..a38c6e25c20 100644 --- a/homeassistant/components/flick_electric/translations/fi.json +++ b/homeassistant/components/flick_electric/translations/fi.json @@ -19,6 +19,5 @@ "title": "Flick Login -tunnukset" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/fr.json b/homeassistant/components/flick_electric/translations/fr.json index edae67d4173..291a8e59fe4 100644 --- a/homeassistant/components/flick_electric/translations/fr.json +++ b/homeassistant/components/flick_electric/translations/fr.json @@ -19,6 +19,5 @@ "title": "Identifiants de connexion Flick" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/it.json b/homeassistant/components/flick_electric/translations/it.json index a955849183a..a505f915c6f 100644 --- a/homeassistant/components/flick_electric/translations/it.json +++ b/homeassistant/components/flick_electric/translations/it.json @@ -19,6 +19,5 @@ "title": "Credenziali di accesso Flick" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/ko.json b/homeassistant/components/flick_electric/translations/ko.json index 9becb915c3a..82d095f2755 100644 --- a/homeassistant/components/flick_electric/translations/ko.json +++ b/homeassistant/components/flick_electric/translations/ko.json @@ -19,6 +19,5 @@ "title": "Flick \ub85c\uadf8\uc778 \uc790\uaca9 \uc99d\uba85" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/lb.json b/homeassistant/components/flick_electric/translations/lb.json index 4eef13683a2..3eeb352d81d 100644 --- a/homeassistant/components/flick_electric/translations/lb.json +++ b/homeassistant/components/flick_electric/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "D\u00ebse Kont ass scho konfigur\u00e9iert" + "already_configured": "Kont ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, @@ -19,6 +19,5 @@ "title": "Flick Login Informatiounen" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/nl.json b/homeassistant/components/flick_electric/translations/nl.json index f252147c776..f90ee71301b 100644 --- a/homeassistant/components/flick_electric/translations/nl.json +++ b/homeassistant/components/flick_electric/translations/nl.json @@ -3,12 +3,20 @@ "abort": { "already_configured": "Account is al geconfigureerd" }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "client_id": "Client-ID (optioneel)", + "client_secret": "Clientgeheim (optioneel)", "password": "Wachtwoord", "username": "Gebruikersnaam" - } + }, + "title": "Flick inloggegevens" } } } diff --git a/homeassistant/components/flick_electric/translations/no.json b/homeassistant/components/flick_electric/translations/no.json index 604d48a738f..5cc6357058d 100644 --- a/homeassistant/components/flick_electric/translations/no.json +++ b/homeassistant/components/flick_electric/translations/no.json @@ -19,6 +19,5 @@ "title": "Flick p\u00e5loggingsinformasjon" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/pl.json b/homeassistant/components/flick_electric/translations/pl.json index 1c7d565d232..9abf7ef5ce0 100644 --- a/homeassistant/components/flick_electric/translations/pl.json +++ b/homeassistant/components/flick_electric/translations/pl.json @@ -19,6 +19,5 @@ "title": "Logowanie do Flick" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/pt-BR.json b/homeassistant/components/flick_electric/translations/pt-BR.json index 5d7f10c1e03..f23a27c2b73 100644 --- a/homeassistant/components/flick_electric/translations/pt-BR.json +++ b/homeassistant/components/flick_electric/translations/pt-BR.json @@ -19,6 +19,5 @@ "title": "Credenciais de login do Flick" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/ru.json b/homeassistant/components/flick_electric/translations/ru.json index 5883c386696..c97bb9133cc 100644 --- a/homeassistant/components/flick_electric/translations/ru.json +++ b/homeassistant/components/flick_electric/translations/ru.json @@ -19,6 +19,5 @@ "title": "Flick Electric" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flick_electric/translations/zh-Hant.json b/homeassistant/components/flick_electric/translations/zh-Hant.json index 9e7b29b4893..3df68984ec5 100644 --- a/homeassistant/components/flick_electric/translations/zh-Hant.json +++ b/homeassistant/components/flick_electric/translations/zh-Hant.json @@ -19,6 +19,5 @@ "title": "Flick \u767b\u5165\u6191\u8b49" } } - }, - "title": "Flick Electric" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/manifest.json b/homeassistant/components/flo/manifest.json index 1d9ae596afb..81505ed8d14 100644 --- a/homeassistant/components/flo/manifest.json +++ b/homeassistant/components/flo/manifest.json @@ -4,9 +4,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/flo", "requirements": ["aioflo==0.4.1"], - "ssdp": [], - "zeroconf": [], - "homekit": {}, - "dependencies": [], "codeowners": ["@dmulcahey"] } diff --git a/homeassistant/components/flo/strings.json b/homeassistant/components/flo/strings.json index 7da0d2df2be..d6e3212b4ea 100644 --- a/homeassistant/components/flo/strings.json +++ b/homeassistant/components/flo/strings.json @@ -1,5 +1,4 @@ { - "title": "flo", "config": { "step": { "user": { @@ -19,4 +18,4 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } } -} \ No newline at end of file +} diff --git a/homeassistant/components/flo/translations/ca.json b/homeassistant/components/flo/translations/ca.json index 9f2af24fb0c..df8218bab3e 100644 --- a/homeassistant/components/flo/translations/ca.json +++ b/homeassistant/components/flo/translations/ca.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/cs.json b/homeassistant/components/flo/translations/cs.json index bbb0d3bfe65..0f02cd974c2 100644 --- a/homeassistant/components/flo/translations/cs.json +++ b/homeassistant/components/flo/translations/cs.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/en.json b/homeassistant/components/flo/translations/en.json index 2b5ee5b33ee..f15fe84c3ed 100644 --- a/homeassistant/components/flo/translations/en.json +++ b/homeassistant/components/flo/translations/en.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/es.json b/homeassistant/components/flo/translations/es.json index cf11e586483..9267e363693 100644 --- a/homeassistant/components/flo/translations/es.json +++ b/homeassistant/components/flo/translations/es.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/et.json b/homeassistant/components/flo/translations/et.json index b926ea91669..7898215ded8 100644 --- a/homeassistant/components/flo/translations/et.json +++ b/homeassistant/components/flo/translations/et.json @@ -17,6 +17,5 @@ } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/fr.json b/homeassistant/components/flo/translations/fr.json index 4013a390696..45620fe7795 100644 --- a/homeassistant/components/flo/translations/fr.json +++ b/homeassistant/components/flo/translations/fr.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/it.json b/homeassistant/components/flo/translations/it.json index 824e021aa58..e9356485e08 100644 --- a/homeassistant/components/flo/translations/it.json +++ b/homeassistant/components/flo/translations/it.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/ko.json b/homeassistant/components/flo/translations/ko.json index 7235d67c278..ab85b70afa7 100644 --- a/homeassistant/components/flo/translations/ko.json +++ b/homeassistant/components/flo/translations/ko.json @@ -15,6 +15,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/lb.json b/homeassistant/components/flo/translations/lb.json index 33aaba2878f..e235a2f9047 100644 --- a/homeassistant/components/flo/translations/lb.json +++ b/homeassistant/components/flo/translations/lb.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/nl.json b/homeassistant/components/flo/translations/nl.json index c4901d328c3..d4c409802c1 100644 --- a/homeassistant/components/flo/translations/nl.json +++ b/homeassistant/components/flo/translations/nl.json @@ -1,8 +1,17 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "host": "Host", "password": "Wachtwoord", "username": "Gebruikersnaam" } diff --git a/homeassistant/components/flo/translations/no.json b/homeassistant/components/flo/translations/no.json index bf7f9170872..249711bb912 100644 --- a/homeassistant/components/flo/translations/no.json +++ b/homeassistant/components/flo/translations/no.json @@ -17,6 +17,5 @@ } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/pl.json b/homeassistant/components/flo/translations/pl.json index 561b45d65b1..25dab56796c 100644 --- a/homeassistant/components/flo/translations/pl.json +++ b/homeassistant/components/flo/translations/pl.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/ru.json b/homeassistant/components/flo/translations/ru.json index 5d55f2d523f..6f71ee41376 100644 --- a/homeassistant/components/flo/translations/ru.json +++ b/homeassistant/components/flo/translations/ru.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flo/translations/zh-Hant.json b/homeassistant/components/flo/translations/zh-Hant.json index 3856bfdec9a..8bf65ef6ee6 100644 --- a/homeassistant/components/flo/translations/zh-Hant.json +++ b/homeassistant/components/flo/translations/zh-Hant.json @@ -17,6 +17,5 @@ } } } - }, - "title": "flo" + } } \ No newline at end of file diff --git a/homeassistant/components/flume/manifest.json b/homeassistant/components/flume/manifest.json index 3698df3c269..f00bccb886a 100644 --- a/homeassistant/components/flume/manifest.json +++ b/homeassistant/components/flume/manifest.json @@ -3,7 +3,6 @@ "name": "Flume", "documentation": "https://www.home-assistant.io/integrations/flume/", "requirements": ["pyflume==0.5.5"], - "dependencies": [], "codeowners": ["@ChrisMandich", "@bdraco"], "config_flow": true } diff --git a/homeassistant/components/flume/translations/et.json b/homeassistant/components/flume/translations/et.json index 6055d02a4d0..e1a080b49a3 100644 --- a/homeassistant/components/flume/translations/et.json +++ b/homeassistant/components/flume/translations/et.json @@ -11,9 +11,13 @@ "step": { "user": { "data": { + "client_id": "Kliendi ID", + "client_secret": "Kliendi salas\u00f5na", "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "description": "Flume Personal API-le juurdep\u00e4\u00e4suks pead lehel https://portal.flumetech.com/settings#token taotlema kliendi ID ja salas\u00f5na.", + "title": "\u00dchendu oma Flume kontoga" } } } diff --git a/homeassistant/components/flume/translations/lb.json b/homeassistant/components/flume/translations/lb.json index 67f18d61547..5edf592fdff 100644 --- a/homeassistant/components/flume/translations/lb.json +++ b/homeassistant/components/flume/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "D\u00ebse Kont ass scho konfigur\u00e9iert" + "already_configured": "Kont ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, diff --git a/homeassistant/components/flume/translations/pl.json b/homeassistant/components/flume/translations/pl.json index a9ff9bcfd04..f84513f1cb5 100644 --- a/homeassistant/components/flume/translations/pl.json +++ b/homeassistant/components/flume/translations/pl.json @@ -16,7 +16,7 @@ "password": "Has\u0142o", "username": "Nazwa u\u017cytkownika" }, - "description": "Aby uzyska\u0107 dost\u0119p do API Flume, musisz poprosi\u0107 o 'ID klienta\u201d i 'klucz tajny klienta' na stronie https://portal.flumetech.com/settings#token", + "description": "Aby uzyska\u0107 dost\u0119p do API Flume, musisz poprosi\u0107 o \"Client ID\" oraz \"Client secret\" na stronie https://portal.flumetech.com/settings#token", "title": "Po\u0142\u0105czenie z kontem Flume" } } diff --git a/homeassistant/components/flunearyou/__init__.py b/homeassistant/components/flunearyou/__init__.py index 4dae0b3f7cd..7399dd3847d 100644 --- a/homeassistant/components/flunearyou/__init__.py +++ b/homeassistant/components/flunearyou/__init__.py @@ -1,211 +1,91 @@ """The flunearyou component.""" import asyncio from datetime import timedelta +from functools import partial 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 -from homeassistant.helpers.dispatcher import async_dispatcher_send -from homeassistant.helpers.event import async_track_time_interval +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import ( CATEGORY_CDC_REPORT, CATEGORY_USER_REPORT, - DATA_CLIENT, + DATA_COORDINATOR, DOMAIN, LOGGER, - SENSORS, - TOPIC_UPDATE, ) -DATA_LISTENER = "listener" +DEFAULT_UPDATE_INTERVAL = timedelta(minutes=30) -DEFAULT_SCAN_INTERVAL = timedelta(minutes=30) +CONFIG_SCHEMA = cv.deprecated(DOMAIN, invalidation_version="0.119") -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, -) - - -@callback -def async_get_api_category(sensor_type): - """Get the category that a particular sensor type belongs to.""" - try: - return next( - ( - category - for category, sensors in SENSORS.items() - for sensor in sensors - if sensor[0] == sensor_type - ) - ) - except StopIteration as err: - raise ValueError(f"Can't find category sensor type: {sensor_type}") from err +PLATFORMS = ["sensor"] 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 - ), - }, - ) - ) - + hass.data[DOMAIN] = {DATA_COORDINATOR: {}} return True async def async_setup_entry(hass, config_entry): """Set up Flu Near You as config entry.""" + hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id] = {} + websession = aiohttp_client.async_get_clientsession(hass) + client = Client(websession) - fny = FluNearYouData( - hass, - Client(websession), - config_entry.data.get(CONF_LATITUDE, hass.config.latitude), - config_entry.data.get(CONF_LONGITUDE, hass.config.longitude), - ) - await fny.async_update() - hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = fny + latitude = config_entry.data.get(CONF_LATITUDE, hass.config.latitude) + longitude = config_entry.data.get(CONF_LONGITUDE, hass.config.longitude) - hass.async_create_task( - hass.config_entries.async_forward_entry_setup(config_entry, "sensor") - ) + async def async_update(api_category): + """Get updated date from the API based on category.""" + try: + if api_category == CATEGORY_CDC_REPORT: + return await client.cdc_reports.status_by_coordinates( + latitude, longitude + ) + return await client.user_reports.status_by_coordinates(latitude, longitude) + except FluNearYouError as err: + raise UpdateFailed(err) from err - async def refresh(event_time): - """Refresh data from Flu Near You.""" - await fny.async_update() + data_init_tasks = [] + for api_category in [CATEGORY_CDC_REPORT, CATEGORY_USER_REPORT]: + coordinator = hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id][ + api_category + ] = DataUpdateCoordinator( + hass, + LOGGER, + name=f"{api_category} ({latitude}, {longitude})", + update_interval=DEFAULT_UPDATE_INTERVAL, + update_method=partial(async_update, api_category), + ) + data_init_tasks.append(coordinator.async_refresh()) - hass.data[DOMAIN][DATA_LISTENER][config_entry.entry_id] = async_track_time_interval( - hass, refresh, DEFAULT_SCAN_INTERVAL - ) + await asyncio.gather(*data_init_tasks) + + for component in PLATFORMS: + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(config_entry, component) + ) return True async def async_unload_entry(hass, config_entry): """Unload an Flu Near You config entry.""" - hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id) + unload_ok = all( + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(config_entry, component) + for component in PLATFORMS + ] + ) + ) + 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() - - await hass.config_entries.async_forward_entry_unload(config_entry, "sensor") - - return True - - -class FluNearYouData: - """Define a data object to retrieve info from Flu Near You.""" - - def __init__(self, hass, client, latitude, longitude): - """Initialize.""" - self._async_cancel_time_interval_listener = None - self._client = client - self._hass = hass - self.data = {} - self.latitude = latitude - self.longitude = longitude - - self._api_category_count = { - CATEGORY_CDC_REPORT: 0, - CATEGORY_USER_REPORT: 0, - } - - self._api_category_locks = { - CATEGORY_CDC_REPORT: asyncio.Lock(), - CATEGORY_USER_REPORT: asyncio.Lock(), - } - - async def _async_get_data_from_api(self, api_category): - """Update and save data for a particular API category.""" - if self._api_category_count[api_category] == 0: - return - - if api_category == CATEGORY_CDC_REPORT: - api_coro = self._client.cdc_reports.status_by_coordinates( - self.latitude, self.longitude - ) - else: - api_coro = self._client.user_reports.status_by_coordinates( - self.latitude, self.longitude - ) - - try: - self.data[api_category] = await api_coro - except FluNearYouError as err: - LOGGER.error("Unable to get %s data: %s", api_category, err) - self.data[api_category] = None - - async def _async_update_listener_action(self, now): - """Define an async_track_time_interval action to update data.""" - await self.async_update() - - @callback - def async_deregister_api_interest(self, sensor_type): - """Decrement the number of entities with data needs from an API category.""" - # If this deregistration should leave us with no registration at all, remove the - # time interval: - if sum(self._api_category_count.values()) == 0: - if self._async_cancel_time_interval_listener: - self._async_cancel_time_interval_listener() - self._async_cancel_time_interval_listener = None - return - - api_category = async_get_api_category(sensor_type) - self._api_category_count[api_category] -= 1 - - async def async_register_api_interest(self, sensor_type): - """Increment the number of entities with data needs from an API category.""" - # If this is the first registration we have, start a time interval: - if not self._async_cancel_time_interval_listener: - self._async_cancel_time_interval_listener = async_track_time_interval( - self._hass, - self._async_update_listener_action, - DEFAULT_SCAN_INTERVAL, - ) - - api_category = async_get_api_category(sensor_type) - self._api_category_count[api_category] += 1 - - # If a sensor registers interest in a particular API call and the data doesn't - # exist for it yet, make the API call and grab the data: - async with self._api_category_locks[api_category]: - if api_category not in self.data: - await self._async_get_data_from_api(api_category) - - async def async_update(self): - """Update Flu Near You data.""" - tasks = [ - self._async_get_data_from_api(api_category) - for api_category in self._api_category_count - ] - - await asyncio.gather(*tasks) - - LOGGER.debug("Received new data") - async_dispatcher_send(self._hass, TOPIC_UPDATE) + return unload_ok diff --git a/homeassistant/components/flunearyou/config_flow.py b/homeassistant/components/flunearyou/config_flow.py index 9918858fd93..8bdef58f7e1 100644 --- a/homeassistant/components/flunearyou/config_flow.py +++ b/homeassistant/components/flunearyou/config_flow.py @@ -30,10 +30,6 @@ class FluNearYouFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): } ) - 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/homeassistant/components/flunearyou/const.py b/homeassistant/components/flunearyou/const.py index ac8008f7f9b..96df29aa300 100644 --- a/homeassistant/components/flunearyou/const.py +++ b/homeassistant/components/flunearyou/const.py @@ -4,35 +4,7 @@ import logging DOMAIN = "flunearyou" LOGGER = logging.getLogger(__package__) -DATA_CLIENT = "client" +DATA_COORDINATOR = "coordinator" CATEGORY_CDC_REPORT = "cdc_report" CATEGORY_USER_REPORT = "user_report" - -TOPIC_UPDATE = "flunearyou_update" - -TYPE_CDC_LEVEL = "level" -TYPE_CDC_LEVEL2 = "level2" -TYPE_USER_CHICK = "chick" -TYPE_USER_DENGUE = "dengue" -TYPE_USER_FLU = "flu" -TYPE_USER_LEPTO = "lepto" -TYPE_USER_NO_SYMPTOMS = "none" -TYPE_USER_SYMPTOMS = "symptoms" -TYPE_USER_TOTAL = "total" - -SENSORS = { - CATEGORY_CDC_REPORT: [ - (TYPE_CDC_LEVEL, "CDC Level", "mdi:biohazard", None), - (TYPE_CDC_LEVEL2, "CDC Level 2", "mdi:biohazard", None), - ], - CATEGORY_USER_REPORT: [ - (TYPE_USER_CHICK, "Avian Flu Symptoms", "mdi:alert", "reports"), - (TYPE_USER_DENGUE, "Dengue Fever Symptoms", "mdi:alert", "reports"), - (TYPE_USER_FLU, "Flu Symptoms", "mdi:alert", "reports"), - (TYPE_USER_LEPTO, "Leptospirosis Symptoms", "mdi:alert", "reports"), - (TYPE_USER_NO_SYMPTOMS, "No Symptoms", "mdi:alert", "reports"), - (TYPE_USER_SYMPTOMS, "Flu-like Symptoms", "mdi:alert", "reports"), - (TYPE_USER_TOTAL, "Total Symptoms", "mdi:alert", "reports"), - ], -} diff --git a/homeassistant/components/flunearyou/sensor.py b/homeassistant/components/flunearyou/sensor.py index 22c56c10038..8bb5f1317d1 100644 --- a/homeassistant/components/flunearyou/sensor.py +++ b/homeassistant/components/flunearyou/sensor.py @@ -1,24 +1,14 @@ """Support for user- and CDC-based flu info sensors from Flu Near You.""" -from homeassistant.const import ATTR_ATTRIBUTION, ATTR_STATE -from homeassistant.core import callback -from homeassistant.helpers.dispatcher import async_dispatcher_connect -from homeassistant.helpers.entity import Entity - -from .const import ( - CATEGORY_CDC_REPORT, - CATEGORY_USER_REPORT, - DATA_CLIENT, - DOMAIN, - SENSORS, - TOPIC_UPDATE, - TYPE_USER_CHICK, - TYPE_USER_DENGUE, - TYPE_USER_FLU, - TYPE_USER_LEPTO, - TYPE_USER_NO_SYMPTOMS, - TYPE_USER_SYMPTOMS, - TYPE_USER_TOTAL, +from homeassistant.const import ( + ATTR_ATTRIBUTION, + ATTR_STATE, + CONF_LATITUDE, + CONF_LONGITUDE, ) +from homeassistant.core import callback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import CATEGORY_CDC_REPORT, CATEGORY_USER_REPORT, DATA_COORDINATOR, DOMAIN ATTR_CITY = "city" ATTR_REPORTED_DATE = "reported_date" @@ -30,46 +20,85 @@ ATTR_ZIP_CODE = "zip_code" DEFAULT_ATTRIBUTION = "Data provided by Flu Near You" -EXTENDED_TYPE_MAPPING = { - TYPE_USER_FLU: "ili", - TYPE_USER_NO_SYMPTOMS: "no_symptoms", - TYPE_USER_TOTAL: "total_surveys", +SENSOR_TYPE_CDC_LEVEL = "level" +SENSOR_TYPE_CDC_LEVEL2 = "level2" +SENSOR_TYPE_USER_CHICK = "chick" +SENSOR_TYPE_USER_DENGUE = "dengue" +SENSOR_TYPE_USER_FLU = "flu" +SENSOR_TYPE_USER_LEPTO = "lepto" +SENSOR_TYPE_USER_NO_SYMPTOMS = "none" +SENSOR_TYPE_USER_SYMPTOMS = "symptoms" +SENSOR_TYPE_USER_TOTAL = "total" + +CDC_SENSORS = [ + (SENSOR_TYPE_CDC_LEVEL, "CDC Level", "mdi:biohazard", None), + (SENSOR_TYPE_CDC_LEVEL2, "CDC Level 2", "mdi:biohazard", None), +] + +USER_SENSORS = [ + (SENSOR_TYPE_USER_CHICK, "Avian Flu Symptoms", "mdi:alert", "reports"), + (SENSOR_TYPE_USER_DENGUE, "Dengue Fever Symptoms", "mdi:alert", "reports"), + (SENSOR_TYPE_USER_FLU, "Flu Symptoms", "mdi:alert", "reports"), + (SENSOR_TYPE_USER_LEPTO, "Leptospirosis Symptoms", "mdi:alert", "reports"), + (SENSOR_TYPE_USER_NO_SYMPTOMS, "No Symptoms", "mdi:alert", "reports"), + (SENSOR_TYPE_USER_SYMPTOMS, "Flu-like Symptoms", "mdi:alert", "reports"), + (SENSOR_TYPE_USER_TOTAL, "Total Symptoms", "mdi:alert", "reports"), +] + +EXTENDED_SENSOR_TYPE_MAPPING = { + SENSOR_TYPE_USER_FLU: "ili", + SENSOR_TYPE_USER_NO_SYMPTOMS: "no_symptoms", + SENSOR_TYPE_USER_TOTAL: "total_surveys", } async def async_setup_entry(hass, config_entry, async_add_entities): """Set up Flu Near You sensors based on a config entry.""" - fny = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] + coordinators = hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id] - async_add_entities( - [ - FluNearYouSensor(fny, sensor_type, name, category, icon, unit) - for category, sensors in SENSORS.items() - for sensor_type, name, icon, unit in sensors - ], - True, - ) + sensors = [] + + for (sensor_type, name, icon, unit) in CDC_SENSORS: + sensors.append( + CdcSensor( + coordinators[CATEGORY_CDC_REPORT], + config_entry, + sensor_type, + name, + icon, + unit, + ) + ) + + for (sensor_type, name, icon, unit) in USER_SENSORS: + sensors.append( + UserSensor( + coordinators[CATEGORY_USER_REPORT], + config_entry, + sensor_type, + name, + icon, + unit, + ) + ) + + async_add_entities(sensors) -class FluNearYouSensor(Entity): +class FluNearYouSensor(CoordinatorEntity): """Define a base Flu Near You sensor.""" - def __init__(self, fny, sensor_type, name, category, icon, unit): + def __init__(self, coordinator, config_entry, sensor_type, name, icon, unit): """Initialize the sensor.""" + super().__init__(coordinator) self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION} - self._category = category - self._fny = fny + self._config_entry = config_entry self._icon = icon self._name = name self._sensor_type = sensor_type self._state = None self._unit = unit - @property - def available(self): - """Return True if entity is available.""" - return bool(self._fny.data[self._category]) - @property def device_state_attributes(self): """Return the device state attributes.""" @@ -93,79 +122,88 @@ class FluNearYouSensor(Entity): @property def unique_id(self): """Return a unique, Home Assistant friendly identifier for this entity.""" - return f"{self._fny.latitude},{self._fny.longitude}_{self._sensor_type}" + return ( + f"{self._config_entry.data[CONF_LATITUDE]}," + f"{self._config_entry.data[CONF_LONGITUDE]}_{self._sensor_type}" + ) @property def unit_of_measurement(self): """Return the unit the value is expressed in.""" return self._unit + @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(async_dispatcher_connect(self.hass, TOPIC_UPDATE, update)) - await self._fny.async_register_api_interest(self._sensor_type) + await super().async_added_to_hass() self.update_from_latest_data() - async def async_will_remove_from_hass(self) -> None: - """Disconnect dispatcher listener when removed.""" - self._fny.async_deregister_api_interest(self._sensor_type) - @callback def update_from_latest_data(self): """Update the sensor.""" - cdc_data = self._fny.data.get(CATEGORY_CDC_REPORT) - user_data = self._fny.data.get(CATEGORY_USER_REPORT) + raise NotImplementedError - if self._category == CATEGORY_CDC_REPORT and cdc_data: - self._attrs.update( - { - ATTR_REPORTED_DATE: cdc_data["week_date"], - ATTR_STATE: cdc_data["name"], - } - ) - self._state = cdc_data[self._sensor_type] - elif self._category == CATEGORY_USER_REPORT and user_data: - self._attrs.update( - { - ATTR_CITY: user_data["local"]["city"].split("(")[0], - ATTR_REPORTED_LATITUDE: user_data["local"]["latitude"], - ATTR_REPORTED_LONGITUDE: user_data["local"]["longitude"], - ATTR_STATE: user_data["state"]["name"], - ATTR_ZIP_CODE: user_data["local"]["zip"], - } - ) - if self._sensor_type in user_data["state"]["data"]: - states_key = self._sensor_type - elif self._sensor_type in EXTENDED_TYPE_MAPPING: - states_key = EXTENDED_TYPE_MAPPING[self._sensor_type] +class CdcSensor(FluNearYouSensor): + """Define a sensor for CDC reports.""" - self._attrs[ATTR_STATE_REPORTS_THIS_WEEK] = user_data["state"]["data"][ - states_key - ] - self._attrs[ATTR_STATE_REPORTS_LAST_WEEK] = user_data["state"][ - "last_week_data" - ][states_key] + @callback + def update_from_latest_data(self): + """Update the sensor.""" + self._attrs.update( + { + ATTR_REPORTED_DATE: self.coordinator.data["week_date"], + ATTR_STATE: self.coordinator.data["name"], + } + ) + self._state = self.coordinator.data[self._sensor_type] - if self._sensor_type == TYPE_USER_TOTAL: - self._state = sum( - v - for k, v in user_data["local"].items() - if k - in ( - TYPE_USER_CHICK, - TYPE_USER_DENGUE, - TYPE_USER_FLU, - TYPE_USER_LEPTO, - TYPE_USER_SYMPTOMS, - ) + +class UserSensor(FluNearYouSensor): + """Define a sensor for user reports.""" + + @callback + def update_from_latest_data(self): + """Update the sensor.""" + self._attrs.update( + { + ATTR_CITY: self.coordinator.data["local"]["city"].split("(")[0], + ATTR_REPORTED_LATITUDE: self.coordinator.data["local"]["latitude"], + ATTR_REPORTED_LONGITUDE: self.coordinator.data["local"]["longitude"], + ATTR_STATE: self.coordinator.data["state"]["name"], + ATTR_ZIP_CODE: self.coordinator.data["local"]["zip"], + } + ) + + if self._sensor_type in self.coordinator.data["state"]["data"]: + states_key = self._sensor_type + elif self._sensor_type in EXTENDED_SENSOR_TYPE_MAPPING: + states_key = EXTENDED_SENSOR_TYPE_MAPPING[self._sensor_type] + + self._attrs[ATTR_STATE_REPORTS_THIS_WEEK] = self.coordinator.data["state"][ + "data" + ][states_key] + self._attrs[ATTR_STATE_REPORTS_LAST_WEEK] = self.coordinator.data["state"][ + "last_week_data" + ][states_key] + + if self._sensor_type == SENSOR_TYPE_USER_TOTAL: + self._state = sum( + v + for k, v in self.coordinator.data["local"].items() + if k + in ( + SENSOR_TYPE_USER_CHICK, + SENSOR_TYPE_USER_DENGUE, + SENSOR_TYPE_USER_FLU, + SENSOR_TYPE_USER_LEPTO, + SENSOR_TYPE_USER_SYMPTOMS, ) - else: - self._state = user_data["local"][self._sensor_type] + ) + else: + self._state = self.coordinator.data["local"][self._sensor_type] diff --git a/homeassistant/components/flunearyou/strings.json b/homeassistant/components/flunearyou/strings.json index 5736b266e6c..4df0326fc3b 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 +} diff --git a/homeassistant/components/flunearyou/translations/ca.json b/homeassistant/components/flunearyou/translations/ca.json index e61856a6601..9ae2ebd9a26 100644 --- a/homeassistant/components/flunearyou/translations/ca.json +++ b/homeassistant/components/flunearyou/translations/ca.json @@ -4,7 +4,6 @@ "already_configured": "La ubicaci\u00f3 ja est\u00e0 configurada" }, "error": { - "general_error": "S'ha produ\u00eft un error desconegut.", "unknown": "Error inesperat" }, "step": { diff --git a/homeassistant/components/flunearyou/translations/cs.json b/homeassistant/components/flunearyou/translations/cs.json index 3d9f981c65a..64cb764a52d 100644 --- a/homeassistant/components/flunearyou/translations/cs.json +++ b/homeassistant/components/flunearyou/translations/cs.json @@ -4,7 +4,6 @@ "already_configured": "Um\u00edst\u011bn\u00ed je ji\u017e nastaveno" }, "error": { - "general_error": "Do\u0161lo k nezn\u00e1m\u00e9 chyb\u011b.", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { diff --git a/homeassistant/components/flunearyou/translations/de.json b/homeassistant/components/flunearyou/translations/de.json index 69e4fc0f478..e7dc1f6cd27 100644 --- a/homeassistant/components/flunearyou/translations/de.json +++ b/homeassistant/components/flunearyou/translations/de.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Diese Koordinaten sind bereits registriert." }, - "error": { - "general_error": "Es gab einen unbekannten Fehler." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/flunearyou/translations/en.json b/homeassistant/components/flunearyou/translations/en.json index d94d5c771f4..29af5b2b288 100644 --- a/homeassistant/components/flunearyou/translations/en.json +++ b/homeassistant/components/flunearyou/translations/en.json @@ -4,7 +4,6 @@ "already_configured": "Location is already configured" }, "error": { - "general_error": "There was an unknown error.", "unknown": "Unexpected error" }, "step": { @@ -13,7 +12,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/es-419.json b/homeassistant/components/flunearyou/translations/es-419.json index 9626a509bca..726a898a8b6 100644 --- a/homeassistant/components/flunearyou/translations/es-419.json +++ b/homeassistant/components/flunearyou/translations/es-419.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Estas coordenadas ya est\u00e1n registradas." }, - "error": { - "general_error": "Se ha producido un error desconocido." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/flunearyou/translations/es.json b/homeassistant/components/flunearyou/translations/es.json index c7306db4ec7..5d0c05c0c54 100644 --- a/homeassistant/components/flunearyou/translations/es.json +++ b/homeassistant/components/flunearyou/translations/es.json @@ -4,7 +4,6 @@ "already_configured": "Estas coordenadas ya est\u00e1n registradas." }, "error": { - "general_error": "Se ha producido un error desconocido.", "unknown": "Error inesperado" }, "step": { diff --git a/homeassistant/components/flunearyou/translations/et.json b/homeassistant/components/flunearyou/translations/et.json index 1f745801393..9d79d166ef7 100644 --- a/homeassistant/components/flunearyou/translations/et.json +++ b/homeassistant/components/flunearyou/translations/et.json @@ -4,7 +4,6 @@ "already_configured": "Asukoht on juba h\u00e4\u00e4lestatud" }, "error": { - "general_error": "Tekkis tundmatu viga.", "unknown": "Tundmatu viga" }, "step": { @@ -12,7 +11,9 @@ "data": { "latitude": "Laiuskraad", "longitude": "Pikkuskraad" - } + }, + "description": "Kasutajap\u00f5histe ja CDC-aruannete j\u00e4lgimine antud asukohas.", + "title": "Seadista Flu Near You" } } } diff --git a/homeassistant/components/flunearyou/translations/fr.json b/homeassistant/components/flunearyou/translations/fr.json index 50300be55e1..bd1cc30ca5b 100644 --- a/homeassistant/components/flunearyou/translations/fr.json +++ b/homeassistant/components/flunearyou/translations/fr.json @@ -4,7 +4,7 @@ "already_configured": "Coordonn\u00e9es d\u00e9j\u00e0 enregistr\u00e9es" }, "error": { - "general_error": "Une erreur inconnue est survenue." + "unknown": "Erreur inattendue" }, "step": { "user": { diff --git a/homeassistant/components/flunearyou/translations/it.json b/homeassistant/components/flunearyou/translations/it.json index 1f46a5e140f..af43ada9596 100644 --- a/homeassistant/components/flunearyou/translations/it.json +++ b/homeassistant/components/flunearyou/translations/it.json @@ -4,7 +4,6 @@ "already_configured": "La posizione \u00e8 gi\u00e0 configurata" }, "error": { - "general_error": "Si \u00e8 verificato un errore sconosciuto.", "unknown": "Errore imprevisto" }, "step": { diff --git a/homeassistant/components/flunearyou/translations/ko.json b/homeassistant/components/flunearyou/translations/ko.json index 5c5e81476ef..68e65d3c349 100644 --- a/homeassistant/components/flunearyou/translations/ko.json +++ b/homeassistant/components/flunearyou/translations/ko.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\uc88c\ud45c\uac12\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, - "error": { - "general_error": "\uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/flunearyou/translations/lb.json b/homeassistant/components/flunearyou/translations/lb.json index d71fc49be1e..457f64f34a7 100644 --- a/homeassistant/components/flunearyou/translations/lb.json +++ b/homeassistant/components/flunearyou/translations/lb.json @@ -1,10 +1,9 @@ { "config": { "abort": { - "already_configured": "D\u00ebs Koordinate si scho registr\u00e9iert" + "already_configured": "Standuert ass scho konfigur\u00e9iert" }, "error": { - "general_error": "Onbekannten Feeler", "unknown": "Onerwaarte Feeler" }, "step": { diff --git a/homeassistant/components/flunearyou/translations/nl.json b/homeassistant/components/flunearyou/translations/nl.json index c3f83fc93bf..c63a59e18e7 100644 --- a/homeassistant/components/flunearyou/translations/nl.json +++ b/homeassistant/components/flunearyou/translations/nl.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Deze co\u00f6rdinaten zijn al geregistreerd." }, - "error": { - "general_error": "Er is een onbekende fout opgetreden." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/flunearyou/translations/no.json b/homeassistant/components/flunearyou/translations/no.json index 94fed823761..b958aea2ab5 100644 --- a/homeassistant/components/flunearyou/translations/no.json +++ b/homeassistant/components/flunearyou/translations/no.json @@ -4,7 +4,6 @@ "already_configured": "Plasseringen er allerede konfigurert" }, "error": { - "general_error": "Det oppstod en ukjent feil.", "unknown": "Uventet feil" }, "step": { @@ -13,7 +12,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/pl.json b/homeassistant/components/flunearyou/translations/pl.json index 47fcf5b5777..b250d220cf3 100644 --- a/homeassistant/components/flunearyou/translations/pl.json +++ b/homeassistant/components/flunearyou/translations/pl.json @@ -4,7 +4,6 @@ "already_configured": "Lokalizacja jest ju\u017c skonfigurowana" }, "error": { - "general_error": "Nieoczekiwany b\u0142\u0105d", "unknown": "Nieoczekiwany b\u0142\u0105d" }, "step": { @@ -14,7 +13,7 @@ "longitude": "D\u0142ugo\u015b\u0107 geograficzna" }, "description": "Monitoruj raporty oparte na u\u017cytkownikach i CDC dla pary wsp\u00f3\u0142rz\u0119dnych.", - "title": "Skonfiguruj Flu Near You" + "title": "Konfiguracja Flu Near You" } } } diff --git a/homeassistant/components/flunearyou/translations/ru.json b/homeassistant/components/flunearyou/translations/ru.json index e7d56ae1323..e4694cf31b9 100644 --- a/homeassistant/components/flunearyou/translations/ru.json +++ b/homeassistant/components/flunearyou/translations/ru.json @@ -4,7 +4,6 @@ "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." }, "error": { - "general_error": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "step": { @@ -13,7 +12,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/sl.json b/homeassistant/components/flunearyou/translations/sl.json index 843794b8a52..667f0e3c0ed 100644 --- a/homeassistant/components/flunearyou/translations/sl.json +++ b/homeassistant/components/flunearyou/translations/sl.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Te koordinate so \u017ee registrirane." }, - "error": { - "general_error": "Pri\u0161lo je do neznane napake." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/flunearyou/translations/sv.json b/homeassistant/components/flunearyou/translations/sv.json index adcf6008c1e..e39e45a3ec0 100644 --- a/homeassistant/components/flunearyou/translations/sv.json +++ b/homeassistant/components/flunearyou/translations/sv.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Dessa koordinater \u00e4r redan registrerade." }, - "error": { - "general_error": "Ett ok\u00e4nt fel intr\u00e4ffade." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/flunearyou/translations/zh-Hant.json b/homeassistant/components/flunearyou/translations/zh-Hant.json index 6b62857244e..f3273349f1f 100644 --- a/homeassistant/components/flunearyou/translations/zh-Hant.json +++ b/homeassistant/components/flunearyou/translations/zh-Hant.json @@ -4,7 +4,6 @@ "already_configured": "\u5ea7\u6a19\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "general_error": "\u767c\u751f\u672a\u77e5\u932f\u8aa4\u3002", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "step": { @@ -13,7 +12,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/forked_daapd/config_flow.py b/homeassistant/components/forked_daapd/config_flow.py index faef33f8334..285f1382644 100644 --- a/homeassistant/components/forked_daapd/config_flow.py +++ b/homeassistant/components/forked_daapd/config_flow.py @@ -31,6 +31,7 @@ DATA_SCHEMA_DICT = { } TEST_CONNECTION_ERROR_DICT = { + "forbidden": "forbidden", "ok": "ok", "websocket_not_enabled": "websocket_not_enabled", "wrong_host_or_port": "wrong_host_or_port", diff --git a/homeassistant/components/forked_daapd/manifest.json b/homeassistant/components/forked_daapd/manifest.json index 2304e4196a7..15f043dbbfe 100644 --- a/homeassistant/components/forked_daapd/manifest.json +++ b/homeassistant/components/forked_daapd/manifest.json @@ -3,7 +3,7 @@ "name": "forked-daapd", "documentation": "https://www.home-assistant.io/integrations/forked-daapd", "codeowners": ["@uvjustin"], - "requirements": ["pyforked-daapd==0.1.10", "pylibrespot-java==0.1.0"], + "requirements": ["pyforked-daapd==0.1.11", "pylibrespot-java==0.1.0"], "config_flow": true, "zeroconf": ["_daap._tcp.local."] } diff --git a/homeassistant/components/forked_daapd/strings.json b/homeassistant/components/forked_daapd/strings.json index e3be0b6795d..d0523073699 100644 --- a/homeassistant/components/forked_daapd/strings.json +++ b/homeassistant/components/forked_daapd/strings.json @@ -13,6 +13,7 @@ } }, "error": { + "forbidden": "Unable to connect. Please check your forked-daapd network permissions.", "websocket_not_enabled": "forked-daapd server websocket not enabled.", "wrong_host_or_port": "Unable to connect. Please check host and port.", "wrong_password": "Incorrect password.", diff --git a/homeassistant/components/forked_daapd/translations/ca.json b/homeassistant/components/forked_daapd/translations/ca.json index 1b3792eeb1b..fb778199efa 100644 --- a/homeassistant/components/forked_daapd/translations/ca.json +++ b/homeassistant/components/forked_daapd/translations/ca.json @@ -5,6 +5,7 @@ "not_forked_daapd": "El dispositiu no \u00e9s un servidor de forked-daapd." }, "error": { + "forbidden": "No s'ha pogut connectar. Comprova els permisos de xarxa de forked-daapd.", "unknown_error": "Error inesperat", "websocket_not_enabled": "El websocket de forked-daapd no est\u00e0 activat.", "wrong_host_or_port": "No s'ha pogut connectar, verifica l'amfitri\u00f3 i el port.", diff --git a/homeassistant/components/forked_daapd/translations/cs.json b/homeassistant/components/forked_daapd/translations/cs.json index 602e5859ca1..55fa46e68ca 100644 --- a/homeassistant/components/forked_daapd/translations/cs.json +++ b/homeassistant/components/forked_daapd/translations/cs.json @@ -5,17 +5,34 @@ "not_forked_daapd": "Za\u0159\u00edzen\u00ed nen\u00ed server forked-daapd." }, "error": { + "forbidden": "Nelze se p\u0159ipojit. Zkontrolujte pros\u00edm opr\u00e1vn\u011bn\u00ed s\u00edt\u011b forked-daapd.", "unknown_error": "Neo\u010dek\u00e1van\u00e1 chyba", + "websocket_not_enabled": "Websocket serveru forked-daapd nen\u00ed povolen.", + "wrong_host_or_port": "Nelze se p\u0159ipojit. Zkontrolujte hostitele a port.", "wrong_password": "Nespr\u00e1vn\u00e9 heslo.", "wrong_server_type": "Integrace forked-daapd vy\u017eaduje server forked-daapd s verz\u00ed >= 27.0." }, + "flow_title": "Server forked-daapd: {name} ({host})", "step": { "user": { "data": { "host": "Hostitel", "name": "Zobrazovan\u00e9 jm\u00e9no", - "password": "Heslo API (ponechte pr\u00e1zdn\u00e9, pokud \u017e\u00e1dn\u00e9 heslo nen\u00ed)" - } + "password": "Heslo API (ponechte pr\u00e1zdn\u00e9, pokud \u017e\u00e1dn\u00e9 heslo nen\u00ed)", + "port": "Port API" + }, + "title": "Nastaven\u00ed za\u0159\u00edzen\u00ed forked-daapd" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "max_playlists": "Maxim\u00e1ln\u00ed po\u010det seznam\u016f skladeb pou\u017eit\u00fdch jako zdroje" + }, + "description": "Nastavte r\u016fzn\u00e9 mo\u017enosti integrace forked-daapd.", + "title": "Nastavte mo\u017enosti forked-daapd" } } } diff --git a/homeassistant/components/forked_daapd/translations/en.json b/homeassistant/components/forked_daapd/translations/en.json index 397836809da..4a5426e6f83 100644 --- a/homeassistant/components/forked_daapd/translations/en.json +++ b/homeassistant/components/forked_daapd/translations/en.json @@ -5,6 +5,7 @@ "not_forked_daapd": "Device is not a forked-daapd server." }, "error": { + "forbidden": "Unable to connect. Please check your forked-daapd network permissions.", "unknown_error": "Unexpected error", "websocket_not_enabled": "forked-daapd server websocket not enabled.", "wrong_host_or_port": "Unable to connect. Please check host and port.", diff --git a/homeassistant/components/forked_daapd/translations/es.json b/homeassistant/components/forked_daapd/translations/es.json index 39215f2667d..7ec30e72b1a 100644 --- a/homeassistant/components/forked_daapd/translations/es.json +++ b/homeassistant/components/forked_daapd/translations/es.json @@ -5,6 +5,7 @@ "not_forked_daapd": "El dispositivo no es un servidor forked-daapd." }, "error": { + "forbidden": "No se puede conectar. Compruebe los permisos de red de bifurcaci\u00f3n.", "unknown_error": "Error desconocido.", "websocket_not_enabled": "Websocket no activado en servidor forked-daapd.", "wrong_host_or_port": "No se ha podido conectar. Por favor comprueba host y puerto.", diff --git a/homeassistant/components/forked_daapd/translations/et.json b/homeassistant/components/forked_daapd/translations/et.json index 3e3952e4f67..8e2096e821c 100644 --- a/homeassistant/components/forked_daapd/translations/et.json +++ b/homeassistant/components/forked_daapd/translations/et.json @@ -1,17 +1,41 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud", + "not_forked_daapd": "Seade ei ole forked-daapd server." }, "error": { + "forbidden": "Ei saa \u00fchendust. Kontrolli oma forked-daapd sidumise v\u00f5rgu\u00f5igusi.", "unknown_error": "Tundmatu viga", - "wrong_password": "Vale salas\u00f5na." + "websocket_not_enabled": "forked- daapd serveri veebisoklit pole lubatud.", + "wrong_host_or_port": "\u00dchendust ei saa luua. Palun kontrolli hosti ja porti.", + "wrong_password": "Vale salas\u00f5na.", + "wrong_server_type": "Forked-daapd sidumine n\u00f5uab forked-daapd serveri versioon >= 27.0." }, + "flow_title": "forked-daapd server: {name} ( {host} )", "step": { "user": { "data": { - "host": "" - } + "host": "", + "name": "S\u00f5bralik nimi", + "password": "API salas\u00f5na (j\u00e4ta t\u00fchjaks kui salas\u00f5na puudub)", + "port": "" + }, + "title": "Seadista forked-daapd seade" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "librespot_java_port": "Librespot-java pipe juhtimise port (kui seda kasutatakse)", + "max_playlists": "Allikatena kasutatud esitusloendite maksimaalne arv", + "tts_pause_time": "Paus sekundites enne ja p\u00e4rast TTS teavitust", + "tts_volume": "TTS helitugevus (ujukoma vahemikus [0-1])" + }, + "description": "M\u00e4\u00e4rake forked-daapd-i sidumise erinevad valikud.", + "title": "Forked- daapd valikute seadistamine" } } } diff --git a/homeassistant/components/forked_daapd/translations/fr.json b/homeassistant/components/forked_daapd/translations/fr.json index 03214f960ac..2e20c75d33f 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/forked_daapd/translations/it.json b/homeassistant/components/forked_daapd/translations/it.json index 3f400e0edc5..d4303f6dba6 100644 --- a/homeassistant/components/forked_daapd/translations/it.json +++ b/homeassistant/components/forked_daapd/translations/it.json @@ -5,6 +5,7 @@ "not_forked_daapd": "Il dispositivo non \u00e8 un server forked-daapd." }, "error": { + "forbidden": "Impossibile connettersi. Si prega di controllare i permessi di rete forked-daapd.", "unknown_error": "Errore imprevisto", "websocket_not_enabled": "websocket del server forked-daapd non abilitato.", "wrong_host_or_port": "Impossibile connettersi. Si prega di controllare host e porta.", diff --git a/homeassistant/components/forked_daapd/translations/lb.json b/homeassistant/components/forked_daapd/translations/lb.json index f5ee557acf9..59a27e7600e 100644 --- a/homeassistant/components/forked_daapd/translations/lb.json +++ b/homeassistant/components/forked_daapd/translations/lb.json @@ -5,6 +5,7 @@ "not_forked_daapd": "Apparat ass kee forked-daapd server." }, "error": { + "forbidden": "Feeler beim verbannen, iwwerpr\u00e9if w.e.g Netzwierk Autorisatioun vun dengem forked-daapd.", "unknown_error": "Onerwaarte Feeler", "websocket_not_enabled": "forked-daapd server websocket net aktiv.", "wrong_host_or_port": "Feeler beim verbannen, iwwerpr\u00e9if w.e.g d'Adresse a Port.", diff --git a/homeassistant/components/forked_daapd/translations/no.json b/homeassistant/components/forked_daapd/translations/no.json index 4b3a0dfd87d..da260c9a019 100644 --- a/homeassistant/components/forked_daapd/translations/no.json +++ b/homeassistant/components/forked_daapd/translations/no.json @@ -5,6 +5,7 @@ "not_forked_daapd": "Enheten er ikke en forked-daapd-server." }, "error": { + "forbidden": "Kan ikke koble til, vennligst sjekk dine forked-daapd nettverkstillatelser", "unknown_error": "Uventet feil", "websocket_not_enabled": "websocket for forked-daapd server ikke aktivert.", "wrong_host_or_port": "Kan ikke koble til. Vennligst sjekk vert og port.", diff --git a/homeassistant/components/forked_daapd/translations/pl.json b/homeassistant/components/forked_daapd/translations/pl.json index 3b28e79803c..781dd9fca6b 100644 --- a/homeassistant/components/forked_daapd/translations/pl.json +++ b/homeassistant/components/forked_daapd/translations/pl.json @@ -5,13 +5,14 @@ "not_forked_daapd": "Urz\u0105dzenie nie jest serwerem forked-daapd" }, "error": { + "forbidden": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia. Sprawd\u017a uprawnienia sieciowe forked-daapd.", "unknown_error": "Nieoczekiwany b\u0142\u0105d", "websocket_not_enabled": "Websocket serwera forked-daapd nie jest w\u0142\u0105czony", "wrong_host_or_port": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia. Sprawd\u017a adres hosta i port.", "wrong_password": "Nieprawid\u0142owe has\u0142o", "wrong_server_type": "Integracja forked-daapd wymaga serwera forked-daapd w wersji >= 27.0" }, - "flow_title": "Serwer forked-daapd: {name} ( {host})", + "flow_title": "Serwer forked-daapd: {name} ({host})", "step": { "user": { "data": { @@ -20,7 +21,7 @@ "password": "Has\u0142o API (pozostaw puste, je\u015bli nie ma has\u0142a)", "port": "Port API" }, - "title": "Skonfiguruj urz\u0105dzenie forked-daapd" + "title": "Konfiguracja urz\u0105dzenia forked-daapd" } } }, diff --git a/homeassistant/components/forked_daapd/translations/ru.json b/homeassistant/components/forked_daapd/translations/ru.json index d5111b8f286..58d574b4054 100644 --- a/homeassistant/components/forked_daapd/translations/ru.json +++ b/homeassistant/components/forked_daapd/translations/ru.json @@ -5,6 +5,7 @@ "not_forked_daapd": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440 forked-daapd." }, "error": { + "forbidden": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f forked-daapd.", "unknown_error": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", "websocket_not_enabled": "\u0412\u0435\u0431-\u0441\u043e\u043a\u0435\u0442 forked-daapd \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0435\u043d.", "wrong_host_or_port": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0430\u0434\u0440\u0435\u0441 \u0445\u043e\u0441\u0442\u0430.", diff --git a/homeassistant/components/forked_daapd/translations/zh-Hant.json b/homeassistant/components/forked_daapd/translations/zh-Hant.json index 2dcced078ed..88e8628848c 100644 --- a/homeassistant/components/forked_daapd/translations/zh-Hant.json +++ b/homeassistant/components/forked_daapd/translations/zh-Hant.json @@ -5,6 +5,7 @@ "not_forked_daapd": "\u8a2d\u5099\u4e26\u975e forked-daapd \u4f3a\u670d\u5668\u3002" }, "error": { + "forbidden": "\u7121\u6cd5\u9023\u7dda\uff0c\u8acb\u78ba\u8a8d forked-daapd \u7db2\u8def\u6b0a\u9650\u3002", "unknown_error": "\u672a\u9810\u671f\u932f\u8aa4", "websocket_not_enabled": "forked-daapd \u4f3a\u670d\u5668 websocket \u672a\u958b\u555f\u3002", "wrong_host_or_port": "\u7121\u6cd5\u9023\u7dda\uff0c\u8acb\u78ba\u8a8d\u4e3b\u6a5f\u8207\u901a\u8a0a\u57e0\u3002", diff --git a/homeassistant/components/freebox/translations/cs.json b/homeassistant/components/freebox/translations/cs.json index 98d4258ee02..4c11d4b442b 100644 --- a/homeassistant/components/freebox/translations/cs.json +++ b/homeassistant/components/freebox/translations/cs.json @@ -10,6 +10,7 @@ }, "step": { "link": { + "description": "Klikn\u011bte na \"Odeslat\" a pot\u00e9 stiskn\u011bte \u0161ipku doprava na routeru - t\u00edm zaregistrujte Freebox u Home Assistant.\n\n![Um\u00edst\u011bn\u00ed tla\u010d\u00edtka na routeru](/static/images/config_freebox.png)", "title": "Propojte router Freebox" }, "user": { diff --git a/homeassistant/components/freebox/translations/et.json b/homeassistant/components/freebox/translations/et.json index aac3f2f0155..4f0239350e3 100644 --- a/homeassistant/components/freebox/translations/et.json +++ b/homeassistant/components/freebox/translations/et.json @@ -9,6 +9,10 @@ "unknown": "Tundmatu viga" }, "step": { + "link": { + "description": "Kl\u00f5psa nuppu \"Esita\", seej\u00e4rel puuduta ruuteri paremat noolt, et registreerida Freebox Home Assistanti abil. \n\n ! [Nupu asukoht ruuteril] (/ static / images / config_freebox.png)", + "title": "Lingi Freebox ruuter" + }, "user": { "data": { "host": "", diff --git a/homeassistant/components/freebox/translations/lb.json b/homeassistant/components/freebox/translations/lb.json index e7c1b1148dc..e2fdaf18352 100644 --- a/homeassistant/components/freebox/translations/lb.json +++ b/homeassistant/components/freebox/translations/lb.json @@ -4,9 +4,9 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "register_failed": "Feeler beim registr\u00e9ieren, prob\u00e9ier w.e.g. nach emol", - "unknown": "Onbekannte Feeler: prob\u00e9iertsp\u00e9ider nach emol" + "unknown": "Onerwaarte Feeler" }, "step": { "link": { diff --git a/homeassistant/components/fritz/device_tracker.py b/homeassistant/components/fritz/device_tracker.py index 6eb23d4b85e..4da566376a6 100644 --- a/homeassistant/components/fritz/device_tracker.py +++ b/homeassistant/components/fritz/device_tracker.py @@ -15,13 +15,14 @@ import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) -CONF_DEFAULT_IP = "169.254.1.1" # This IP is valid for all FRITZ!Box routers. +DEFAULT_HOST = "169.254.1.1" # This IP is valid for all FRITZ!Box routers. +DEFAULT_USERNAME = "admin" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { - vol.Optional(CONF_HOST, default=CONF_DEFAULT_IP): cv.string, - vol.Optional(CONF_PASSWORD, default="admin"): cv.string, - vol.Optional(CONF_USERNAME, default=""): cv.string, + vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, + vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string, + vol.Optional(CONF_PASSWORD): cv.string, } ) @@ -40,7 +41,7 @@ class FritzBoxScanner(DeviceScanner): self.last_results = [] self.host = config[CONF_HOST] self.username = config[CONF_USERNAME] - self.password = config[CONF_PASSWORD] + self.password = config.get(CONF_PASSWORD) self.success_init = True # Establish a connection to the FRITZ!Box. diff --git a/homeassistant/components/fritz/manifest.json b/homeassistant/components/fritz/manifest.json index 3723bd7885a..a1924296f75 100644 --- a/homeassistant/components/fritz/manifest.json +++ b/homeassistant/components/fritz/manifest.json @@ -2,6 +2,6 @@ "domain": "fritz", "name": "AVM FRITZ!Box", "documentation": "https://www.home-assistant.io/integrations/fritz", - "requirements": ["fritzconnection==1.2.0"], + "requirements": ["fritzconnection==1.3.4"], "codeowners": [] } diff --git a/homeassistant/components/fritzbox/manifest.json b/homeassistant/components/fritzbox/manifest.json index 1905311a9f6..6b1bbdc4af5 100644 --- a/homeassistant/components/fritzbox/manifest.json +++ b/homeassistant/components/fritzbox/manifest.json @@ -1,6 +1,6 @@ { "domain": "fritzbox", - "name": "AVM FRITZ!Box", + "name": "AVM FRITZ!SmartHome", "documentation": "https://www.home-assistant.io/integrations/fritzbox", "requirements": ["pyfritzhome==0.4.2"], "ssdp": [ @@ -8,7 +8,6 @@ "st": "urn:schemas-upnp-org:device:fritzbox:1" } ], - "dependencies": [], "codeowners": [], "config_flow": true } diff --git a/homeassistant/components/fritzbox/translations/ca.json b/homeassistant/components/fritzbox/translations/ca.json index 335c25aa602..8b0122dbe18 100644 --- a/homeassistant/components/fritzbox/translations/ca.json +++ b/homeassistant/components/fritzbox/translations/ca.json @@ -4,11 +4,9 @@ "already_configured": "El dispositiu ja est\u00e0 configurat", "already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs", "no_devices_found": "No s'han trobat dispositius a la xarxa", - "not_found": "No s'ha trobat cap AVM FRITZ!Box compatible a la xarxa.", "not_supported": "Connectat a AVM FRITZ!Box per\u00f2 no es poden controlar dispositius Smart Home." }, "error": { - "auth_failed": "Nom d'usuari i/o contrasenya incorrectes.", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "flow_title": "AVM FRITZ!Box: {name}", diff --git a/homeassistant/components/fritzbox/translations/cs.json b/homeassistant/components/fritzbox/translations/cs.json index b2fab27422f..67ff5db7f99 100644 --- a/homeassistant/components/fritzbox/translations/cs.json +++ b/homeassistant/components/fritzbox/translations/cs.json @@ -3,11 +3,9 @@ "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", - "no_devices_found": "V s\u00edti nebyla nalezena \u017e\u00e1dn\u00e1 za\u0159\u00edzen\u00ed", - "not_found": "V s\u00edti nebyl nalezen \u017e\u00e1dn\u00fd podporovan\u00fd AVM FRITZ!Box." + "no_devices_found": "V s\u00edti nebyla nalezena \u017e\u00e1dn\u00e1 za\u0159\u00edzen\u00ed" }, "error": { - "auth_failed": "U\u017eivatelsk\u00e9 jm\u00e9no nebo heslo je nespr\u00e1vn\u00e9.", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "flow_title": "AVM FRITZ!Box: {name}", diff --git a/homeassistant/components/fritzbox/translations/de.json b/homeassistant/components/fritzbox/translations/de.json index ac2f4b2d401..19ca2e80903 100644 --- a/homeassistant/components/fritzbox/translations/de.json +++ b/homeassistant/components/fritzbox/translations/de.json @@ -3,12 +3,8 @@ "abort": { "already_configured": "Diese AVM FRITZ! Box ist bereits konfiguriert.", "already_in_progress": "Die Konfiguration der AVM FRITZ! Box ist bereits in Bearbeitung.", - "not_found": "Keine unterst\u00fctzte AVM FRITZ! Box im Netzwerk gefunden.", "not_supported": "Verbunden mit AVM FRITZ! Box, kann jedoch keine Smart Home-Ger\u00e4te steuern." }, - "error": { - "auth_failed": "Benutzername und/oder Passwort sind falsch." - }, "flow_title": "AVM FRITZ! Box: {name}", "step": { "confirm": { diff --git a/homeassistant/components/fritzbox/translations/en.json b/homeassistant/components/fritzbox/translations/en.json index 95a820c8686..1f22bc30252 100644 --- a/homeassistant/components/fritzbox/translations/en.json +++ b/homeassistant/components/fritzbox/translations/en.json @@ -4,11 +4,9 @@ "already_configured": "Device is already configured", "already_in_progress": "Configuration flow is already in progress", "no_devices_found": "No devices found on the network", - "not_found": "No supported AVM FRITZ!Box found on the network.", "not_supported": "Connected to AVM FRITZ!Box but it's unable to control Smart Home devices." }, "error": { - "auth_failed": "Username and/or password are incorrect.", "invalid_auth": "Invalid authentication" }, "flow_title": "AVM FRITZ!Box: {name}", diff --git a/homeassistant/components/fritzbox/translations/es-419.json b/homeassistant/components/fritzbox/translations/es-419.json index 9cc1a40daa3..f66a3dc0dd0 100644 --- a/homeassistant/components/fritzbox/translations/es-419.json +++ b/homeassistant/components/fritzbox/translations/es-419.json @@ -3,12 +3,8 @@ "abort": { "already_configured": "Este AVM FRITZ!Box ya est\u00e1 configurado.", "already_in_progress": "La configuraci\u00f3n de AVM FRITZ!Box ya est\u00e1 en progreso.", - "not_found": "No se encontr\u00f3 ning\u00fan AVM FRITZ!Box compatible en la red.", "not_supported": "Conectado a AVM FRITZ!Box pero no puede controlar dispositivos Smart Home." }, - "error": { - "auth_failed": "El nombre de usuario y/o la contrase\u00f1a son incorrectos." - }, "flow_title": "AVM FRITZ!Box: {name}", "step": { "confirm": { diff --git a/homeassistant/components/fritzbox/translations/es.json b/homeassistant/components/fritzbox/translations/es.json index 2009f16e5fc..5a9544df4e5 100644 --- a/homeassistant/components/fritzbox/translations/es.json +++ b/homeassistant/components/fritzbox/translations/es.json @@ -4,11 +4,9 @@ "already_configured": "Este AVM FRITZ!Box ya est\u00e1 configurado.", "already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en proceso", "no_devices_found": "No se encontraron dispositivos en la red", - "not_found": "No se encontr\u00f3 ning\u00fan AVM FRITZ!Box compatible en la red.", "not_supported": "Conectado a AVM FRITZ!Box pero no es capaz de controlar dispositivos Smart Home." }, "error": { - "auth_failed": "Usuario y/o contrase\u00f1a incorrectos.", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "flow_title": "AVM FRITZ!Box: {name}", diff --git a/homeassistant/components/fritzbox/translations/et.json b/homeassistant/components/fritzbox/translations/et.json index 0fe0c791d75..702488bce0c 100644 --- a/homeassistant/components/fritzbox/translations/et.json +++ b/homeassistant/components/fritzbox/translations/et.json @@ -3,12 +3,13 @@ "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", "already_in_progress": "Seadistamine on juba k\u00e4imas", - "no_devices_found": "V\u00f5rgust ei leitud seadmeid" + "no_devices_found": "V\u00f5rgust ei leitud seadmeid", + "not_supported": "\u00dchendatud AVM FRITZ!Boxiga! kuid see ei saa juhtida Smart Home seadmeid." }, "error": { - "auth_failed": "Kasutajanimi v\u00f5i salas\u00f5na on vale.", "invalid_auth": "Tuvastamise viga" }, + "flow_title": "", "step": { "confirm": { "data": { @@ -22,7 +23,8 @@ "host": "", "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "description": "Sisesta oma AVM FRITZ! Boxi teave." } } } diff --git a/homeassistant/components/fritzbox/translations/fr.json b/homeassistant/components/fritzbox/translations/fr.json index 3bd90697596..e7a8acaa762 100644 --- a/homeassistant/components/fritzbox/translations/fr.json +++ b/homeassistant/components/fritzbox/translations/fr.json @@ -3,11 +3,11 @@ "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.", - "not_found": "Aucune AVM FRITZ!Box support\u00e9e trouv\u00e9e sur le r\u00e9seau.", + "no_devices_found": "Aucun appareil trouv\u00e9 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." + "invalid_auth": "Authentification invalide" }, "flow_title": "AVM FRITZ!Box : {name}", "step": { diff --git a/homeassistant/components/fritzbox/translations/hi.json b/homeassistant/components/fritzbox/translations/hi.json deleted file mode 100644 index f95cac200e9..00000000000 --- a/homeassistant/components/fritzbox/translations/hi.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "abort": { - "not_found": "\u0915\u094b\u0908 \u0938\u092e\u0930\u094d\u0925\u093f\u0924 AVM FRITZ! \u092c\u0949\u0915\u094d\u0938 \u0928\u0947\u091f\u0935\u0930\u094d\u0915 \u092a\u0930 \u0928\u0939\u0940\u0902 \u092e\u093f\u0932\u093e\u0964" - } - } -} \ No newline at end of file diff --git a/homeassistant/components/fritzbox/translations/it.json b/homeassistant/components/fritzbox/translations/it.json index d3c64a08307..ab44ae13863 100644 --- a/homeassistant/components/fritzbox/translations/it.json +++ b/homeassistant/components/fritzbox/translations/it.json @@ -4,11 +4,9 @@ "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso", "no_devices_found": "Nessun dispositivo trovato sulla rete", - "not_found": "Nessun AVM FRITZ!Box supportato trovato sulla rete.", "not_supported": "Collegato a AVM FRITZ!Box ma non \u00e8 in grado di controllare i dispositivi Smart Home." }, "error": { - "auth_failed": "Nome utente e/o password non sono corretti.", "invalid_auth": "Autenticazione non valida" }, "flow_title": "AVM FRITZ!Box: {name}", diff --git a/homeassistant/components/fritzbox/translations/ko.json b/homeassistant/components/fritzbox/translations/ko.json index 0d27f8e0606..b04b6905284 100644 --- a/homeassistant/components/fritzbox/translations/ko.json +++ b/homeassistant/components/fritzbox/translations/ko.json @@ -3,12 +3,8 @@ "abort": { "already_configured": "\uc774 AVM FRITZ!Box \ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "already_in_progress": "AVM FRITZ!Box \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4.", - "not_found": "\uc9c0\uc6d0\ub418\ub294 AVM FRITZ!Box \uac00 \ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ubc1c\uacac\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4.", "not_supported": "AVM FRITZ!Box \uc5d0 \uc5f0\uacb0\ub418\uc5c8\uc9c0\ub9cc \uc2a4\ub9c8\ud2b8 \ud648 \uae30\uae30\ub97c \uc81c\uc5b4\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." }, - "error": { - "auth_failed": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ub610\ub294 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "flow_title": "AVM FRITZ!Box: {name}", "step": { "confirm": { diff --git a/homeassistant/components/fritzbox/translations/lb.json b/homeassistant/components/fritzbox/translations/lb.json index f60c58e8888..de6f75f01d5 100644 --- a/homeassistant/components/fritzbox/translations/lb.json +++ b/homeassistant/components/fritzbox/translations/lb.json @@ -1,13 +1,13 @@ { "config": { "abort": { - "already_configured": "D\u00ebs AVM FRITZ!Box ass scho konfigur\u00e9iert", + "already_configured": "Apparat ass scho konfigur\u00e9iert", "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaang.", - "not_found": "Keng \u00ebnnerst\u00ebtzte AVM FRITZ!Box am Netzwierk fonnt.", + "no_devices_found": "Keng Apparater am Netzwierk fonnt", "not_supported": "Mat der AVM FRITZ!Box verbonnen mee sie kann keng Smart Home Apparater kontroll\u00e9ieren." }, "error": { - "auth_failed": "Benotzernumm an/oder Passwuert inkorrekt" + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "flow_title": "AVM FRITZ!Box: {name}", "step": { diff --git a/homeassistant/components/fritzbox/translations/nl.json b/homeassistant/components/fritzbox/translations/nl.json index ea8b715b7ea..b72374547bc 100644 --- a/homeassistant/components/fritzbox/translations/nl.json +++ b/homeassistant/components/fritzbox/translations/nl.json @@ -3,12 +3,8 @@ "abort": { "already_configured": "Deze AVM FRITZ!Box is al geconfigureerd.", "already_in_progress": "AVM FRITZ!Box configuratie is al bezig.", - "not_found": "Geen ondersteunde AVM FRITZ!Box gevonden op het netwerk.", "not_supported": "Verbonden met AVM FRITZ! Box, maar het kan geen Smart Home-apparaten bedienen." }, - "error": { - "auth_failed": "Ongeldige gebruikersnaam of wachtwoord" - }, "flow_title": "AVM FRITZ!Box: {name}", "step": { "confirm": { diff --git a/homeassistant/components/fritzbox/translations/no.json b/homeassistant/components/fritzbox/translations/no.json index a4436896d94..024e25741a7 100644 --- a/homeassistant/components/fritzbox/translations/no.json +++ b/homeassistant/components/fritzbox/translations/no.json @@ -4,11 +4,9 @@ "already_configured": "Enheten er allerede konfigurert", "already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede", "no_devices_found": "Ingen enheter funnet p\u00e5 nettverket", - "not_found": "Ingen st\u00f8ttet AVM FRITZ!Box funnet p\u00e5 nettverket.", "not_supported": "Tilkoblet AVM FRITZ! Box, men den klarer ikke \u00e5 kontrollere Smart Home-enheter." }, "error": { - "auth_failed": "Brukernavn og/eller passord er feil.", "invalid_auth": "Ugyldig godkjenning" }, "flow_title": "", diff --git a/homeassistant/components/fritzbox/translations/pl.json b/homeassistant/components/fritzbox/translations/pl.json index 359c792bfe4..fc162310189 100644 --- a/homeassistant/components/fritzbox/translations/pl.json +++ b/homeassistant/components/fritzbox/translations/pl.json @@ -4,11 +4,9 @@ "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "already_in_progress": "Konfiguracja jest ju\u017c w toku", "no_devices_found": "Nie znaleziono urz\u0105dze\u0144 w sieci", - "not_found": "W sieci nie znaleziono obs\u0142ugiwanego urz\u0105dzenia AVM FRITZ!Box", - "not_supported": "Po\u0142\u0105czony z AVM FRITZ! Box, ale nie jest w stanie kontrolowa\u0107 urz\u0105dze\u0144 Smart Home" + "not_supported": "Po\u0142\u0105czony z AVM FRITZ!Box, ale nie jest w stanie kontrolowa\u0107 urz\u0105dze\u0144 Smart Home" }, "error": { - "auth_failed": "Nazwa u\u017cytkownika i/lub has\u0142o s\u0105 nieprawid\u0142owe", "invalid_auth": "Niepoprawne uwierzytelnienie" }, "flow_title": "AVM FRITZ!Box: {name}", diff --git a/homeassistant/components/fritzbox/translations/pt-BR.json b/homeassistant/components/fritzbox/translations/pt-BR.json index befa6942be9..9685e93f927 100644 --- a/homeassistant/components/fritzbox/translations/pt-BR.json +++ b/homeassistant/components/fritzbox/translations/pt-BR.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "auth_failed": "Nome de usu\u00e1rio e/ou senha est\u00e3o incorretos." - }, "step": { "confirm": { "data": { diff --git a/homeassistant/components/fritzbox/translations/pt.json b/homeassistant/components/fritzbox/translations/pt.json index 4743c909f2e..a5b5cd26dc2 100644 --- a/homeassistant/components/fritzbox/translations/pt.json +++ b/homeassistant/components/fritzbox/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "auth_failed": "Nome de utilizador ou palavra passe incorretos" - }, "step": { "confirm": { "data": { diff --git a/homeassistant/components/fritzbox/translations/ru.json b/homeassistant/components/fritzbox/translations/ru.json index 0dbaf505571..322f677c2af 100644 --- a/homeassistant/components/fritzbox/translations/ru.json +++ b/homeassistant/components/fritzbox/translations/ru.json @@ -4,11 +4,9 @@ "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.", "no_devices_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u0441\u0435\u0442\u0438.", - "not_found": "\u0412 \u0441\u0435\u0442\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432.", "not_supported": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a AVM FRITZ! Box \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e, \u043d\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 Smart Home \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e." }, "error": { - "auth_failed": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "flow_title": "AVM FRITZ!Box: {name}", diff --git a/homeassistant/components/fritzbox/translations/sl.json b/homeassistant/components/fritzbox/translations/sl.json index cd85c58af24..0077e286859 100644 --- a/homeassistant/components/fritzbox/translations/sl.json +++ b/homeassistant/components/fritzbox/translations/sl.json @@ -3,12 +3,8 @@ "abort": { "already_configured": "Ta AVM FRITZ! Box je \u017ee konfiguriran.", "already_in_progress": "Konfiguracija AVM FRITZ! Box je \u017ee v teku.", - "not_found": "V omre\u017eju ni bilo najdenih nobenih podprtih naprav AVM Fritz!Box.", "not_supported": "Povezani z AVM FRITZ! Box, vendar ne morete upravljati pametnih naprav." }, - "error": { - "auth_failed": "Uporabni\u0161ko ime in/ali geslo sta napa\u010dna." - }, "flow_title": "AVM FRITZ!Box: {name}", "step": { "confirm": { diff --git a/homeassistant/components/fritzbox/translations/sv.json b/homeassistant/components/fritzbox/translations/sv.json index 1ed4e4fc3d8..2d5586b6bc6 100644 --- a/homeassistant/components/fritzbox/translations/sv.json +++ b/homeassistant/components/fritzbox/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "auth_failed": "Anv\u00e4ndarnamn och/eller l\u00f6senord \u00e4r fel." - }, "step": { "confirm": { "data": { diff --git a/homeassistant/components/fritzbox/translations/zh-Hans.json b/homeassistant/components/fritzbox/translations/zh-Hans.json index 183c748b2d2..cbe36c66e71 100644 --- a/homeassistant/components/fritzbox/translations/zh-Hans.json +++ b/homeassistant/components/fritzbox/translations/zh-Hans.json @@ -1,7 +1,7 @@ { "config": { "error": { - "auth_failed": "\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef" + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" }, "step": { "confirm": { diff --git a/homeassistant/components/fritzbox/translations/zh-Hant.json b/homeassistant/components/fritzbox/translations/zh-Hant.json index f1960cee54d..b09eac77619 100644 --- a/homeassistant/components/fritzbox/translations/zh-Hant.json +++ b/homeassistant/components/fritzbox/translations/zh-Hant.json @@ -4,11 +4,9 @@ "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d", "no_devices_found": "\u7db2\u8def\u4e0a\u627e\u4e0d\u5230\u8a2d\u5099", - "not_found": "\u5728\u7db2\u8def\u4e0a\u627e\u4e0d\u5230\u652f\u63f4\u7684 AVM FRITZ!Box\u3002", "not_supported": "\u5df2\u9023\u7dda\u81f3 AVM FRITZ!Box \u4f46\u7121\u6cd5\u63a7\u5236\u667a\u80fd\u5bb6\u5ead\u8a2d\u5099\u3002" }, "error": { - "auth_failed": "\u4f7f\u7528\u8005\u53ca/\u6216\u5bc6\u78bc\u932f\u8aa4\u3002", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "flow_title": "AVM FRITZ!Box\uff1a{name}", diff --git a/homeassistant/components/fritzbox_callmonitor/manifest.json b/homeassistant/components/fritzbox_callmonitor/manifest.json index b5fa26c096b..e06d3b881f7 100644 --- a/homeassistant/components/fritzbox_callmonitor/manifest.json +++ b/homeassistant/components/fritzbox_callmonitor/manifest.json @@ -2,6 +2,6 @@ "domain": "fritzbox_callmonitor", "name": "AVM FRITZ!Box Call Monitor", "documentation": "https://www.home-assistant.io/integrations/fritzbox_callmonitor", - "requirements": ["fritzconnection==1.2.0"], + "requirements": ["fritzconnection==1.3.4"], "codeowners": [] } diff --git a/homeassistant/components/fritzbox_callmonitor/sensor.py b/homeassistant/components/fritzbox_callmonitor/sensor.py index 40791458505..2656e07c3a5 100644 --- a/homeassistant/components/fritzbox_callmonitor/sensor.py +++ b/homeassistant/components/fritzbox_callmonitor/sensor.py @@ -28,8 +28,10 @@ CONF_PHONEBOOK = "phonebook" CONF_PREFIXES = "prefixes" DEFAULT_HOST = "169.254.1.1" # IP valid for all Fritz!Box routers +DEFAULT_USERNAME = "admin" DEFAULT_NAME = "Phone" DEFAULT_PORT = 1012 +DEFAULT_PHONEBOOK = 0 INTERVAL_RECONNECT = 60 @@ -48,9 +50,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, - vol.Optional(CONF_PASSWORD, default="admin"): cv.string, - vol.Optional(CONF_USERNAME, default=""): cv.string, - vol.Optional(CONF_PHONEBOOK, default=0): cv.positive_int, + vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string, + vol.Optional(CONF_PASSWORD): cv.string, + vol.Optional(CONF_PHONEBOOK, default=DEFAULT_PHONEBOOK): cv.positive_int, vol.Optional(CONF_PREFIXES, default=[]): vol.All(cv.ensure_list, [cv.string]), } ) @@ -58,19 +60,19 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Fritz!Box call monitor sensor platform.""" - name = config.get(CONF_NAME) - host = config.get(CONF_HOST) + name = config[CONF_NAME] + host = config[CONF_HOST] # Try to resolve a hostname; if it is already an IP, it will be returned as-is try: host = socket.gethostbyname(host) except OSError: _LOGGER.error("Could not resolve hostname %s", host) return - port = config.get(CONF_PORT) - username = config.get(CONF_USERNAME) + port = config[CONF_PORT] + username = config[CONF_USERNAME] password = config.get(CONF_PASSWORD) - phonebook_id = config.get(CONF_PHONEBOOK) - prefixes = config.get(CONF_PREFIXES) + phonebook_id = config[CONF_PHONEBOOK] + prefixes = config[CONF_PREFIXES] try: phonebook = FritzBoxPhonebook( diff --git a/homeassistant/components/fritzbox_netmonitor/manifest.json b/homeassistant/components/fritzbox_netmonitor/manifest.json index dde4d634867..3eeac8bd8dd 100644 --- a/homeassistant/components/fritzbox_netmonitor/manifest.json +++ b/homeassistant/components/fritzbox_netmonitor/manifest.json @@ -2,6 +2,6 @@ "domain": "fritzbox_netmonitor", "name": "AVM FRITZ!Box Net Monitor", "documentation": "https://www.home-assistant.io/integrations/fritzbox_netmonitor", - "requirements": ["fritzconnection==1.2.0"], + "requirements": ["fritzconnection==1.3.4"], "codeowners": [] } diff --git a/homeassistant/components/fritzbox_netmonitor/sensor.py b/homeassistant/components/fritzbox_netmonitor/sensor.py index 5601ad5d74f..13b822ae8a4 100644 --- a/homeassistant/components/fritzbox_netmonitor/sensor.py +++ b/homeassistant/components/fritzbox_netmonitor/sensor.py @@ -15,8 +15,8 @@ from homeassistant.util import Throttle _LOGGER = logging.getLogger(__name__) -CONF_DEFAULT_NAME = "fritz_netmonitor" -CONF_DEFAULT_IP = "169.254.1.1" # This IP is valid for all FRITZ!Box routers. +DEFAULT_NAME = "fritz_netmonitor" +DEFAULT_HOST = "169.254.1.1" # This IP is valid for all FRITZ!Box routers. ATTR_BYTES_RECEIVED = "bytes_received" ATTR_BYTES_SENT = "bytes_sent" @@ -38,16 +38,16 @@ ICON = "mdi:web" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { - vol.Optional(CONF_NAME, default=CONF_DEFAULT_NAME): cv.string, - vol.Optional(CONF_HOST, default=CONF_DEFAULT_IP): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, } ) def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the FRITZ!Box monitor sensors.""" - name = config.get(CONF_NAME) - host = config.get(CONF_HOST) + name = config[CONF_NAME] + host = config[CONF_HOST] try: fstatus = FritzStatus(address=host) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 66c1b6d997f..080d786d4e4 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from .storage import async_setup_frontend_storage # mypy: allow-untyped-defs, no-check-untyped-defs # Fix mimetypes for borked Windows machines -# https://github.com/home-assistant/home-assistant-polymer/issues/3336 +# https://github.com/home-assistant/frontend/issues/3336 mimetypes.add_type("text/css", ".css") mimetypes.add_type("application/javascript", ".js") diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index 0957c6fd776..aea1717ce6f 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.4"], + "requirements": ["home-assistant-frontend==20201111.2"], "dependencies": [ "api", "auth", diff --git a/homeassistant/components/garmin_connect/__init__.py b/homeassistant/components/garmin_connect/__init__.py index c0a1012f051..896c243f386 100644 --- a/homeassistant/components/garmin_connect/__init__.py +++ b/homeassistant/components/garmin_connect/__init__.py @@ -90,6 +90,17 @@ class GarminConnectData: self.client = client self.data = None + async def _get_combined_alarms_of_all_devices(self): + """Combine the list of active alarms from all garmin devices.""" + alarms = [] + devices = await self.hass.async_add_executor_job(self.client.get_devices) + for device in devices: + device_settings = await self.hass.async_add_executor_job( + self.client.get_device_settings, device["deviceId"] + ) + alarms += device_settings["alarms"] + return alarms + @Throttle(MIN_SCAN_INTERVAL) async def async_update(self): """Update data via library.""" @@ -99,6 +110,7 @@ class GarminConnectData: self.data = await self.hass.async_add_executor_job( self.client.get_stats_and_body, today.isoformat() ) + self.data["nextAlarm"] = await self._get_combined_alarms_of_all_devices() except ( GarminConnectAuthenticationError, GarminConnectTooManyRequestsError, diff --git a/homeassistant/components/garmin_connect/alarm_util.py b/homeassistant/components/garmin_connect/alarm_util.py new file mode 100644 index 00000000000..4964d70e886 --- /dev/null +++ b/homeassistant/components/garmin_connect/alarm_util.py @@ -0,0 +1,50 @@ +"""Utility method for converting Garmin Connect alarms to python datetime.""" +from datetime import date, datetime, timedelta +import logging + +_LOGGER = logging.getLogger(__name__) + +DAY_TO_NUMBER = { + "Mo": 1, + "M": 1, + "Tu": 2, + "We": 3, + "W": 3, + "Th": 4, + "Fr": 5, + "F": 5, + "Sa": 6, + "Su": 7, +} + + +def calculate_next_active_alarms(alarms): + """ + Calculate garmin next active alarms from settings. + + Alarms are sorted by time + """ + active_alarms = [] + _LOGGER.debug(alarms) + + for alarm_setting in alarms: + if alarm_setting["alarmMode"] != "ON": + continue + for day in alarm_setting["alarmDays"]: + alarm_time = alarm_setting["alarmTime"] + if day == "ONCE": + midnight = datetime.combine(date.today(), datetime.min.time()) + alarm = midnight + timedelta(minutes=alarm_time) + if alarm < datetime.now(): + alarm += timedelta(days=1) + else: + start_of_week = datetime.combine( + date.today() - timedelta(days=datetime.today().isoweekday() % 7), + datetime.min.time(), + ) + days_to_add = DAY_TO_NUMBER[day] % 7 + alarm = start_of_week + timedelta(minutes=alarm_time, days=days_to_add) + if alarm < datetime.now(): + alarm += timedelta(days=7) + active_alarms.append(alarm.isoformat()) + return sorted(active_alarms) if active_alarms else None diff --git a/homeassistant/components/garmin_connect/const.py b/homeassistant/components/garmin_connect/const.py index 77db3359a71..7a143e2e63a 100644 --- a/homeassistant/components/garmin_connect/const.py +++ b/homeassistant/components/garmin_connect/const.py @@ -348,4 +348,5 @@ GARMIN_ENTITY_LIST = { "physiqueRating": ["Physique Rating", "", "mdi:numeric", None, False], "visceralFat": ["Visceral Fat", "", "mdi:food", None, False], "metabolicAge": ["Metabolic Age", "", "mdi:calendar-heart", None, False], + "nextAlarm": ["Next Alarm Time", "", "mdi:alarm", DEVICE_CLASS_TIMESTAMP, True], } diff --git a/homeassistant/components/garmin_connect/manifest.json b/homeassistant/components/garmin_connect/manifest.json index 7a57b1bf102..c7880f9b416 100644 --- a/homeassistant/components/garmin_connect/manifest.json +++ b/homeassistant/components/garmin_connect/manifest.json @@ -2,7 +2,7 @@ "domain": "garmin_connect", "name": "Garmin Connect", "documentation": "https://www.home-assistant.io/integrations/garmin_connect", - "requirements": ["garminconnect==0.1.13"], + "requirements": ["garminconnect==0.1.16"], "codeowners": ["@cyberjunky"], "config_flow": true } diff --git a/homeassistant/components/garmin_connect/sensor.py b/homeassistant/components/garmin_connect/sensor.py index 9b678011053..5d18f0a0dd0 100644 --- a/homeassistant/components/garmin_connect/sensor.py +++ b/homeassistant/components/garmin_connect/sensor.py @@ -13,6 +13,7 @@ from homeassistant.const import ATTR_ATTRIBUTION, CONF_ID from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import HomeAssistantType +from .alarm_util import calculate_next_active_alarms from .const import ATTRIBUTION, DOMAIN, GARMIN_ENTITY_LIST _LOGGER = logging.getLogger(__name__) @@ -123,11 +124,16 @@ class GarminConnectSensor(Entity): """Return attributes for sensor.""" if not self._data.data: return {} - return { + attributes = { "source": self._data.data["source"], "last_synced": self._data.data["lastSyncTimestampGMT"], ATTR_ATTRIBUTION: ATTRIBUTION, } + if self._type == "nextAlarm": + attributes["next_alarms"] = calculate_next_active_alarms( + self._data.data[self._type] + ) + return attributes @property def device_info(self) -> Dict[str, Any]: @@ -177,6 +183,12 @@ class GarminConnectSensor(Entity): self._type == "bodyFat" or self._type == "bodyWater" or self._type == "bmi" ): self._state = round(data[self._type], 2) + elif self._type == "nextAlarm": + active_alarms = calculate_next_active_alarms(data[self._type]) + if active_alarms: + self._state = active_alarms[0] + else: + self._available = False else: self._state = data[self._type] diff --git a/homeassistant/components/garmin_connect/translations/et.json b/homeassistant/components/garmin_connect/translations/et.json index b46ffd39076..eeaefe92700 100644 --- a/homeassistant/components/garmin_connect/translations/et.json +++ b/homeassistant/components/garmin_connect/translations/et.json @@ -6,6 +6,7 @@ "error": { "cannot_connect": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamine nurjus", + "too_many_requests": "Liiga palju taotlusi, proovi hiljem uuesti.", "unknown": "Tundmatu viga" }, "step": { @@ -14,6 +15,7 @@ "password": "Salas\u00f5na", "username": "Kasutajanimi" }, + "description": "Sisesta oma mandaat.", "title": "" } } diff --git a/homeassistant/components/garmin_connect/translations/lb.json b/homeassistant/components/garmin_connect/translations/lb.json index 136f2bff5d3..583942b1575 100644 --- a/homeassistant/components/garmin_connect/translations/lb.json +++ b/homeassistant/components/garmin_connect/translations/lb.json @@ -4,10 +4,10 @@ "already_configured": "Kont ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9iert w.e.g. nach emol.", - "invalid_auth": "Ong\u00eblteg Authentifikatioun.", + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", "too_many_requests": "Ze vill Ufroen, prob\u00e9iert sp\u00e9ider nach emol.", - "unknown": "Onerwaarte Feeler." + "unknown": "Onerwaarte Feeler" }, "step": { "user": { diff --git a/homeassistant/components/gdacs/manifest.json b/homeassistant/components/gdacs/manifest.json index 630ed0a4a06..1b6356d21e8 100644 --- a/homeassistant/components/gdacs/manifest.json +++ b/homeassistant/components/gdacs/manifest.json @@ -3,7 +3,7 @@ "name": "Global Disaster Alert and Coordination System (GDACS)", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/gdacs", - "requirements": ["aio_georss_gdacs==0.3"], + "requirements": ["aio_georss_gdacs==0.4"], "codeowners": ["@exxamalte"], "quality_scale": "platinum" } diff --git a/homeassistant/components/gdacs/translations/et.json b/homeassistant/components/gdacs/translations/et.json index 7df1adb08b5..a2ab0d92c50 100644 --- a/homeassistant/components/gdacs/translations/et.json +++ b/homeassistant/components/gdacs/translations/et.json @@ -2,6 +2,14 @@ "config": { "abort": { "already_configured": "Teenus on juba seadistatud" + }, + "step": { + "user": { + "data": { + "radius": "Raadius" + }, + "title": "Sisesta filtri \u00fcksikasjad." + } } } } \ No newline at end of file diff --git a/homeassistant/components/gdacs/translations/lb.json b/homeassistant/components/gdacs/translations/lb.json index 5125ce8c58e..851aead0a69 100644 --- a/homeassistant/components/gdacs/translations/lb.json +++ b/homeassistant/components/gdacs/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Standuert ass scho konfigu\u00e9iert." + "already_configured": "Service ass scho konfigu\u00e9iert" }, "step": { "user": { diff --git a/homeassistant/components/geofency/strings.json b/homeassistant/components/geofency/strings.json index a7b6649fb6e..855d3f43864 100644 --- a/homeassistant/components/geofency/strings.json +++ b/homeassistant/components/geofency/strings.json @@ -8,7 +8,7 @@ }, "abort": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Geofency." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup the webhook feature in Geofency.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/geofency/translations/bg.json b/homeassistant/components/geofency/translations/bg.json index 1bd9cf1a818..de2e8af5d97 100644 --- a/homeassistant/components/geofency/translations/bg.json +++ b/homeassistant/components/geofency/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 Geofency.", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u0441\u044a\u0431\u0438\u0442\u0438\u044f \u0434\u043e Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0442\u0430 webhook \u0432 Geofency. \n\n \u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: \n\n - URL: ` {webhook_url} ` \n - Method: POST \n\n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438." }, diff --git a/homeassistant/components/geofency/translations/ca.json b/homeassistant/components/geofency/translations/ca.json index 59eab112331..a956bf5ce62 100644 --- a/homeassistant/components/geofency/translations/ca.json +++ b/homeassistant/components/geofency/translations/ca.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de Geofency.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar esdeveniments a Home Assistant, haur\u00e0s de configurar l'opci\u00f3 webhook de Geofency.\n\nCompleta la seg\u00fcent informaci\u00f3:\n\n- URL: `{webhook_url}` \n- M\u00e8tode: POST \n\nConsulta la [documentaci\u00f3]({docs_url}) per a m\u00e9s detalls." diff --git a/homeassistant/components/geofency/translations/cs.json b/homeassistant/components/geofency/translations/cs.json index 0b7e363d64c..bc03c9c8aa6 100644 --- a/homeassistant/components/geofency/translations/cs.json +++ b/homeassistant/components/geofency/translations/cs.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "not_internet_accessible": "V\u00e1\u0161 Home Asistent mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy od Geofency.", - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "create_entry": { - "default": "Chcete-li odes\u00edlat ud\u00e1losti do aplikace Home Assistant, mus\u00edte v aplikaci Geofency nastavit funkci webhook. \n\n Vypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: `{webhook_url}` \n - Metoda: POST \n\n Dal\u0161\u00ed informace viz [dokumentace]({docs_url})." + "default": "Chcete-li odes\u00edlat ud\u00e1losti do Home Assistant, mus\u00edte v aplikaci Geofency nastavit funkci webhook. \n\nVypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: `{webhook_url}` \n - Metoda: POST \n\nDal\u0161\u00ed informace viz [dokumentace]({docs_url})." }, "step": { "user": { diff --git a/homeassistant/components/geofency/translations/da.json b/homeassistant/components/geofency/translations/da.json index 176ba84b768..6d75dab49d1 100644 --- a/homeassistant/components/geofency/translations/da.json +++ b/homeassistant/components/geofency/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage Geofency-meddelelser.", - "one_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning" - }, "create_entry": { "default": "For at sende h\u00e6ndelser til Home Assistant skal du konfigurere webhook-funktionen i Geofency.\n\n Udfyld f\u00f8lgende oplysninger: \n\n - Webadresse: `{webhook_url}`\n - Metode: POST\n \nSe [dokumentationen]({docs_url}) for yderligere oplysninger." }, diff --git a/homeassistant/components/geofency/translations/de.json b/homeassistant/components/geofency/translations/de.json index c585ee467aa..31b8a5eb321 100644 --- a/homeassistant/components/geofency/translations/de.json +++ b/homeassistant/components/geofency/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Deine Home-Assistant-Instanz muss aus dem internet erreichbar sein, um Nachrichten von Geofency zu erhalten.", - "one_instance_allowed": "Es ist nur eine einzige Instanz erforderlich." - }, "create_entry": { "default": "Um Ereignisse an den Home Assistant zu senden, musst das Webhook Feature in Geofency konfiguriert werden.\n\n F\u00fcge die folgenden Informationen ein: \n\n - URL: ` {webhook_url} ` \n - Methode: POST \n \n Weitere Informationen finden sich in der [Dokumentation]({docs_url})." }, diff --git a/homeassistant/components/geofency/translations/en.json b/homeassistant/components/geofency/translations/en.json index 5fc9983e68c..db7a9e684f9 100644 --- a/homeassistant/components/geofency/translations/en.json +++ b/homeassistant/components/geofency/translations/en.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Geofency.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup the webhook feature in Geofency.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/geofency/translations/es-419.json b/homeassistant/components/geofency/translations/es-419.json index bb8160ed5ef..fa57c99af19 100644 --- a/homeassistant/components/geofency/translations/es-419.json +++ b/homeassistant/components/geofency/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Geofency.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar eventos a Home Assistant, deber\u00e1 configurar la funci\u00f3n de webhook en Geofency. \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n\n Vea [la documentaci\u00f3n] ( {docs_url} ) para m\u00e1s detalles." }, diff --git a/homeassistant/components/geofency/translations/es.json b/homeassistant/components/geofency/translations/es.json index 28856f5d65d..22aa30cc182 100644 --- a/homeassistant/components/geofency/translations/es.json +++ b/homeassistant/components/geofency/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Tu Home Assistant debe ser accesible desde Internet para recibir mensajes de GPSLogger.", - "one_instance_allowed": "S\u00f3lo se necesita una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar eventos a Home Assistant, necesitar\u00e1s configurar la funci\u00f3n de webhook en Geofency.\n\nRellene la siguiente informaci\u00f3n:\n\n- URL: ``{webhook_url}``\n- M\u00e9todo: POST\n\nVer[la documentaci\u00f3n]({docs_url}) para m\u00e1s detalles." diff --git a/homeassistant/components/geofency/translations/et.json b/homeassistant/components/geofency/translations/et.json index 05a493683e1..fa87d80871f 100644 --- a/homeassistant/components/geofency/translations/et.json +++ b/homeassistant/components/geofency/translations/et.json @@ -1,12 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Lubatud on ainult \u00fcks sidumine.", - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." + }, + "create_entry": { + "default": "S\u00fcndmuste saatmiseks Home Assistantile pead seadistama Geofency veebihaagi. \n\n Sisesta j\u00e4rgmine teave: \n\n - URL: \" {webhook_url} \" \n - Meetod: POST \n \n Lisateavet leiad [documentation] ( {docs_url} )." }, "step": { "user": { - "description": "Kas soovid Geofency Webhooki seadistada?" + "description": "Kas soovid Geofency Webhooki seadistada?", + "title": "Seadista Geofency Webhook" } } } diff --git a/homeassistant/components/geofency/translations/fr.json b/homeassistant/components/geofency/translations/fr.json index b7940cbe58c..270a6275791 100644 --- a/homeassistant/components/geofency/translations/fr.json +++ b/homeassistant/components/geofency/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance Home Assistant doit \u00eatre accessible \u00e0 partir d'Internet pour recevoir les messages Geofency.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez configurer la fonctionnalit\u00e9 Webhook dans Geofency. \n\n Remplissez les informations suivantes: \n\n - URL: ` {webhook_url} ` \n - M\u00e9thode: POST \n\n Voir [la documentation] ( {docs_url} ) pour plus de d\u00e9tails." diff --git a/homeassistant/components/geofency/translations/hu.json b/homeassistant/components/geofency/translations/hu.json index 026912e0d3e..99dc0fecead 100644 --- a/homeassistant/components/geofency/translations/hu.json +++ b/homeassistant/components/geofency/translations/hu.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Az Home Assistantnek el\u00e9rhet\u0151nek kell lennie az internetr\u0151l, hogy megkapja a Geofency \u00fczeneteit.", - "one_instance_allowed": "Csak egy p\u00e9ld\u00e1ny sz\u00fcks\u00e9ges." - }, "create_entry": { "default": "Az esem\u00e9ny Home Assistantnek val\u00f3 k\u00fcld\u00e9s\u00e9hez be kell \u00e1ll\u00edtanod a webhook funkci\u00f3t a Geofencyben. \n\n Az al\u00e1bbi inform\u00e1ci\u00f3kat haszn\u00e1ld: \n\n - URL: ` {webhook_url} ` \n - Method: POST \n\n Tov\u00e1bbi r\u00e9szletek a [dokument\u00e1ci\u00f3] ( {docs_url} ) linken tal\u00e1lhat\u00f3k." }, diff --git a/homeassistant/components/geofency/translations/it.json b/homeassistant/components/geofency/translations/it.json index e061e803e28..48f0456a2bc 100644 --- a/homeassistant/components/geofency/translations/it.json +++ b/homeassistant/components/geofency/translations/it.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi da Geofency.", - "one_instance_allowed": "\u00c8 necessaria una sola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare eventi a Home Assistant, dovrai configurare la funzionalit\u00e0 webhook in Geofency.\n\n Compila le seguenti informazioni: \n\n - URL: `{webhook_url}` \n - Method: POST \n\n Vedi [la documentazione]({docs_url}) for ulteriori dettagli." diff --git a/homeassistant/components/geofency/translations/ko.json b/homeassistant/components/geofency/translations/ko.json index d0d0fde2efd..8bab38a8a34 100644 --- a/homeassistant/components/geofency/translations/ko.json +++ b/homeassistant/components/geofency/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Geofency \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\ub824\uba74 Geofency \uc5d0\uc11c \uc6f9 \ud6c5\uc744 \uc124\uc815\ud574\uc57c\ud569\ub2c8\ub2e4. \n\n\ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694:\n\n - URL: `{webhook_url}`\n - Method: POST\n \n \uc790\uc138\ud55c \uc815\ubcf4\ub294 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/geofency/translations/lb.json b/homeassistant/components/geofency/translations/lb.json index fcf26deb3ad..1e7b20d8423 100644 --- a/homeassistant/components/geofency/translations/lb.json +++ b/homeassistant/components/geofency/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir Geofency Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { diff --git a/homeassistant/components/geofency/translations/nl.json b/homeassistant/components/geofency/translations/nl.json index 06bce326c95..763d903a8ba 100644 --- a/homeassistant/components/geofency/translations/nl.json +++ b/homeassistant/components/geofency/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Uw Home Assistant instantie moet toegankelijk zijn vanaf het internet om Geofency-berichten te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/geofency/translations/no.json b/homeassistant/components/geofency/translations/no.json index a07a2bcd127..51fa75f66b4 100644 --- a/homeassistant/components/geofency/translations/no.json +++ b/homeassistant/components/geofency/translations/no.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta meldinger fra Geofency.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { "default": "For \u00e5 kunne sende hendelser til Home Assistant, m\u00e5 du sette opp webhook-funksjonen i Geofency. \n\n Fyll ut f\u00f8lgende informasjon: \n\n - URL: `{webhook_url}` \n - Metode: POST \n\n Se [dokumentasjonen]({docs_url}) for ytterligere detaljer." diff --git a/homeassistant/components/geofency/translations/pl.json b/homeassistant/components/geofency/translations/pl.json index 00608c86467..b43dbabb806 100644 --- a/homeassistant/components/geofency/translations/pl.json +++ b/homeassistant/components/geofency/translations/pl.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty z Geofency", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant, musisz skonfigurowa\u0107 webhook w Geofency. \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}), by pozna\u0107 szczeg\u00f3\u0142y." }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 Geofency?", + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", "title": "Konfiguracja Geofency Webhook" } } diff --git a/homeassistant/components/geofency/translations/pt-BR.json b/homeassistant/components/geofency/translations/pt-BR.json index 1f715bf4a7a..d8b430df5f4 100644 --- a/homeassistant/components/geofency/translations/pt-BR.json +++ b/homeassistant/components/geofency/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia do Home Assistant precisa estar acess\u00edvel na Internet para receber mensagens da Geofency.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, voc\u00ea precisar\u00e1 configurar o recurso webhook no Geofency. \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n\n Veja [a documenta\u00e7\u00e3o] ( {docs_url} ) para mais detalhes." }, diff --git a/homeassistant/components/geofency/translations/pt.json b/homeassistant/components/geofency/translations/pt.json index c5b080f0dcd..4e202834624 100644 --- a/homeassistant/components/geofency/translations/pt.json +++ b/homeassistant/components/geofency/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A sua inst\u00e2ncia Home Assistent precisa de ser acess\u00edvel a partir da internet para receber mensagens IFTTT.", - "one_instance_allowed": "Apenas uma inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, \u00e9 necess\u00e1rio configurar um webhook no Geofency. \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: `{webhook_url}`\n - M\u00e9todo: POST \n\n Veja [the documentation]({docs_url}) para obter mais detalhes." }, diff --git a/homeassistant/components/geofency/translations/ru.json b/homeassistant/components/geofency/translations/ru.json index 80304f3eb26..46b5c0ba93f 100644 --- a/homeassistant/components/geofency/translations/ru.json +++ b/homeassistant/components/geofency/translations/ru.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 Geofency.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Webhook \u0434\u043b\u044f Geofency.\n\n\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\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 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438." diff --git a/homeassistant/components/geofency/translations/sl.json b/homeassistant/components/geofency/translations/sl.json index ba293c8c11a..be1b150d93c 100644 --- a/homeassistant/components/geofency/translations/sl.json +++ b/homeassistant/components/geofency/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Va\u0161 Home Assistant mora biti dostopen prek interneta, da boste lahko prejemali Geofency sporo\u010dila.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "\u010ce \u017eelite dogodke poslati v Home Assistant, morate v Geofency-ju nastaviti funkcijo webhook. \n\n Izpolnite naslednje podatke: \n\n - URL: ` {webhook_url} ` \n - Metoda: POST \n\n Za ve\u010d podrobnosti si oglejte [dokumentacijo] ( {docs_url} )." }, diff --git a/homeassistant/components/geofency/translations/sv.json b/homeassistant/components/geofency/translations/sv.json index f18a7bd25bb..453b33533ce 100644 --- a/homeassistant/components/geofency/translations/sv.json +++ b/homeassistant/components/geofency/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant instans m\u00e5ste vara \u00e5tkomlig ifr\u00e5n internet f\u00f6r att ta emot meddelanden ifr\u00e5n Geofency.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du konfigurera webhook funktionen i Geofency.\n\n Fyll i f\u00f6ljande information:\n \n- URL: `{webhook_url}`\n- Method: POST\n\nSe [dokumentation]({docs_url}) om hur du konfigurerar detta f\u00f6r mer information." }, diff --git a/homeassistant/components/geofency/translations/zh-Hans.json b/homeassistant/components/geofency/translations/zh-Hans.json index 5be88f69e41..d6355fd3809 100644 --- a/homeassistant/components/geofency/translations/zh-Hans.json +++ b/homeassistant/components/geofency/translations/zh-Hans.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u63a5\u5165\u4e92\u8054\u7f51\u4ee5\u63a5\u6536 Geofency \u6d88\u606f\u3002", - "one_instance_allowed": "\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u662f\u5fc5\u9700\u7684\u3002" - }, "create_entry": { "default": "\u8981\u5411 Home Assistant \u53d1\u9001\u4e8b\u4ef6\uff0c\u60a8\u9700\u8981\u914d\u7f6e Geofency \u7684 Webhook \u529f\u80fd\u3002\n\n\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\u8bf7\u53c2\u9605[\u6587\u6863]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u591a\u4fe1\u606f\u3002" }, diff --git a/homeassistant/components/geofency/translations/zh-Hant.json b/homeassistant/components/geofency/translations/zh-Hant.json index 494dc8ddf23..0bef632c5a8 100644 --- a/homeassistant/components/geofency/translations/zh-Hant.json +++ b/homeassistant/components/geofency/translations/zh-Hant.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u8a2d\u5099\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 Geofency \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u65bc Geofency \u5167\u8a2d\u5b9a webhook \u529f\u80fd\u3002\n\n\u8acb\u586b\u5beb\u4e0b\u5217\u8cc7\u8a0a\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\u8acb\u53c3\u95b1 [\u6587\u4ef6]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u8a73\u7d30\u8cc7\u6599\u3002" diff --git a/homeassistant/components/geonetnz_quakes/translations/et.json b/homeassistant/components/geonetnz_quakes/translations/et.json index 7df1adb08b5..16a83bd12f9 100644 --- a/homeassistant/components/geonetnz_quakes/translations/et.json +++ b/homeassistant/components/geonetnz_quakes/translations/et.json @@ -2,6 +2,15 @@ "config": { "abort": { "already_configured": "Teenus on juba seadistatud" + }, + "step": { + "user": { + "data": { + "mmi": "", + "radius": "Raadius" + }, + "title": "Sisesta oma filtri \u00fcksikasjad." + } } } } \ No newline at end of file diff --git a/homeassistant/components/geonetnz_quakes/translations/lb.json b/homeassistant/components/geonetnz_quakes/translations/lb.json index 482330099b3..03e6ef3df56 100644 --- a/homeassistant/components/geonetnz_quakes/translations/lb.json +++ b/homeassistant/components/geonetnz_quakes/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Standuert ass scho konfigu\u00e9iert." + "already_configured": "Service ass scho konfigu\u00e9iert" }, "step": { "user": { diff --git a/homeassistant/components/geonetnz_volcano/translations/bg.json b/homeassistant/components/geonetnz_volcano/translations/bg.json index e50751ad49e..042696219fc 100644 --- a/homeassistant/components/geonetnz_volcano/translations/bg.json +++ b/homeassistant/components/geonetnz_volcano/translations/bg.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u0442\u043e \u0432\u0435\u0447\u0435 \u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d\u043e" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/ca.json b/homeassistant/components/geonetnz_volcano/translations/ca.json index 5868d9acf93..0cb35b8fe77 100644 --- a/homeassistant/components/geonetnz_volcano/translations/ca.json +++ b/homeassistant/components/geonetnz_volcano/translations/ca.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "La ubicaci\u00f3 ja est\u00e0 configurada" }, - "error": { - "identifier_exists": "Ubicaci\u00f3 ja registrada" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/cs.json b/homeassistant/components/geonetnz_volcano/translations/cs.json index 03d10c800a9..9555d163507 100644 --- a/homeassistant/components/geonetnz_volcano/translations/cs.json +++ b/homeassistant/components/geonetnz_volcano/translations/cs.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Um\u00edst\u011bn\u00ed je ji\u017e nastaveno" }, - "error": { - "identifier_exists": "Um\u00edst\u011bn\u00ed ji\u017e existuje" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/da.json b/homeassistant/components/geonetnz_volcano/translations/da.json index b83162e0b35..be546e35c8e 100644 --- a/homeassistant/components/geonetnz_volcano/translations/da.json +++ b/homeassistant/components/geonetnz_volcano/translations/da.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Lokalitet allerede registreret" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/de.json b/homeassistant/components/geonetnz_volcano/translations/de.json index 8c3cd960b4d..b573d93cd5a 100644 --- a/homeassistant/components/geonetnz_volcano/translations/de.json +++ b/homeassistant/components/geonetnz_volcano/translations/de.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Standort bereits registriert" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/en.json b/homeassistant/components/geonetnz_volcano/translations/en.json index b6adecdeb7d..4c5a6b78015 100644 --- a/homeassistant/components/geonetnz_volcano/translations/en.json +++ b/homeassistant/components/geonetnz_volcano/translations/en.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Location is already configured" }, - "error": { - "identifier_exists": "Location already registered" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/es-419.json b/homeassistant/components/geonetnz_volcano/translations/es-419.json index c26033e1861..9ceb51de1e9 100644 --- a/homeassistant/components/geonetnz_volcano/translations/es-419.json +++ b/homeassistant/components/geonetnz_volcano/translations/es-419.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Lugar ya registrado" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/es.json b/homeassistant/components/geonetnz_volcano/translations/es.json index c26033e1861..1621a42eb4a 100644 --- a/homeassistant/components/geonetnz_volcano/translations/es.json +++ b/homeassistant/components/geonetnz_volcano/translations/es.json @@ -1,7 +1,7 @@ { "config": { - "error": { - "identifier_exists": "Lugar ya registrado" + "abort": { + "already_configured": "La ubicaci\u00f3n ya est\u00e1 configurada" }, "step": { "user": { diff --git a/homeassistant/components/geonetnz_volcano/translations/et.json b/homeassistant/components/geonetnz_volcano/translations/et.json index 413d9e20992..2a89ceb66e5 100644 --- a/homeassistant/components/geonetnz_volcano/translations/et.json +++ b/homeassistant/components/geonetnz_volcano/translations/et.json @@ -2,6 +2,14 @@ "config": { "abort": { "already_configured": "Asukoht on juba m\u00e4\u00e4ratud" + }, + "step": { + "user": { + "data": { + "radius": "" + }, + "title": "Sisesta filtri \u00fcksikasjad." + } } } } \ No newline at end of file diff --git a/homeassistant/components/geonetnz_volcano/translations/fr.json b/homeassistant/components/geonetnz_volcano/translations/fr.json index 2692768910c..78739065645 100644 --- a/homeassistant/components/geonetnz_volcano/translations/fr.json +++ b/homeassistant/components/geonetnz_volcano/translations/fr.json @@ -1,7 +1,7 @@ { "config": { - "error": { - "identifier_exists": "Emplacement d\u00e9j\u00e0 enregistr\u00e9" + "abort": { + "already_configured": "L'emplacement est d\u00e9j\u00e0 configur\u00e9" }, "step": { "user": { diff --git a/homeassistant/components/geonetnz_volcano/translations/hu.json b/homeassistant/components/geonetnz_volcano/translations/hu.json index e1d2bdb9f9e..42de5a13142 100644 --- a/homeassistant/components/geonetnz_volcano/translations/hu.json +++ b/homeassistant/components/geonetnz_volcano/translations/hu.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "A hely m\u00e1r regisztr\u00e1lt" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/it.json b/homeassistant/components/geonetnz_volcano/translations/it.json index c566cdfb81b..85445d9a77d 100644 --- a/homeassistant/components/geonetnz_volcano/translations/it.json +++ b/homeassistant/components/geonetnz_volcano/translations/it.json @@ -1,7 +1,7 @@ { "config": { - "error": { - "identifier_exists": "Localit\u00e0 gi\u00e0 registrata" + "abort": { + "already_configured": "La posizione \u00e8 gi\u00e0 configurata" }, "step": { "user": { diff --git a/homeassistant/components/geonetnz_volcano/translations/ko.json b/homeassistant/components/geonetnz_volcano/translations/ko.json index 9ee235ea2b6..26e83789e8f 100644 --- a/homeassistant/components/geonetnz_volcano/translations/ko.json +++ b/homeassistant/components/geonetnz_volcano/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "\uc704\uce58\uac00 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/lb.json b/homeassistant/components/geonetnz_volcano/translations/lb.json index 0d5108982b6..a9d18c4e5d6 100644 --- a/homeassistant/components/geonetnz_volcano/translations/lb.json +++ b/homeassistant/components/geonetnz_volcano/translations/lb.json @@ -1,7 +1,7 @@ { "config": { - "error": { - "identifier_exists": "Standuert ass scho registr\u00e9iert" + "abort": { + "already_configured": "Standuert ass scho konfigur\u00e9iert" }, "step": { "user": { diff --git a/homeassistant/components/geonetnz_volcano/translations/nl.json b/homeassistant/components/geonetnz_volcano/translations/nl.json index 73c7c1eaab3..0e678aa6489 100644 --- a/homeassistant/components/geonetnz_volcano/translations/nl.json +++ b/homeassistant/components/geonetnz_volcano/translations/nl.json @@ -1,7 +1,7 @@ { "config": { - "error": { - "identifier_exists": "Locatie al geregistreerd" + "abort": { + "already_configured": "Locatie is al geconfigureerd" }, "step": { "user": { diff --git a/homeassistant/components/geonetnz_volcano/translations/no.json b/homeassistant/components/geonetnz_volcano/translations/no.json index b7bd20b3eb4..4c40684bd51 100644 --- a/homeassistant/components/geonetnz_volcano/translations/no.json +++ b/homeassistant/components/geonetnz_volcano/translations/no.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Plasseringen er allerede konfigurert" }, - "error": { - "identifier_exists": "Plasseringen er allerede registrert" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/pl.json b/homeassistant/components/geonetnz_volcano/translations/pl.json index 3c3d829f1c7..d4db79e3fa7 100644 --- a/homeassistant/components/geonetnz_volcano/translations/pl.json +++ b/homeassistant/components/geonetnz_volcano/translations/pl.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Lokalizacja jest ju\u017c skonfigurowana" }, - "error": { - "identifier_exists": "Lokalizacja jest ju\u017c zarejestrowana" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/pt-BR.json b/homeassistant/components/geonetnz_volcano/translations/pt-BR.json index b1629599926..98180e11248 100644 --- a/homeassistant/components/geonetnz_volcano/translations/pt-BR.json +++ b/homeassistant/components/geonetnz_volcano/translations/pt-BR.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Local j\u00e1 registrado" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/ru.json b/homeassistant/components/geonetnz_volcano/translations/ru.json index 8610314b9aa..36d2cc6f1bc 100644 --- a/homeassistant/components/geonetnz_volcano/translations/ru.json +++ b/homeassistant/components/geonetnz_volcano/translations/ru.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." }, - "error": { - "identifier_exists": "\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/sl.json b/homeassistant/components/geonetnz_volcano/translations/sl.json index 885c41957f7..81bcef5fe19 100644 --- a/homeassistant/components/geonetnz_volcano/translations/sl.json +++ b/homeassistant/components/geonetnz_volcano/translations/sl.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Lokacija je \u017ee registrirana" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/sv.json b/homeassistant/components/geonetnz_volcano/translations/sv.json index 3abddb78c68..0ad4f7f0853 100644 --- a/homeassistant/components/geonetnz_volcano/translations/sv.json +++ b/homeassistant/components/geonetnz_volcano/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Plats redan registrerad" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/geonetnz_volcano/translations/zh-Hant.json b/homeassistant/components/geonetnz_volcano/translations/zh-Hant.json index a7962258b75..9dd69261e59 100644 --- a/homeassistant/components/geonetnz_volcano/translations/zh-Hant.json +++ b/homeassistant/components/geonetnz_volcano/translations/zh-Hant.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\u5ea7\u6a19\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, - "error": { - "identifier_exists": "\u5ea7\u6a19\u5df2\u8a3b\u518a" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/gios/translations/et.json b/homeassistant/components/gios/translations/et.json index 3c90c9b3abf..163407ffce6 100644 --- a/homeassistant/components/gios/translations/et.json +++ b/homeassistant/components/gios/translations/et.json @@ -4,13 +4,17 @@ "already_configured": "Asukoht on juba m\u00e4\u00e4ratud" }, "error": { - "cannot_connect": "\u00dchendamine nurjus" + "cannot_connect": "\u00dchendamine nurjus", + "invalid_sensors_data": "Selle m\u00f5\u00f5tejaama andurite andmed on valed.", + "wrong_station_id": "M\u00f5\u00f5tejaama ID ei ole \u00f5ige." }, "step": { "user": { "data": { - "name": "Nimi" + "name": "Nimi", + "station_id": "M\u00f5\u00f5tejaama ID" }, + "description": "Loo GIO\u015a (Poola keskkonnakaitse peainspektsioon) \u00f5hukvaliteedi sidumnie. Kui vajad seadistamisel abi, vaats siit: https://www.home-assistant.io/integrations/gios", "title": "" } } diff --git a/homeassistant/components/gios/translations/lb.json b/homeassistant/components/gios/translations/lb.json index 66cd2393a22..8e8ab861b43 100644 --- a/homeassistant/components/gios/translations/lb.json +++ b/homeassistant/components/gios/translations/lb.json @@ -1,17 +1,17 @@ { "config": { "abort": { - "already_configured": "GIO\u015a Integratioun fir d\u00ebs Miess Statioun ass scho konfigur\u00e9iert." + "already_configured": "Standuert ass scho konfigur\u00e9iert." }, "error": { - "cannot_connect": "Konnt sech net mam GIO\u015a Server verbannen.", + "cannot_connect": "Feeler beim verbannen", "invalid_sensors_data": "Ong\u00eblteg Sensor Donn\u00e9e\u00eb fir d\u00ebs Miess Statioun", "wrong_station_id": "ID vun der Miess Statioun ass net korrekt." }, "step": { "user": { "data": { - "name": "Numm vun der Integratioun", + "name": "Numm", "station_id": "ID vun der Miess Statioun" }, "description": "GIO\u015a (Polnesch Chefinspektorat vum \u00cbmweltschutz) Loft Qualit\u00e9it Integratioun ariichten. Fir w\u00e9ider H\u00ebllef mat der Konfiuratioun kuckt hei: https://www.home-assistant.io/integrations/gios", diff --git a/homeassistant/components/gitter/sensor.py b/homeassistant/components/gitter/sensor.py index ee71599d9fc..aff6dc17923 100644 --- a/homeassistant/components/gitter/sensor.py +++ b/homeassistant/components/gitter/sensor.py @@ -98,7 +98,7 @@ class GitterSensor(Entity): _LOGGER.error(error) return - if "error" not in data.keys(): + if "error" not in data: self._mention = len(data["mention"]) self._state = len(data["chat"]) else: diff --git a/homeassistant/components/glances/translations/et.json b/homeassistant/components/glances/translations/et.json index 654196d1020..7f5e1bb63be 100644 --- a/homeassistant/components/glances/translations/et.json +++ b/homeassistant/components/glances/translations/et.json @@ -4,7 +4,8 @@ "already_configured": "Seade on juba h\u00e4\u00e4lestatud" }, "error": { - "cannot_connect": "\u00dchendamine nurjus" + "cannot_connect": "\u00dchendamine nurjus", + "wrong_version": "Versiooni ei toetata (ainult 2 v\u00f5i 3)" }, "step": { "user": { @@ -15,8 +16,20 @@ "port": "Port", "ssl": "Kasutab SSL serti", "username": "Kasutajanimi", - "verify_ssl": "Kontrolli SSL sertifikaati" - } + "verify_ssl": "Kontrolli SSL sertifikaati", + "version": "Glances API versioon (2 v\u00f5i 3)" + }, + "title": "Seadista Glances" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "scan_interval": "V\u00e4rskendussagedus" + }, + "description": "Seadista Glances valikud" } } } diff --git a/homeassistant/components/glances/translations/lb.json b/homeassistant/components/glances/translations/lb.json index 4aba9293bd9..68c6131cb5a 100644 --- a/homeassistant/components/glances/translations/lb.json +++ b/homeassistant/components/glances/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Kann sech net mam Server verbannen.", + "cannot_connect": "Feeler beim verbannen", "wrong_version": "Versioun net \u00ebnnerst\u00ebtzt (n\u00ebmmen 2 oder 3)" }, "step": { @@ -14,9 +14,9 @@ "name": "Numm", "password": "Passwuert", "port": "Port", - "ssl": "Benotzt SSL/TLS fir sech mam Usiichte System ze verbannen", + "ssl": "Benotzt ee SSLZertifikat", "username": "Benotzernumm", - "verify_ssl": "Zertifikatioun vum System iwwerpr\u00e9iwen", + "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen", "version": "API Versioun vun den Usiichten (2 oder 3)" }, "title": "Usiichten konfigur\u00e9ieren" diff --git a/homeassistant/components/glances/translations/zh-Hans.json b/homeassistant/components/glances/translations/zh-Hans.json index a5f4ff11f09..22cb2995672 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/goalzero/translations/cs.json b/homeassistant/components/goalzero/translations/cs.json index db33844a04d..4d39a29a7c3 100644 --- a/homeassistant/components/goalzero/translations/cs.json +++ b/homeassistant/components/goalzero/translations/cs.json @@ -14,6 +14,7 @@ "host": "Hostitel", "name": "Jm\u00e9no" }, + "description": "Nejprve si mus\u00edte st\u00e1hnout aplikaci Goal Zero: https://www.goalzero.com/product-features/yeti-app/ \n\nPodle pokyn\u016f p\u0159ipojte za\u0159\u00edzen\u00ed Yeti k s\u00edti Wifi. Pot\u00e9 z\u00edskejte hostitelskou IP z routeru. Aby se IP hostitele nezm\u011bnila, mus\u00ed b\u00fdt v nastaven\u00ed routeru pro za\u0159\u00edzen\u00ed nastaven DHCP. Informace nalezenete v u\u017eivatelsk\u00e9 p\u0159\u00edru\u010dce k routeru.", "title": "Goal Zero Yeti" } } diff --git a/homeassistant/components/goalzero/translations/de.json b/homeassistant/components/goalzero/translations/de.json new file mode 100644 index 00000000000..80db678f279 --- /dev/null +++ b/homeassistant/components/goalzero/translations/de.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "invalid_host": "Ung\u00fcltiger Hostname oder IP Adresse" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/goalzero/translations/fr.json b/homeassistant/components/goalzero/translations/fr.json index a155e8370d1..5c4b7a01580 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/goalzero/translations/nl.json b/homeassistant/components/goalzero/translations/nl.json index 50f6dcd1b87..86958670d70 100644 --- a/homeassistant/components/goalzero/translations/nl.json +++ b/homeassistant/components/goalzero/translations/nl.json @@ -12,7 +12,8 @@ "user": { "data": { "name": "Naam" - } + }, + "description": "Eerst moet u de Goal Zero-app downloaden: https://www.goalzero.com/product-features/yeti-app/ \n\n Volg de instructies om je Yeti te verbinden met je wifi-netwerk. Haal dan de host-ip van uw router. DHCP moet zijn ingesteld in uw routerinstellingen voor het apparaat om ervoor te zorgen dat het host-ip niet verandert. Raadpleeg de gebruikershandleiding van uw router." } } } diff --git a/homeassistant/components/gogogate2/translations/et.json b/homeassistant/components/gogogate2/translations/et.json index 5c68fd43010..b3ab67388a1 100644 --- a/homeassistant/components/gogogate2/translations/et.json +++ b/homeassistant/components/gogogate2/translations/et.json @@ -13,7 +13,9 @@ "ip_address": "IP aadress", "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "description": "Esita vajalik teave allpool.", + "title": "GogoGate2 v\u00f5i iSmartGate'i seadistamine" } } } diff --git a/homeassistant/components/gogogate2/translations/pl.json b/homeassistant/components/gogogate2/translations/pl.json index 2ea10491255..6569c444c20 100644 --- a/homeassistant/components/gogogate2/translations/pl.json +++ b/homeassistant/components/gogogate2/translations/pl.json @@ -15,7 +15,7 @@ "username": "Nazwa u\u017cytkownika" }, "description": "Wprowad\u017a wymagane informacje poni\u017cej.", - "title": "Konfiguracja GogoGate2 oraz iSmartGate" + "title": "Konfiguracja GogoGate2 lub iSmartGate" } } } diff --git a/homeassistant/components/google/calendar.py b/homeassistant/components/google/calendar.py index 8a6eb644621..6448e035171 100644 --- a/homeassistant/components/google/calendar.py +++ b/homeassistant/components/google/calendar.py @@ -156,7 +156,7 @@ class GoogleCalendarData: items = result.get("items", []) event_list = [] for item in items: - if not self.ignore_availability and "transparency" in item.keys(): + if not self.ignore_availability and "transparency" in item: if item["transparency"] == "opaque": event_list.append(item) else: @@ -178,7 +178,7 @@ class GoogleCalendarData: new_event = None for item in items: - if not self.ignore_availability and "transparency" in item.keys(): + if not self.ignore_availability and "transparency" in item: if item["transparency"] == "opaque": new_event = item break diff --git a/homeassistant/components/google_assistant/const.py b/homeassistant/components/google_assistant/const.py index 339f4ab27ab..be69f020190 100644 --- a/homeassistant/components/google_assistant/const.py +++ b/homeassistant/components/google_assistant/const.py @@ -69,7 +69,9 @@ TYPE_SCENE = f"{PREFIX_TYPES}SCENE" TYPE_FAN = f"{PREFIX_TYPES}FAN" TYPE_THERMOSTAT = f"{PREFIX_TYPES}THERMOSTAT" TYPE_LOCK = f"{PREFIX_TYPES}LOCK" +TYPE_AWNING = f"{PREFIX_TYPES}AWNING" TYPE_BLINDS = f"{PREFIX_TYPES}BLINDS" +TYPE_SHUTTER = f"{PREFIX_TYPES}SHUTTER" TYPE_GARAGE = f"{PREFIX_TYPES}GARAGE" TYPE_OUTLET = f"{PREFIX_TYPES}OUTLET" TYPE_SENSOR = f"{PREFIX_TYPES}SENSOR" @@ -137,6 +139,8 @@ DEVICE_CLASS_TO_GOOGLE_TYPES = { (cover.DOMAIN, cover.DEVICE_CLASS_GARAGE): TYPE_GARAGE, (cover.DOMAIN, cover.DEVICE_CLASS_GATE): TYPE_GARAGE, (cover.DOMAIN, cover.DEVICE_CLASS_DOOR): TYPE_DOOR, + (cover.DOMAIN, cover.DEVICE_CLASS_AWNING): TYPE_AWNING, + (cover.DOMAIN, cover.DEVICE_CLASS_SHUTTER): TYPE_SHUTTER, (switch.DOMAIN, switch.DEVICE_CLASS_SWITCH): TYPE_SWITCH, (switch.DOMAIN, switch.DEVICE_CLASS_OUTLET): TYPE_OUTLET, (binary_sensor.DOMAIN, binary_sensor.DEVICE_CLASS_DOOR): TYPE_DOOR, diff --git a/homeassistant/components/google_pubsub/manifest.json b/homeassistant/components/google_pubsub/manifest.json index c879788f2c0..717a52dd623 100644 --- a/homeassistant/components/google_pubsub/manifest.json +++ b/homeassistant/components/google_pubsub/manifest.json @@ -2,6 +2,6 @@ "domain": "google_pubsub", "name": "Google Pub/Sub", "documentation": "https://www.home-assistant.io/integrations/google_pubsub", - "requirements": ["google-cloud-pubsub==0.39.1"], + "requirements": ["google-cloud-pubsub==2.1.0"], "codeowners": [] } diff --git a/homeassistant/components/gpslogger/strings.json b/homeassistant/components/gpslogger/strings.json index b757e5c46cb..981fb49e60c 100644 --- a/homeassistant/components/gpslogger/strings.json +++ b/homeassistant/components/gpslogger/strings.json @@ -8,7 +8,7 @@ }, "abort": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from GPSLogger." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup the webhook feature in GPSLogger.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/gpslogger/translations/bg.json b/homeassistant/components/gpslogger/translations/bg.json index 56843e752c9..895cf27ee5b 100644 --- a/homeassistant/components/gpslogger/translations/bg.json +++ b/homeassistant/components/gpslogger/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 GPSLogger.", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u0441\u044a\u0431\u0438\u0442\u0438\u044f \u0434\u043e Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0442\u0430 webhook \u0432 GPSLogger. \n\n \u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: \n\n - URL: ` {webhook_url} ` \n - Method: POST \n\n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438." }, diff --git a/homeassistant/components/gpslogger/translations/ca.json b/homeassistant/components/gpslogger/translations/ca.json index 96edeea6ccb..49878948880 100644 --- a/homeassistant/components/gpslogger/translations/ca.json +++ b/homeassistant/components/gpslogger/translations/ca.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de GPSLogger.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar esdeveniments a Home Assistant, haur\u00e0s de configurar l'opci\u00f3 webhook de GPSLogger.\n\nCompleta la seg\u00fcent informaci\u00f3:\n\n- URL: `{webhook_url}` \n- M\u00e8tode: POST \n\nConsulta la [documentaci\u00f3]({docs_url}) per a m\u00e9s detalls." diff --git a/homeassistant/components/gpslogger/translations/cs.json b/homeassistant/components/gpslogger/translations/cs.json index 33cc75fda46..b94aeea3b9c 100644 --- a/homeassistant/components/gpslogger/translations/cs.json +++ b/homeassistant/components/gpslogger/translations/cs.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "not_internet_accessible": "V\u00e1\u0161 Home Asistent mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy od GPSLogger.", - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "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 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/gpslogger/translations/da.json b/homeassistant/components/gpslogger/translations/da.json index e14b3a9ceb0..4799599b5f7 100644 --- a/homeassistant/components/gpslogger/translations/da.json +++ b/homeassistant/components/gpslogger/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage GPSLogger-meddelelser.", - "one_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning" - }, "create_entry": { "default": "For at sende h\u00e6ndelser til Home Assistant skal du konfigurere webhook-funktionen i GPSLogger.\n\n Udfyld f\u00f8lgende oplysninger: \n\n - Webadresse: `{webhook_url}`\n - Metode: POST\n \nSe [dokumentationen]({docs_url}) for yderligere oplysninger." }, diff --git a/homeassistant/components/gpslogger/translations/de.json b/homeassistant/components/gpslogger/translations/de.json index 3aab63489c3..d976a5fd663 100644 --- a/homeassistant/components/gpslogger/translations/de.json +++ b/homeassistant/components/gpslogger/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Deine Home-Assistant-Instanz muss aus dem internet erreichbar sein, um Nachrichten von GPSLogger zu erhalten.", - "one_instance_allowed": "Nur eine einzige Instanz ist notwendig." - }, "create_entry": { "default": "Um Ereignisse an Home Assistant zu senden, muss das Webhook Feature in der GPSLogger konfiguriert werden.\n\n F\u00fcge die folgenden Informationen ein: \n\n - URL: ` {webhook_url} ` \n - Methode: POST \n \n Weitere Informationen finden sich in der [Dokumentation]({docs_url})." }, diff --git a/homeassistant/components/gpslogger/translations/en.json b/homeassistant/components/gpslogger/translations/en.json index 197c012ed40..6d280a4c038 100644 --- a/homeassistant/components/gpslogger/translations/en.json +++ b/homeassistant/components/gpslogger/translations/en.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from GPSLogger.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup the webhook feature in GPSLogger.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/gpslogger/translations/es-419.json b/homeassistant/components/gpslogger/translations/es-419.json index a6d855dc758..5fd775907aa 100644 --- a/homeassistant/components/gpslogger/translations/es-419.json +++ b/homeassistant/components/gpslogger/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de GPSLogger.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar eventos a Home Assistant, deber\u00e1 configurar la funci\u00f3n de webhook en GPSLogger. \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n\n Vea [la documentaci\u00f3n] ( {docs_url} ) para m\u00e1s detalles." }, diff --git a/homeassistant/components/gpslogger/translations/es.json b/homeassistant/components/gpslogger/translations/es.json index ae4a9c310b7..733871c5ee7 100644 --- a/homeassistant/components/gpslogger/translations/es.json +++ b/homeassistant/components/gpslogger/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Tu Home Assistant debe ser accesible desde Internet para recibir mensajes de GPSLogger.", - "one_instance_allowed": "S\u00f3lo se necesita una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar eventos a Home Assistant, necesitar\u00e1s configurar la funci\u00f3n de webhook en GPSLogger.\n\nRellena la siguiente informaci\u00f3n:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nEcha un vistazo a [la documentaci\u00f3n]({docs_url}) para m\u00e1s detalles." diff --git a/homeassistant/components/gpslogger/translations/et.json b/homeassistant/components/gpslogger/translations/et.json index 8e56840d74b..a84a69a3d0d 100644 --- a/homeassistant/components/gpslogger/translations/et.json +++ b/homeassistant/components/gpslogger/translations/et.json @@ -1,12 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Lubatud on ainult \u00fcks sidumine.", - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." + }, + "create_entry": { + "default": "S\u00fcndmuste saatmiseks Home Assistantile pead seadistamaGPSLogger'i veebihaagi. \n\n Sisesta j\u00e4rgmine teave: \n\n - URL: \" {webhook_url} \" \n - Meetod: POST \n \n Lisateavet leiad [documentation] ( {docs_url} )." }, "step": { "user": { - "description": "Kas soovid seadistada GPSLogger Webhooki?" + "description": "Kas soovid seadistada GPSLogger Webhooki?", + "title": "Seadista GPSLoggeri veebihaak" } } } diff --git a/homeassistant/components/gpslogger/translations/fr.json b/homeassistant/components/gpslogger/translations/fr.json index bb9321c5fcc..05f5985a8df 100644 --- a/homeassistant/components/gpslogger/translations/fr.json +++ b/homeassistant/components/gpslogger/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance Home Assistant doit \u00eatre accessible \u00e0 partir d'Internet pour recevoir les messages GPSLogger.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez configurer la fonction Webhook dans GPSLogger. \n\n Remplissez les informations suivantes: \n\n - URL: ` {webhook_url} ` \n - M\u00e9thode: POST \n\n Voir [la documentation] ( {docs_url} ) pour plus de d\u00e9tails." diff --git a/homeassistant/components/gpslogger/translations/hu.json b/homeassistant/components/gpslogger/translations/hu.json index 6080cf11c5e..4fa3678043e 100644 --- a/homeassistant/components/gpslogger/translations/hu.json +++ b/homeassistant/components/gpslogger/translations/hu.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Az Home Assistantnek el\u00e9rhet\u0151nek kell lennie az internetr\u0151l, hogy megkapja a GPSLogger \u00fczeneteit.", - "one_instance_allowed": "Csak egy p\u00e9ld\u00e1ny sz\u00fcks\u00e9ges." - }, "create_entry": { "default": "Az esem\u00e9ny Home Assistantnek val\u00f3 k\u00fcld\u00e9s\u00e9hez be kell \u00e1ll\u00edtanod a webhook funkci\u00f3t a GPSLoggerben. \n\n Az al\u00e1bbi inform\u00e1ci\u00f3kat haszn\u00e1ld: \n\n - URL: ` {webhook_url} ` \n - Method: POST \n\n Tov\u00e1bbi r\u00e9szletek a [dokument\u00e1ci\u00f3] ( {docs_url} ) linken tal\u00e1lhat\u00f3k." }, diff --git a/homeassistant/components/gpslogger/translations/it.json b/homeassistant/components/gpslogger/translations/it.json index dac92f90262..1ad8589583f 100644 --- a/homeassistant/components/gpslogger/translations/it.json +++ b/homeassistant/components/gpslogger/translations/it.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi da GPSLogger.", - "one_instance_allowed": "\u00c8 necessaria una sola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare eventi a Home Assistant, dovrai configurare la funzionalit\u00e0 webhook in GPSLogger.\n\n Compila le seguenti informazioni: \n\n - URL: `{webhook_url}` \n - Method: POST \n\n Vedi [la documentazione]({docs_url}) for ulteriori dettagli." diff --git a/homeassistant/components/gpslogger/translations/ko.json b/homeassistant/components/gpslogger/translations/ko.json index 3c010cb65b9..a6d95a0e51b 100644 --- a/homeassistant/components/gpslogger/translations/ko.json +++ b/homeassistant/components/gpslogger/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "GPSLogger \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\ub824\uba74 GPSLogger \uc5d0\uc11c \uc6f9 \ud6c5\uc744 \uc124\uc815\ud574\uc57c\ud569\ub2c8\ub2e4. \n\n\ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694:\n\n - URL: `{webhook_url}`\n - Method: POST\n \n \uc790\uc138\ud55c \uc815\ubcf4\ub294 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/gpslogger/translations/lb.json b/homeassistant/components/gpslogger/translations/lb.json index 2e4362b18e2..b3b137544f3 100644 --- a/homeassistant/components/gpslogger/translations/lb.json +++ b/homeassistant/components/gpslogger/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir GPSLogger Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { diff --git a/homeassistant/components/gpslogger/translations/nl.json b/homeassistant/components/gpslogger/translations/nl.json index 34b9739707b..dbf7f47a2e9 100644 --- a/homeassistant/components/gpslogger/translations/nl.json +++ b/homeassistant/components/gpslogger/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Uw Home Assistant-instantie moet via internet toegankelijk zijn om berichten van GPSLogger te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/gpslogger/translations/no.json b/homeassistant/components/gpslogger/translations/no.json index f940330d4e6..655cfa38418 100644 --- a/homeassistant/components/gpslogger/translations/no.json +++ b/homeassistant/components/gpslogger/translations/no.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta meldinger fra GPSLogger.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du sette opp webhook-funksjonen i GPSLogger. \n\n Fyll ut f\u00f8lgende informasjon: \n\n - URL: `{webhook_url}` \n - Metode: POST \n\n Se [dokumentasjonen]({docs_url}) for ytterligere detaljer." diff --git a/homeassistant/components/gpslogger/translations/pl.json b/homeassistant/components/gpslogger/translations/pl.json index 8d17896ceeb..a7f40dbeb9f 100644 --- a/homeassistant/components/gpslogger/translations/pl.json +++ b/homeassistant/components/gpslogger/translations/pl.json @@ -1,17 +1,16 @@ { "config": { "abort": { - "not_internet_accessible": "Twoja instancja Home Assistant musi by\u0107 dost\u0119pna z Internetu, aby otrzymywa\u0107 wiadomo\u015bci z GPSlogger", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 lokalizacje do Home Assistant, musisz skonfigurowa\u0107 webhook w aplikacji GPSLogger. \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}), by pozna\u0107 szczeg\u00f3\u0142y." }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 Geofency?", - "title": "Konfiguracja Geofency Webhook" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", + "title": "Konfiguracja GPSLogger Webhook" } } } diff --git a/homeassistant/components/gpslogger/translations/pt-BR.json b/homeassistant/components/gpslogger/translations/pt-BR.json index 6362914f52a..fe07d42744e 100644 --- a/homeassistant/components/gpslogger/translations/pt-BR.json +++ b/homeassistant/components/gpslogger/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia do Home Assistant precisa estar acess\u00edvel na Internet para receber mensagens do GPSLogger.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, voc\u00ea precisar\u00e1 configurar o recurso webhook no GPSLogger. \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n\n Veja [a documenta\u00e7\u00e3o] ( {docs_url} ) para mais detalhes." }, diff --git a/homeassistant/components/gpslogger/translations/pt.json b/homeassistant/components/gpslogger/translations/pt.json index de430273ba5..8602afcabfe 100644 --- a/homeassistant/components/gpslogger/translations/pt.json +++ b/homeassistant/components/gpslogger/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A sua inst\u00e2ncia Home Assistent precisa de ser acess\u00edvel a partir da internet para receber mensagens GPSlogger.", - "one_instance_allowed": "Apenas uma inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, \u00e9 necess\u00e1rio configurar um webhook no GPslogger. \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: `{webhook_url}`\n - M\u00e9todo: POST \n\n Veja [the documentation]({docs_url}) para obter mais detalhes." }, diff --git a/homeassistant/components/gpslogger/translations/ru.json b/homeassistant/components/gpslogger/translations/ru.json index bfa6a4850b3..31b7759d2cb 100644 --- a/homeassistant/components/gpslogger/translations/ru.json +++ b/homeassistant/components/gpslogger/translations/ru.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 GPSLogger.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Webhook \u0434\u043b\u044f GPSLogger.\n\n\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\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 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438." diff --git a/homeassistant/components/gpslogger/translations/sl.json b/homeassistant/components/gpslogger/translations/sl.json index 1d33f450699..2c300465e74 100644 --- a/homeassistant/components/gpslogger/translations/sl.json +++ b/homeassistant/components/gpslogger/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Va\u0161 Home Assistant mora biti dostopek prek interneta, da boste lahko prejemali GPSlogger sporo\u010dila.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "\u010ce \u017eelite dogodke poslati v Home Assistant, morate v GPSLoggerju nastaviti funkcijo webhook. \n\n Izpolnite naslednje podatke: \n\n - URL: ` {webhook_url} ` \n - Metoda: POST \n\n Za ve\u010d podrobnosti si oglejte [dokumentacijo] ( {docs_url} )." }, diff --git a/homeassistant/components/gpslogger/translations/sv.json b/homeassistant/components/gpslogger/translations/sv.json index db53fcff973..40b54557d80 100644 --- a/homeassistant/components/gpslogger/translations/sv.json +++ b/homeassistant/components/gpslogger/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant instans m\u00e5ste vara \u00e5tkomlig ifr\u00e5n internet f\u00f6r att ta emot meddelanden ifr\u00e5n GPSLogger.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du konfigurera webhook funktionen i GPSLogger.\n\n Fyll i f\u00f6ljande information:\n \n- URL: `{webhook_url}`\n- Method: POST\n\nSe [dokumentation]({docs_url}) om hur du konfigurerar detta f\u00f6r mer information." }, diff --git a/homeassistant/components/gpslogger/translations/zh-Hans.json b/homeassistant/components/gpslogger/translations/zh-Hans.json index f6934cb5e4f..343acd4b5d9 100644 --- a/homeassistant/components/gpslogger/translations/zh-Hans.json +++ b/homeassistant/components/gpslogger/translations/zh-Hans.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u53ef\u4ece\u4e92\u8054\u7f51\u8bbf\u95ee\u4ee5\u63a5\u6536 GPSLogger \u6d88\u606f\u3002", - "one_instance_allowed": "\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u662f\u5fc5\u9700\u7684\u3002" - }, "create_entry": { "default": "\u8981\u5411 Home Assistant \u53d1\u9001\u4e8b\u4ef6\uff0c\u60a8\u9700\u8981\u914d\u7f6e GPSLogger \u7684 Webhook \u529f\u80fd\u3002\n\n\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\u8bf7\u53c2\u9605[\u6587\u6863]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u591a\u4fe1\u606f\u3002" }, diff --git a/homeassistant/components/gpslogger/translations/zh-Hant.json b/homeassistant/components/gpslogger/translations/zh-Hant.json index 59aa99d1689..324a92cd8b5 100644 --- a/homeassistant/components/gpslogger/translations/zh-Hant.json +++ b/homeassistant/components/gpslogger/translations/zh-Hant.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u8a2d\u5099\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 GPSLogger \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u65bc GPSLogger \u5167\u8a2d\u5b9a webhook \u529f\u80fd\u3002\n\n\u8acb\u586b\u5beb\u4e0b\u5217\u8cc7\u8a0a\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\u8acb\u53c3\u95b1 [\u6587\u4ef6]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u8a73\u7d30\u8cc7\u6599\u3002" diff --git a/homeassistant/components/gree/manifest.json b/homeassistant/components/gree/manifest.json index 3480d84d97f..0d2bed3ff28 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.5"], + "requirements": ["greeclimate==0.10.3"], "codeowners": ["@cmroche"] } \ No newline at end of file diff --git a/homeassistant/components/gree/strings.json b/homeassistant/components/gree/strings.json index 878ebc3bbd7..ad8f0f41ae7 100644 --- a/homeassistant/components/gree/strings.json +++ b/homeassistant/components/gree/strings.json @@ -1,5 +1,4 @@ { - "title": "Gree Climate", "config": { "step": { "confirm": { diff --git a/homeassistant/components/gree/translations/ca.json b/homeassistant/components/gree/translations/ca.json index 88c94cfe41b..dc21c371e60 100644 --- a/homeassistant/components/gree/translations/ca.json +++ b/homeassistant/components/gree/translations/ca.json @@ -9,6 +9,5 @@ "description": "Vols comen\u00e7ar la configuraci\u00f3?" } } - }, - "title": "Gree Climate" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/cs.json b/homeassistant/components/gree/translations/cs.json index fdc367097eb..d3f0e37a132 100644 --- a/homeassistant/components/gree/translations/cs.json +++ b/homeassistant/components/gree/translations/cs.json @@ -9,6 +9,5 @@ "description": "Chcete za\u010d\u00edt nastavovat?" } } - }, - "title": "Gree Climate" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/en.json b/homeassistant/components/gree/translations/en.json index 996292cde3f..f05becffed3 100644 --- a/homeassistant/components/gree/translations/en.json +++ b/homeassistant/components/gree/translations/en.json @@ -9,6 +9,5 @@ "description": "Do you want to start set up?" } } - }, - "title": "Gree Climate" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/es.json b/homeassistant/components/gree/translations/es.json index 2a6d217e5e5..520df7ee4cd 100644 --- a/homeassistant/components/gree/translations/es.json +++ b/homeassistant/components/gree/translations/es.json @@ -9,6 +9,5 @@ "description": "\u00bfQuieres iniciar la configuraci\u00f3n?" } } - }, - "title": "Gree Climate" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/et.json b/homeassistant/components/gree/translations/et.json index d10de355646..5435f98eb2e 100644 --- a/homeassistant/components/gree/translations/et.json +++ b/homeassistant/components/gree/translations/et.json @@ -2,13 +2,12 @@ "config": { "abort": { "no_devices_found": "V\u00f5rgust ei leitud seadmeid", - "single_instance_allowed": "Seade on juba lisatud. Lubatud on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "step": { "confirm": { "description": "Kas alustan Gree seadistamist?" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/fr.json b/homeassistant/components/gree/translations/fr.json new file mode 100644 index 00000000000..e9ae4e0b644 --- /dev/null +++ b/homeassistant/components/gree/translations/fr.json @@ -0,0 +1,13 @@ +{ + "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 ?" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/gree/translations/it.json b/homeassistant/components/gree/translations/it.json index 5bb4f9a3ee9..0278fe07bfe 100644 --- a/homeassistant/components/gree/translations/it.json +++ b/homeassistant/components/gree/translations/it.json @@ -9,6 +9,5 @@ "description": "Vuoi iniziare la configurazione?" } } - }, - "title": "Gree Climate" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/lb.json b/homeassistant/components/gree/translations/lb.json new file mode 100644 index 00000000000..4ea09574c0b --- /dev/null +++ b/homeassistant/components/gree/translations/lb.json @@ -0,0 +1,13 @@ +{ + "config": { + "abort": { + "no_devices_found": "Keng Apparater am Netzwierk fonnt", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." + }, + "step": { + "confirm": { + "description": "Soll den Ariichtungs Prozess gestart ginn?" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/gree/translations/no.json b/homeassistant/components/gree/translations/no.json index 602a81af2f5..b3d6b5d782e 100644 --- a/homeassistant/components/gree/translations/no.json +++ b/homeassistant/components/gree/translations/no.json @@ -9,6 +9,5 @@ "description": "Vil du starte oppsettet?" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/pl.json b/homeassistant/components/gree/translations/pl.json index b754e529248..a8ee3fa57ac 100644 --- a/homeassistant/components/gree/translations/pl.json +++ b/homeassistant/components/gree/translations/pl.json @@ -9,6 +9,5 @@ "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } - }, - "title": "Klimatyzacja Gree" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/ru.json b/homeassistant/components/gree/translations/ru.json index ee7bf509773..85a42bf1be5 100644 --- a/homeassistant/components/gree/translations/ru.json +++ b/homeassistant/components/gree/translations/ru.json @@ -9,6 +9,5 @@ "description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443?" } } - }, - "title": "Gree Climate" + } } \ No newline at end of file diff --git a/homeassistant/components/gree/translations/zh-Hans.json b/homeassistant/components/gree/translations/zh-Hans.json deleted file mode 100644 index c6d2c4c7cfb..00000000000 --- a/homeassistant/components/gree/translations/zh-Hans.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "\u683c\u529b\u7a7a\u8c03" -} \ No newline at end of file diff --git a/homeassistant/components/gree/translations/zh-Hant.json b/homeassistant/components/gree/translations/zh-Hant.json index 138912467bd..91a0dc60be7 100644 --- a/homeassistant/components/gree/translations/zh-Hant.json +++ b/homeassistant/components/gree/translations/zh-Hant.json @@ -9,6 +9,5 @@ "description": "\u662f\u5426\u8981\u958b\u59cb\u8a2d\u5b9a\uff1f" } } - }, - "title": "\u683c\u529b\u6eab\u63a7" + } } \ No newline at end of file diff --git a/homeassistant/components/griddy/translations/et.json b/homeassistant/components/griddy/translations/et.json index 0f7df7bd156..82d2232b04e 100644 --- a/homeassistant/components/griddy/translations/et.json +++ b/homeassistant/components/griddy/translations/et.json @@ -6,6 +6,15 @@ "error": { "cannot_connect": "\u00dchendamine nurjus", "unknown": "Tundmatu viga" + }, + "step": { + "user": { + "data": { + "loadzone": "Load Zone (arvelduspunkt)" + }, + "description": "Load Zone asub Griddy konto valikutes \u201cAccount > Meter > Load Zone.\u201d", + "title": "Seadista oma Griddy Load Zone" + } } } } \ No newline at end of file diff --git a/homeassistant/components/griddy/translations/lb.json b/homeassistant/components/griddy/translations/lb.json index 2e2458cb8ed..84511186f88 100644 --- a/homeassistant/components/griddy/translations/lb.json +++ b/homeassistant/components/griddy/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "D\u00ebs Lued Zon ass scho konfigur\u00e9iert" + "already_configured": "Standuert ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9iert w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "unknown": "Onerwaarte Feeler" }, "step": { diff --git a/homeassistant/components/griddy/translations/nl.json b/homeassistant/components/griddy/translations/nl.json index 9227d4702ab..bd97b9ccf7c 100644 --- a/homeassistant/components/griddy/translations/nl.json +++ b/homeassistant/components/griddy/translations/nl.json @@ -9,6 +9,9 @@ }, "step": { "user": { + "data": { + "loadzone": "Laadzone (vestigingspunt)" + }, "description": "Uw Load Zone staat op uw Griddy account onder \"Account > Meter > Load Zone\".", "title": "Stel uw Griddy Load Zone in" } diff --git a/homeassistant/components/griddy/translations/pl.json b/homeassistant/components/griddy/translations/pl.json index 40b2c88803a..035521336f6 100644 --- a/homeassistant/components/griddy/translations/pl.json +++ b/homeassistant/components/griddy/translations/pl.json @@ -13,7 +13,7 @@ "loadzone": "Strefa obci\u0105\u017cenia (punkt rozliczenia)" }, "description": "Twoja strefa obci\u0105\u017cenia znajduje si\u0119 na twoim koncie Griddy w sekcji \"Konto > Licznik > Strefa obci\u0105\u017cenia\".", - "title": "Konfigurowanie strefy obci\u0105\u017cenia Griddy" + "title": "Konfiguracja strefy obci\u0105\u017cenia Griddy" } } } diff --git a/homeassistant/components/group/translations/pl.json b/homeassistant/components/group/translations/pl.json index ce231ebaad9..b45f3f85cfb 100644 --- a/homeassistant/components/group/translations/pl.json +++ b/homeassistant/components/group/translations/pl.json @@ -3,14 +3,14 @@ "_": { "closed": "zamkni\u0119te", "home": "w domu", - "locked": "Zablokowane", + "locked": "zamkni\u0119te", "not_home": "poza domem", "off": "wy\u0142.", "ok": "ok", "on": "w\u0142.", "open": "otwarte", "problem": "problem", - "unlocked": "Odblokowany" + "unlocked": "otwarte" } }, "title": "Grupa" diff --git a/homeassistant/components/group/translations/tr.json b/homeassistant/components/group/translations/tr.json index 5a596efdf01..f92785a737f 100644 --- a/homeassistant/components/group/translations/tr.json +++ b/homeassistant/components/group/translations/tr.json @@ -2,9 +2,9 @@ "state": { "_": { "closed": "Kapand\u0131", - "home": "Evde", + "home": "[%key:common::state::evde%]", "locked": "Kilitli", - "not_home": "D\u0131\u015far\u0131da", + "not_home": "[%key:common::state::evde_degil%]", "off": "Kapal\u0131", "ok": "Tamam", "on": "A\u00e7\u0131k", diff --git a/homeassistant/components/guardian/manifest.json b/homeassistant/components/guardian/manifest.json index 6d69597a065..f1fa9c73e5d 100644 --- a/homeassistant/components/guardian/manifest.json +++ b/homeassistant/components/guardian/manifest.json @@ -4,14 +4,12 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/guardian", "requirements": [ - "aioguardian==1.0.1" + "aioguardian==1.0.4" ], - "ssdp": [], "zeroconf": [ "_api._udp.local." ], "homekit": {}, - "dependencies": [], "codeowners": [ "@bachya" ] diff --git a/homeassistant/components/guardian/strings.json b/homeassistant/components/guardian/strings.json index 47abe35037d..59c838c7e2d 100644 --- a/homeassistant/components/guardian/strings.json +++ b/homeassistant/components/guardian/strings.json @@ -1,5 +1,4 @@ { - "title": "Elexa Guardian", "config": { "step": { "user": { diff --git a/homeassistant/components/guardian/translations/ca.json b/homeassistant/components/guardian/translations/ca.json index 207242e32c3..476bf49ee5a 100644 --- a/homeassistant/components/guardian/translations/ca.json +++ b/homeassistant/components/guardian/translations/ca.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", "already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs", - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar amb el dispositiu Guardian." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "Vols configurar aquest dispositiu Guardian?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/cs.json b/homeassistant/components/guardian/translations/cs.json index 084dbf1a728..cb5ee7ef102 100644 --- a/homeassistant/components/guardian/translations/cs.json +++ b/homeassistant/components/guardian/translations/cs.json @@ -3,20 +3,19 @@ "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed Guardian se nezda\u0159ilo." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "user": { "data": { "ip_address": "IP adresa", "port": "Port" - } + }, + "description": "Nastate m\u00edstn\u00ed za\u0159\u00edzen\u00ed Elexa Guardian." }, "zeroconf_confirm": { "description": "Chcete nastavit toto za\u0159\u00edzen\u00ed Guardian?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/de.json b/homeassistant/components/guardian/translations/de.json index d148ab8c382..7407782bc3f 100644 --- a/homeassistant/components/guardian/translations/de.json +++ b/homeassistant/components/guardian/translations/de.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "connection_error": "Verbindung zum Guardian-Ger\u00e4t fehlgeschlagen." + "already_configured": "Ger\u00e4t ist bereits konfiguriert" }, "step": { "user": { @@ -11,6 +11,5 @@ } } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/en.json b/homeassistant/components/guardian/translations/en.json index 2e47f4d28aa..3b038935662 100644 --- a/homeassistant/components/guardian/translations/en.json +++ b/homeassistant/components/guardian/translations/en.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Device is already configured", "already_in_progress": "Configuration flow is already in progress", - "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect to the Guardian device." + "cannot_connect": "Failed to connect" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "Do you want to set up this Guardian device?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/es.json b/homeassistant/components/guardian/translations/es.json index 657261f213e..9e6cfdaa7c7 100644 --- a/homeassistant/components/guardian/translations/es.json +++ b/homeassistant/components/guardian/translations/es.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Este dispositivo Guardian ya ha sido configurado", "already_in_progress": "La configuraci\u00f3n del dispositivo Guardian ya est\u00e1 en proceso.", - "cannot_connect": "No se pudo conectar", - "connection_error": "No se ha podido conectar con el dispositivo Guardian." + "cannot_connect": "No se pudo conectar" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "\u00bfQuieres configurar este dispositivo Guardian?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/et.json b/homeassistant/components/guardian/translations/et.json index 93df5eb12d2..42c425ec85f 100644 --- a/homeassistant/components/guardian/translations/et.json +++ b/homeassistant/components/guardian/translations/et.json @@ -3,20 +3,19 @@ "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", "already_in_progress": "Seadistamine on juba k\u00e4imas", - "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "Guardian seadmega \u00fchenduse loomine nurjus." + "cannot_connect": "\u00dchendamine nurjus" }, "step": { "user": { "data": { "ip_address": "IP aadress", "port": "" - } + }, + "description": "Seadista kohalik Elexa Guardiani seade." }, "zeroconf_confirm": { "description": "Kas soovid seadistada seda Guardian'i seadet?" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/fr.json b/homeassistant/components/guardian/translations/fr.json index 427c34e6ca1..ca5635a17b7 100644 --- a/homeassistant/components/guardian/translations/fr.json +++ b/homeassistant/components/guardian/translations/fr.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Ce p\u00e9riph\u00e9rique Guardian a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9.", "already_in_progress": "La configuration de l'appareil Guardian est d\u00e9j\u00e0 en cours.", - "cannot_connect": "\u00c9chec de connexion", - "connection_error": "Impossible de se connecter au p\u00e9riph\u00e9rique Guardian." + "cannot_connect": "\u00c9chec de connexion" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "Voulez-vous configurer cet appareil Guardian?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/it.json b/homeassistant/components/guardian/translations/it.json index 24647fff40e..5cd20f78a3f 100644 --- a/homeassistant/components/guardian/translations/it.json +++ b/homeassistant/components/guardian/translations/it.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso", - "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi al dispositivo Guardian." + "cannot_connect": "Impossibile connettersi" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "Vuoi configurare questo dispositivo Guardian?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/ko.json b/homeassistant/components/guardian/translations/ko.json index 4580fba76d1..da40b674009 100644 --- a/homeassistant/components/guardian/translations/ko.json +++ b/homeassistant/components/guardian/translations/ko.json @@ -2,8 +2,7 @@ "config": { "abort": { "already_configured": "\uc774 Guardian \uae30\uae30\ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "already_in_progress": "Guardian \uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4.", - "connection_error": "Guardian \uae30\uae30\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." + "already_in_progress": "Guardian \uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4." }, "step": { "user": { @@ -17,6 +16,5 @@ "description": "\uc774 Guardian \uae30\uae30\ub97c \uc124\uc815\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/lb.json b/homeassistant/components/guardian/translations/lb.json index f1bf72b9d0c..8d062eb8cf7 100644 --- a/homeassistant/components/guardian/translations/lb.json +++ b/homeassistant/components/guardian/translations/lb.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Apparat ass scho konfigur\u00e9iert.", "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaang.", - "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen mam Guardian Apparat." + "cannot_connect": "Feeler beim verbannen" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "Soll d\u00ebsen Guardian Apparat konfigur\u00e9iert ginn?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/nl.json b/homeassistant/components/guardian/translations/nl.json index 69a69cf9c60..959a847a7cf 100644 --- a/homeassistant/components/guardian/translations/nl.json +++ b/homeassistant/components/guardian/translations/nl.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Dit Guardian-apparaat is al geconfigureerd.", "already_in_progress": "De configuratie van het Guardian-apparaat is al bezig.", - "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met het Guardian-apparaat." + "cannot_connect": "Kan geen verbinding maken" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "Wilt u dit Guardian-apparaat instellen?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/no.json b/homeassistant/components/guardian/translations/no.json index e1904e11091..18410f382ca 100644 --- a/homeassistant/components/guardian/translations/no.json +++ b/homeassistant/components/guardian/translations/no.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Enheten er allerede konfigurert", "already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede", - "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kan ikke koble til Guardian-enheten." + "cannot_connect": "Tilkobling mislyktes" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "Vil du konfigurere denne Guardian-enheten?" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/pl.json b/homeassistant/components/guardian/translations/pl.json index 2c5a4370abd..7dfa4b06c5b 100644 --- a/homeassistant/components/guardian/translations/pl.json +++ b/homeassistant/components/guardian/translations/pl.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "already_in_progress": "Konfiguracja jest ju\u017c w toku", - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z urz\u0105dzeniem Guardian" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "Czy chcesz skonfigurowa\u0107 to urz\u0105dzenie Guardian?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/ru.json b/homeassistant/components/guardian/translations/ru.json index 36eefd1a4cd..20e1710f120 100644 --- a/homeassistant/components/guardian/translations/ru.json +++ b/homeassistant/components/guardian/translations/ru.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.", - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u044d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e Elexa Guardian?" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/guardian/translations/zh-Hant.json b/homeassistant/components/guardian/translations/zh-Hant.json index 1b0ca0090d9..e40cef4f940 100644 --- a/homeassistant/components/guardian/translations/zh-Hant.json +++ b/homeassistant/components/guardian/translations/zh-Hant.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d", - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "Guardian \u8a2d\u5099\u9023\u7dda\u5931\u6557\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "user": { @@ -18,6 +17,5 @@ "description": "\u662f\u5426\u8981\u8a2d\u5b9a Guardian \u8a2d\u5099\uff1f" } } - }, - "title": "Elexa Guardian" + } } \ No newline at end of file diff --git a/homeassistant/components/hangouts/translations/et.json b/homeassistant/components/hangouts/translations/et.json index c5b1ff734b4..a587edcd632 100644 --- a/homeassistant/components/hangouts/translations/et.json +++ b/homeassistant/components/hangouts/translations/et.json @@ -14,13 +14,16 @@ "data": { "2fa": "2FA PIN" }, + "description": "", "title": "Kaheastmeline autentimine" }, "user": { "data": { + "authorization_code": "Autoriseerimiskood (vajalik k\u00e4sitsi autentimiseks)", "email": "E-posti aadress", "password": "Salas\u00f5na" }, + "description": "", "title": "Google Hangoutsi sisselogimine" } } diff --git a/homeassistant/components/hangouts/translations/lb.json b/homeassistant/components/hangouts/translations/lb.json index de50fda49a1..a91f2e7b040 100644 --- a/homeassistant/components/hangouts/translations/lb.json +++ b/homeassistant/components/hangouts/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "already_configured": "Google Hangouts ass scho konfigur\u00e9iert", - "unknown": "Onbekannten Feeler opgetrueden" + "already_configured": "Service ass scho konfigur\u00e9iert", + "unknown": "Onerwaarte Feeler" }, "error": { "invalid_2fa": "Ong\u00eblteg 2-Faktor Authentifikatioun, prob\u00e9iert w.e.g. nach emol.", diff --git a/homeassistant/components/harmony/translations/ca.json b/homeassistant/components/harmony/translations/ca.json index 8111fe3b344..7257ddb450d 100644 --- a/homeassistant/components/harmony/translations/ca.json +++ b/homeassistant/components/harmony/translations/ca.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "El dispositiu ja est\u00e0 configurat", - "already_configured_device": "El dispositiu ja est\u00e0 configurat" + "already_configured": "El dispositiu ja est\u00e0 configurat" }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", diff --git a/homeassistant/components/harmony/translations/cs.json b/homeassistant/components/harmony/translations/cs.json index 4ff689252ff..5c4dcabb0e4 100644 --- a/homeassistant/components/harmony/translations/cs.json +++ b/homeassistant/components/harmony/translations/cs.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "already_configured_device": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" + "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", @@ -18,5 +17,15 @@ } } } + }, + "options": { + "step": { + "init": { + "data": { + "activity": "V\u00fdchoz\u00ed aktivita, kter\u00e1 se m\u00e1 prov\u00e9st, kdy\u017e nen\u00ed nic zad\u00e1no.", + "delay_secs": "P\u0159est\u00e1vka mezi odesl\u00e1n\u00edm p\u0159\u00edkaz\u016f." + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/harmony/translations/en.json b/homeassistant/components/harmony/translations/en.json index 8843d741154..0e4243ae49c 100644 --- a/homeassistant/components/harmony/translations/en.json +++ b/homeassistant/components/harmony/translations/en.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Device is already configured", - "already_configured_device": "Device is already configured" + "already_configured": "Device is already configured" }, "error": { "cannot_connect": "Failed to connect", diff --git a/homeassistant/components/harmony/translations/es.json b/homeassistant/components/harmony/translations/es.json index ffd165e5d7a..39305d30680 100644 --- a/homeassistant/components/harmony/translations/es.json +++ b/homeassistant/components/harmony/translations/es.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "El dispositivo ya est\u00e1 configurado", - "already_configured_device": "El dispositivo ya est\u00e1 configurado" + "already_configured": "El dispositivo ya est\u00e1 configurado" }, "error": { "cannot_connect": "No se ha podido conectar, por favor, int\u00e9ntalo de nuevo", diff --git a/homeassistant/components/harmony/translations/et.json b/homeassistant/components/harmony/translations/et.json index 01736201773..86128243014 100644 --- a/homeassistant/components/harmony/translations/et.json +++ b/homeassistant/components/harmony/translations/et.json @@ -1,21 +1,35 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "already_configured_device": "Seade on juba h\u00e4\u00e4letatud" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud" }, "error": { "cannot_connect": "\u00dchenduse loomine nurjus. Proovi uuesti", "unknown": "Ootamatu t\u00f5rge" }, + "flow_title": "", "step": { "link": { - "description": "Kas soovid seadistada {name}({host})?" + "description": "Kas soovid seadistada {name}({host})?", + "title": "Logitech Harmony keskuse seadistamine" }, "user": { "data": { - "host": "" - } + "host": "", + "name": "L\u00fc\u00fcsi nimi" + }, + "title": "Logitech Harmony keskuse seadistamine" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "activity": "Vaiketegevus, mis k\u00e4ivitatakse, kui \u00fchtegi ei ole m\u00e4\u00e4ratud.", + "delay_secs": "Viivitus k\u00e4skude saatmise vahel." + }, + "description": "Kohanda Harmony Hub'i valikuid" } } } diff --git a/homeassistant/components/harmony/translations/fr.json b/homeassistant/components/harmony/translations/fr.json index ed838ed0115..4343ec3139d 100644 --- a/homeassistant/components/harmony/translations/fr.json +++ b/homeassistant/components/harmony/translations/fr.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", - "already_configured_device": "L'appareil est d\u00e9j\u00e0 configur\u00e9" + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" }, "error": { "cannot_connect": "Impossible de se connecter, veuillez r\u00e9essayer", diff --git a/homeassistant/components/harmony/translations/it.json b/homeassistant/components/harmony/translations/it.json index ea28a617ff3..3bc46a83b3a 100644 --- a/homeassistant/components/harmony/translations/it.json +++ b/homeassistant/components/harmony/translations/it.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "already_configured_device": "Il dispositivo \u00e8 gi\u00e0 configurato" + "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato" }, "error": { "cannot_connect": "Impossibile connettersi", diff --git a/homeassistant/components/harmony/translations/lb.json b/homeassistant/components/harmony/translations/lb.json index 91932fa3a04..aebe8e2c7c6 100644 --- a/homeassistant/components/harmony/translations/lb.json +++ b/homeassistant/components/harmony/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "unknown": "Onerwaarte Feeler" }, "flow_title": "Logitech Harmony Hub {name}", diff --git a/homeassistant/components/harmony/translations/no.json b/homeassistant/components/harmony/translations/no.json index eca9136205c..aeeb5ae3c84 100644 --- a/homeassistant/components/harmony/translations/no.json +++ b/homeassistant/components/harmony/translations/no.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Enheten er allerede konfigurert", - "already_configured_device": "Enheten er allerede konfigurert" + "already_configured": "Enheten er allerede konfigurert" }, "error": { "cannot_connect": "Tilkobling mislyktes", diff --git a/homeassistant/components/harmony/translations/pl.json b/homeassistant/components/harmony/translations/pl.json index 17dd1f2418e..0a288b0ce07 100644 --- a/homeassistant/components/harmony/translations/pl.json +++ b/homeassistant/components/harmony/translations/pl.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "already_configured_device": "Urz\u0105dzenie jest ju\u017c skonfigurowane" + "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", diff --git a/homeassistant/components/harmony/translations/ru.json b/homeassistant/components/harmony/translations/ru.json index e7ff5241a12..5dfcff7091d 100644 --- a/homeassistant/components/harmony/translations/ru.json +++ b/homeassistant/components/harmony/translations/ru.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "already_configured_device": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." + "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", diff --git a/homeassistant/components/harmony/translations/zh-Hant.json b/homeassistant/components/harmony/translations/zh-Hant.json index 01af1b23af7..4ab79dd603a 100644 --- a/homeassistant/components/harmony/translations/zh-Hant.json +++ b/homeassistant/components/harmony/translations/zh-Hant.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "already_configured_device": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", diff --git a/homeassistant/components/hassio/__init__.py b/homeassistant/components/hassio/__init__.py index 2e50207fe53..6484c85b95e 100644 --- a/homeassistant/components/hassio/__init__.py +++ b/homeassistant/components/hassio/__init__.py @@ -42,9 +42,11 @@ CONFIG_SCHEMA = vol.Schema( ) -DATA_INFO = "hassio_info" -DATA_HOST_INFO = "hassio_host_info" DATA_CORE_INFO = "hassio_core_info" +DATA_HOST_INFO = "hassio_host_info" +DATA_INFO = "hassio_info" +DATA_OS_INFO = "hassio_os_info" +DATA_SUPERVISOR_INFO = "hassio_supervisor_info" HASSIO_UPDATE_INTERVAL = timedelta(minutes=55) SERVICE_ADDON_START = "addon_start" @@ -145,7 +147,7 @@ async def async_install_addon(hass: HomeAssistantType, slug: str) -> dict: """ hassio = hass.data[DOMAIN] command = f"/addons/{slug}/install" - return await hassio.send_command(command) + return await hassio.send_command(command, timeout=None) @bind_hass @@ -169,7 +171,7 @@ async def async_start_addon(hass: HomeAssistantType, slug: str) -> dict: """ hassio = hass.data[DOMAIN] command = f"/addons/{slug}/start" - return await hassio.send_command(command) + return await hassio.send_command(command, timeout=60) @bind_hass @@ -218,6 +220,26 @@ def get_host_info(hass): return hass.data.get(DATA_HOST_INFO) +@callback +@bind_hass +def get_supervisor_info(hass): + """Return Supervisor information. + + Async friendly. + """ + return hass.data.get(DATA_SUPERVISOR_INFO) + + +@callback +@bind_hass +def get_os_info(hass): + """Return OS information. + + Async friendly. + """ + return hass.data.get(DATA_OS_INFO) + + @callback @bind_hass def get_core_info(hass): @@ -358,6 +380,8 @@ async def async_setup(hass, config): hass.data[DATA_INFO] = await hassio.get_info() hass.data[DATA_HOST_INFO] = await hassio.get_host_info() hass.data[DATA_CORE_INFO] = await hassio.get_core_info() + hass.data[DATA_SUPERVISOR_INFO] = await hassio.get_supervisor_info() + hass.data[DATA_OS_INFO] = await hassio.get_os_info() except HassioAPIError as err: _LOGGER.warning("Can't read last version: %s", err) diff --git a/homeassistant/components/hassio/handler.py b/homeassistant/components/hassio/handler.py index 58dd9db6623..6bc3cb345a5 100644 --- a/homeassistant/components/hassio/handler.py +++ b/homeassistant/components/hassio/handler.py @@ -82,6 +82,14 @@ class HassIO: """ return self.send_command("/host/info", method="get") + @api_data + def get_os_info(self): + """Return data for the OS. + + This method return a coroutine. + """ + return self.send_command("/os/info", method="get") + @api_data def get_core_info(self): """Return data for Home Asssistant Core. @@ -90,6 +98,14 @@ class HassIO: """ return self.send_command("/core/info", method="get") + @api_data + def get_supervisor_info(self): + """Return data for the Supervisor. + + This method returns a coroutine. + """ + return self.send_command("/supervisor/info", method="get") + @api_data def get_addon_info(self, addon): """Return data for a Add-on. diff --git a/homeassistant/components/hassio/manifest.json b/homeassistant/components/hassio/manifest.json index bc215932aa8..ba969a4af3a 100644 --- a/homeassistant/components/hassio/manifest.json +++ b/homeassistant/components/hassio/manifest.json @@ -1,8 +1,8 @@ { "domain": "hassio", - "name": "Hass.io", + "name": "Home Assistant Supervisor", "documentation": "https://www.home-assistant.io/hassio", "dependencies": ["http"], "after_dependencies": ["panel_custom"], - "codeowners": ["@home-assistant/hass-io"] + "codeowners": ["@home-assistant/supervisor"] } diff --git a/homeassistant/components/hassio/services.yaml b/homeassistant/components/hassio/services.yaml index 30314c646b0..8afdcc633bf 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. diff --git a/homeassistant/components/hassio/strings.json b/homeassistant/components/hassio/strings.json new file mode 100644 index 00000000000..875a79a60d7 --- /dev/null +++ b/homeassistant/components/hassio/strings.json @@ -0,0 +1,18 @@ +{ + "system_health": { + "info": { + "board": "Board", + "disk_total": "Disk Total", + "disk_used": "Disk Used", + "docker_version": "Docker Version", + "healthy": "Healthy", + "host_os": "Host Operating System", + "installed_addons": "Installed Add-ons", + "supervisor_api": "Supervisor API", + "supervisor_version": "Supervisor Version", + "supported": "Supported", + "update_channel": "Update Channel", + "version_api": "Version API" + } + } +} diff --git a/homeassistant/components/hassio/system_health.py b/homeassistant/components/hassio/system_health.py new file mode 100644 index 00000000000..530703d3e25 --- /dev/null +++ b/homeassistant/components/hassio/system_health.py @@ -0,0 +1,72 @@ +"""Provide info to system health.""" +import os + +from homeassistant.components import system_health +from homeassistant.core import HomeAssistant, callback + +SUPERVISOR_PING = f"http://{os.environ['HASSIO']}/supervisor/ping" +OBSERVER_URL = f"http://{os.environ['HASSIO']}:4357" + + +@callback +def async_register( + hass: HomeAssistant, register: system_health.SystemHealthRegistration +) -> None: + """Register system health callbacks.""" + register.async_register_info(system_health_info, "/hassio") + + +async def system_health_info(hass: HomeAssistant): + """Get info for the info page.""" + info = hass.components.hassio.get_info() + host_info = hass.components.hassio.get_host_info() + supervisor_info = hass.components.hassio.get_supervisor_info() + + if supervisor_info.get("healthy"): + healthy = True + else: + healthy = { + "type": "failed", + "error": "Unhealthy", + "more_info": "/hassio/system", + } + + if supervisor_info.get("supported"): + supported = True + else: + supported = { + "type": "failed", + "error": "Unsupported", + "more_info": "/hassio/system", + } + + information = { + "host_os": host_info.get("operating_system"), + "update_channel": info.get("channel"), + "supervisor_version": info.get("supervisor"), + "docker_version": info.get("docker"), + "disk_total": f"{host_info.get('disk_total')} GB", + "disk_used": f"{host_info.get('disk_used')} GB", + "healthy": healthy, + "supported": supported, + } + + if info.get("hassos") is not None: + os_info = hass.components.hassio.get_os_info() + information["board"] = os_info.get("board") + + information["supervisor_api"] = system_health.async_check_can_reach_url( + hass, SUPERVISOR_PING, OBSERVER_URL + ) + information["version_api"] = system_health.async_check_can_reach_url( + hass, + f"https://version.home-assistant.io/{info.get('channel')}.json", + "/hassio/system", + ) + + information["installed_addons"] = ", ".join( + f"{addon['name']} ({addon['version']})" + for addon in supervisor_info.get("addons", []) + ) + + return information diff --git a/homeassistant/components/hassio/translations/ca.json b/homeassistant/components/hassio/translations/ca.json index 981cb51c83a..ac804794b48 100644 --- a/homeassistant/components/hassio/translations/ca.json +++ b/homeassistant/components/hassio/translations/ca.json @@ -1,3 +1,19 @@ { + "system_health": { + "info": { + "board": "Placa", + "disk_total": "Total disc", + "disk_used": "Disc utilitzat", + "docker_version": "Versi\u00f3 de Docker", + "healthy": "Saludable", + "host_os": "Sistema operatiu amfitri\u00f3", + "installed_addons": "Complements instal\u00b7lats", + "supervisor_api": "API del Supervisor", + "supervisor_version": "Versi\u00f3 del Supervisor", + "supported": "Compatible", + "update_channel": "Canal d'actualitzaci\u00f3", + "version_api": "API de versions" + } + }, "title": "Hass.io" } \ No newline at end of file diff --git a/homeassistant/components/hassio/translations/cs.json b/homeassistant/components/hassio/translations/cs.json index 981cb51c83a..729dc069d7d 100644 --- a/homeassistant/components/hassio/translations/cs.json +++ b/homeassistant/components/hassio/translations/cs.json @@ -1,3 +1,19 @@ { + "system_health": { + "info": { + "board": "Deska", + "disk_total": "Kapacita disku", + "disk_used": "Obsazen\u00fd disk", + "docker_version": "Verze Dockeru", + "healthy": "V po\u0159\u00e1dku", + "host_os": "Hostitelsk\u00fd opera\u010dn\u00ed syst\u00e9m", + "installed_addons": "Nainstalovan\u00e9 dopl\u0148ky", + "supervisor_api": "API Supervisora", + "supervisor_version": "Verze Supervizora", + "supported": "Podporov\u00e1no", + "update_channel": "Kan\u00e1l aktualizac\u00ed", + "version_api": "Verze API" + } + }, "title": "Hass.io" } \ No newline at end of file diff --git a/homeassistant/components/hassio/translations/en.json b/homeassistant/components/hassio/translations/en.json index 981cb51c83a..230e0c11fea 100644 --- a/homeassistant/components/hassio/translations/en.json +++ b/homeassistant/components/hassio/translations/en.json @@ -1,3 +1,19 @@ { + "system_health": { + "info": { + "board": "Board", + "disk_total": "Disk Total", + "disk_used": "Disk Used", + "docker_version": "Docker Version", + "healthy": "Healthy", + "host_os": "Host Operating System", + "installed_addons": "Installed Add-ons", + "supervisor_api": "Supervisor API", + "supervisor_version": "Supervisor Version", + "supported": "Supported", + "update_channel": "Update Channel", + "version_api": "Version API" + } + }, "title": "Hass.io" } \ No newline at end of file diff --git a/homeassistant/components/hassio/translations/es.json b/homeassistant/components/hassio/translations/es.json index 981cb51c83a..4c8223f606b 100644 --- a/homeassistant/components/hassio/translations/es.json +++ b/homeassistant/components/hassio/translations/es.json @@ -1,3 +1,18 @@ { + "system_health": { + "info": { + "board": "Placa", + "disk_total": "Disco total", + "disk_used": "Disco usado", + "docker_version": "Versi\u00f3n de Docker", + "host_os": "Sistema operativo host", + "installed_addons": "Complementos instalados", + "supervisor_api": "API del Supervisor", + "supervisor_version": "Versi\u00f3n del Supervisor", + "supported": "Soportado", + "update_channel": "Actualizar canal", + "version_api": "Versi\u00f3n del API" + } + }, "title": "Hass.io" } \ No newline at end of file diff --git a/homeassistant/components/hassio/translations/et.json b/homeassistant/components/hassio/translations/et.json index 981cb51c83a..9e5e776013f 100644 --- a/homeassistant/components/hassio/translations/et.json +++ b/homeassistant/components/hassio/translations/et.json @@ -1,3 +1,19 @@ { + "system_health": { + "info": { + "board": "Seade", + "disk_total": "Kettaruum kokku", + "disk_used": "Kasutatud kettaruum", + "docker_version": "Dockeri versioon", + "healthy": "Korras", + "host_os": "Host-i operatsioonis\u00fcsteem", + "installed_addons": "Paigaldatud lisandmoodulid", + "supervisor_api": "Superviisori API", + "supervisor_version": "Superviisori j\u00e4rk", + "supported": "Toetatud", + "update_channel": "V\u00e4rskenduskanal", + "version_api": "API versioon" + } + }, "title": "Hass.io" } \ No newline at end of file diff --git a/homeassistant/components/hassio/translations/no.json b/homeassistant/components/hassio/translations/no.json index d8a4c453015..2fb04f5156e 100644 --- a/homeassistant/components/hassio/translations/no.json +++ b/homeassistant/components/hassio/translations/no.json @@ -1,3 +1,19 @@ { + "system_health": { + "info": { + "board": "Styret", + "disk_total": "Disk totalt", + "disk_used": "Disk brukt", + "docker_version": "Docker-versjon", + "healthy": "Sunn", + "host_os": "Vertsoperativsystem", + "installed_addons": "Installerte tillegg", + "supervisor_api": "API for Supervisor", + "supervisor_version": "Supervisor versjon", + "supported": "St\u00f8ttet", + "update_channel": "Oppdater kanal", + "version_api": "Versjon API" + } + }, "title": "" } \ No newline at end of file diff --git a/homeassistant/components/hassio/translations/pl.json b/homeassistant/components/hassio/translations/pl.json index 981cb51c83a..10ee7c9d16c 100644 --- a/homeassistant/components/hassio/translations/pl.json +++ b/homeassistant/components/hassio/translations/pl.json @@ -1,3 +1,19 @@ { + "system_health": { + "info": { + "board": "Uk\u0142ad", + "disk_total": "Pojemno\u015b\u0107 dysku", + "disk_used": "Pojemno\u015b\u0107 u\u017cyta", + "docker_version": "Wersja Dockera", + "healthy": "Zdrowy", + "host_os": "System operacyjny hosta", + "installed_addons": "Zainstalowane dodatki", + "supervisor_api": "API Supervisora", + "supervisor_version": "Wersja Supervisora", + "supported": "Wspierany", + "update_channel": "Kana\u0142 aktualizacji", + "version_api": "Wersja API" + } + }, "title": "Hass.io" } \ No newline at end of file diff --git a/homeassistant/components/hassio/translations/ru.json b/homeassistant/components/hassio/translations/ru.json index 981cb51c83a..052e1ec21dd 100644 --- a/homeassistant/components/hassio/translations/ru.json +++ b/homeassistant/components/hassio/translations/ru.json @@ -1,3 +1,16 @@ { + "system_health": { + "info": { + "board": "\u041f\u043b\u0430\u0442\u0430", + "docker_version": "\u0412\u0435\u0440\u0441\u0438\u044f Docker", + "host_os": "\u041e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0445\u043e\u0441\u0442\u0430", + "installed_addons": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f", + "supervisor_api": "Supervisor API", + "supervisor_version": "\u0412\u0435\u0440\u0441\u0438\u044f Supervisor", + "supported": "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "update_channel": "\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u0430\u043d\u0430\u043b", + "version_api": "\u0412\u0435\u0440\u0441\u0438\u044f API" + } + }, "title": "Hass.io" } \ No newline at end of file diff --git a/homeassistant/components/heos/translations/bg.json b/homeassistant/components/heos/translations/bg.json index 40156a8b3cd..ced8d049372 100644 --- a/homeassistant/components/heos/translations/bg.json +++ b/homeassistant/components/heos/translations/bg.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "\u041c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 Heos \u0432\u0440\u044a\u0437\u043a\u0430, \u0442\u044a\u0439 \u043a\u0430\u0442\u043e \u0442\u044f \u0449\u0435 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0432\u0441\u0438\u0447\u043a\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u043c\u0440\u0435\u0436\u0430\u0442\u0430." - }, - "error": { - "connection_failure": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0441\u043e\u0447\u0435\u043d\u0438\u044f \u0430\u0434\u0440\u0435\u0441." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/heos/translations/ca.json b/homeassistant/components/heos/translations/ca.json index f12e18ac999..ae3306cd0c0 100644 --- a/homeassistant/components/heos/translations/ca.json +++ b/homeassistant/components/heos/translations/ca.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Nom\u00e9s pots configurar una \u00fanica connexi\u00f3 de Heos tot i que aquesta ja pot controlar tots els dispositius de la xarxa.", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_failure": "No s'ha pogut connectar amb l'amfitri\u00f3 especificat." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/cs.json b/homeassistant/components/heos/translations/cs.json index 97b722b0b75..0350ecef68f 100644 --- a/homeassistant/components/heos/translations/cs.json +++ b/homeassistant/components/heos/translations/cs.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "M\u016f\u017eete nastavit pouze jedno p\u0159ipojen\u00ed Heos, proto\u017ee bude podporovat v\u0161echna za\u0159\u00edzen\u00ed v s\u00edti.", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_failure": "Nelze se p\u0159ipojit k uveden\u00e9mu hostiteli." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/da.json b/homeassistant/components/heos/translations/da.json index 3537ba30553..af56c2de436 100644 --- a/homeassistant/components/heos/translations/da.json +++ b/homeassistant/components/heos/translations/da.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Du kan kun konfigurere en enkelt Heos-forbindelse, da den underst\u00f8tter alle enheder p\u00e5 netv\u00e6rket." - }, - "error": { - "connection_failure": "Kunne ikke oprette forbindelse til den angivne v\u00e6rt." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/heos/translations/de.json b/homeassistant/components/heos/translations/de.json index 4a886f0550b..7c5e1d87c9d 100644 --- a/homeassistant/components/heos/translations/de.json +++ b/homeassistant/components/heos/translations/de.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Es kann nur eine einzige Heos-Verbindung konfiguriert werden, da diese alle Ger\u00e4te im Netzwerk unterst\u00fctzt." - }, - "error": { - "connection_failure": "Es kann keine Verbindung zum angegebenen Host hergestellt werden." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/heos/translations/en.json b/homeassistant/components/heos/translations/en.json index ed82022c969..b9dcf326276 100644 --- a/homeassistant/components/heos/translations/en.json +++ b/homeassistant/components/heos/translations/en.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "You can only configure a single Heos connection as it will support all devices on the network.", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "error": { - "cannot_connect": "Failed to connect", - "connection_failure": "Unable to connect to the specified host." + "cannot_connect": "Failed to connect" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/es-419.json b/homeassistant/components/heos/translations/es-419.json index 6c45936d8be..afb8bc761c5 100644 --- a/homeassistant/components/heos/translations/es-419.json +++ b/homeassistant/components/heos/translations/es-419.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Solo puede configurar una sola conexi\u00f3n Heos, ya que ser\u00e1 compatible con todos los dispositivos de la red." - }, - "error": { - "connection_failure": "No se puede conectar con el host especificado." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/heos/translations/es.json b/homeassistant/components/heos/translations/es.json index 4810c7afd31..dde95e24384 100644 --- a/homeassistant/components/heos/translations/es.json +++ b/homeassistant/components/heos/translations/es.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Solo puedes configurar una \u00fanica conexi\u00f3n Heos, ya que admitir\u00e1 todos los dispositivos de la red.", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "error": { - "cannot_connect": "No se pudo conectar", - "connection_failure": "No se puede conectar al host especificado." + "cannot_connect": "No se pudo conectar" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/et.json b/homeassistant/components/heos/translations/et.json index f9ece4ea62b..bdafeaa8914 100644 --- a/homeassistant/components/heos/translations/et.json +++ b/homeassistant/components/heos/translations/et.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Saad seadistada ainult \u00fche Heosi \u00fchenduse kuna see toetab k\u00f5iki v\u00f5rgus olevaid seadmeid.", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "error": { @@ -11,7 +10,9 @@ "user": { "data": { "host": "" - } + }, + "description": "Sisesta Heos-seadme hosti nimi v\u00f5i IP-aadress (eelistatavalt v\u00f5rgukaabliga \u00fchendatud).", + "title": "\u00dchendu Heos'ega" } } } diff --git a/homeassistant/components/heos/translations/fr.json b/homeassistant/components/heos/translations/fr.json index 39cb39e33f5..05d152e562f 100644 --- a/homeassistant/components/heos/translations/fr.json +++ b/homeassistant/components/heos/translations/fr.json @@ -1,10 +1,10 @@ { "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." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { - "connection_failure": "Impossible de se connecter \u00e0 l'h\u00f4te sp\u00e9cifi\u00e9." + "cannot_connect": "\u00c9chec de connexion" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/it.json b/homeassistant/components/heos/translations/it.json index 353d0a7e319..9b758e36d6d 100644 --- a/homeassistant/components/heos/translations/it.json +++ b/homeassistant/components/heos/translations/it.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u00c8 possibile configurare una singola connessione Heos poich\u00e9 supporta tutti i dispositivi sulla rete.", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "error": { - "cannot_connect": "Impossibile connettersi", - "connection_failure": "Impossibile connettersi all'host specificato." + "cannot_connect": "Impossibile connettersi" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/ko.json b/homeassistant/components/heos/translations/ko.json index acf26df1cec..fc20a77d7b8 100644 --- a/homeassistant/components/heos/translations/ko.json +++ b/homeassistant/components/heos/translations/ko.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Heos \uc5f0\uacb0\uc740 \ub124\ud2b8\uc6cc\ud06c\uc0c1\uc758 \ubaa8\ub4e0 \uae30\uae30\ub97c \uc9c0\uc6d0\ud558\uae30 \ub54c\ubb38\uc5d0 \ud558\ub098\ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4." - }, - "error": { - "connection_failure": "\uc9c0\uc815\ub41c \ud638\uc2a4\ud2b8\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/heos/translations/lb.json b/homeassistant/components/heos/translations/lb.json index a18ec58e4a9..62e6faac8ae 100644 --- a/homeassistant/components/heos/translations/lb.json +++ b/homeassistant/components/heos/translations/lb.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "Dir k\u00ebnnt n\u00ebmmen eng eenzeg Heos Verbindung konfigur\u00e9ieren, well se all Apparater am Netzwierk \u00ebnnerst\u00ebtzen." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { - "cannot_connect": "Feeler beim verbannen", - "connection_failure": "Kann sech net mat dem spezifiz\u00e9ierten Apparat verbannen." + "cannot_connect": "Feeler beim verbannen" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/nl.json b/homeassistant/components/heos/translations/nl.json index 7b9aa21b613..20192ab6428 100644 --- a/homeassistant/components/heos/translations/nl.json +++ b/homeassistant/components/heos/translations/nl.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "U kunt alleen een enkele Heos-verbinding configureren, omdat deze alle apparaten in het netwerk ondersteunt.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "error": { - "cannot_connect": "Kan geen verbinding maken", - "connection_failure": "Kan geen verbinding maken met de opgegeven host." + "cannot_connect": "Kan geen verbinding maken" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/no.json b/homeassistant/components/heos/translations/no.json index defb1f72e8e..bd40ae4d52c 100644 --- a/homeassistant/components/heos/translations/no.json +++ b/homeassistant/components/heos/translations/no.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Du kan kun konfigurere en Heos tilkobling, da den st\u00f8tter alle enhetene p\u00e5 nettverket.", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "connection_failure": "Kan ikke koble til den angitte verten." + "cannot_connect": "Tilkobling mislyktes" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/pl.json b/homeassistant/components/heos/translations/pl.json index 04266204c3b..6cc2489fc15 100644 --- a/homeassistant/components/heos/translations/pl.json +++ b/homeassistant/components/heos/translations/pl.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno po\u0142\u0105czenie Heos, poniewa\u017c b\u0119dzie ono obs\u0142ugiwa\u0107 wszystkie urz\u0105dzenia w sieci", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_failure": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z okre\u015blonym hostem" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/pt-BR.json b/homeassistant/components/heos/translations/pt-BR.json index 55d7b76d96e..328264d3adf 100644 --- a/homeassistant/components/heos/translations/pt-BR.json +++ b/homeassistant/components/heos/translations/pt-BR.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Voc\u00ea s\u00f3 pode configurar uma \u00fanica conex\u00e3o Heos, pois ela suportar\u00e1 todos os dispositivos na rede." - }, - "error": { - "connection_failure": "N\u00e3o \u00e9 poss\u00edvel conectar-se ao host especificado." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/heos/translations/ru.json b/homeassistant/components/heos/translations/ru.json index 2ee40afbe0c..47d8e01a6b4 100644 --- a/homeassistant/components/heos/translations/ru.json +++ b/homeassistant/components/heos/translations/ru.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u041d\u0443\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 HEOS \u0432 \u0441\u0435\u0442\u0438.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_failure": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c\u0443 \u0445\u043e\u0441\u0442\u0443." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "user": { diff --git a/homeassistant/components/heos/translations/sl.json b/homeassistant/components/heos/translations/sl.json index abe3d6dc97a..59035e7d56f 100644 --- a/homeassistant/components/heos/translations/sl.json +++ b/homeassistant/components/heos/translations/sl.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Konfigurirate lahko samo eno povezavo Heos, le ta bo podpirala vse naprave v omre\u017eju." - }, - "error": { - "connection_failure": "Ni mogo\u010de vzpostaviti povezave z dolo\u010denim gostiteljem." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/heos/translations/sv.json b/homeassistant/components/heos/translations/sv.json index 4ade6944e51..a2cec73f291 100644 --- a/homeassistant/components/heos/translations/sv.json +++ b/homeassistant/components/heos/translations/sv.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Du kan bara konfigurera en enda Heos-anslutning eftersom den kommer att st\u00f6dja alla enheter i n\u00e4tverket." - }, - "error": { - "connection_failure": "Det gick inte att ansluta till den angivna v\u00e4rden." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/heos/translations/zh-Hans.json b/homeassistant/components/heos/translations/zh-Hans.json new file mode 100644 index 00000000000..2941dfd9383 --- /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/heos/translations/zh-Hant.json b/homeassistant/components/heos/translations/zh-Hant.json index 24099a77735..95ddf7e51a7 100644 --- a/homeassistant/components/heos/translations/zh-Hant.json +++ b/homeassistant/components/heos/translations/zh-Hant.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44 Heos \u9023\u7dda\uff0c\u5c07\u652f\u63f4\u7db2\u8def\u4e2d\u6240\u6709\u5c0d\u61c9\u8a2d\u5099\u3002", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_failure": "\u7121\u6cd5\u9023\u7dda\u81f3\u6307\u5b9a\u4e3b\u6a5f\u7aef\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "user": { diff --git a/homeassistant/components/hisense_aehw4a1/translations/lb.json b/homeassistant/components/hisense_aehw4a1/translations/lb.json index d97f9fc2893..cf065c3e44b 100644 --- a/homeassistant/components/hisense_aehw4a1/translations/lb.json +++ b/homeassistant/components/hisense_aehw4a1/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "no_devices_found": "Keng Hisense AEH-W4A1 Apparater am Netzwierk fonnt.", - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun Hisense AEH-W4A1 ass m\u00e9iglech." + "no_devices_found": "Keng Apparater am Netzwierk fonnt.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "confirm": { diff --git a/homeassistant/components/hisense_aehw4a1/translations/pl.json b/homeassistant/components/hisense_aehw4a1/translations/pl.json index feab528e03a..a8ee3fa57ac 100644 --- a/homeassistant/components/hisense_aehw4a1/translations/pl.json +++ b/homeassistant/components/hisense_aehw4a1/translations/pl.json @@ -6,7 +6,7 @@ }, "step": { "confirm": { - "description": "Chcesz skonfigurowa\u0107 AEH-W4A1?" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } } diff --git a/homeassistant/components/history/__init__.py b/homeassistant/components/history/__init__.py index a8ea18770d9..894c2b15e47 100644 --- a/homeassistant/components/history/__init__.py +++ b/homeassistant/components/history/__init__.py @@ -482,18 +482,19 @@ class HistoryPeriodView(HomeAssistantView): if start_time > now: return self.json([]) - end_time = request.query.get("end_time") - if end_time: - end_time = dt_util.parse_datetime(end_time) + end_time_str = request.query.get("end_time") + if end_time_str: + end_time = dt_util.parse_datetime(end_time_str) if end_time: end_time = dt_util.as_utc(end_time) else: return self.json_message("Invalid end_time", HTTP_BAD_REQUEST) else: end_time = start_time + one_day - entity_ids = request.query.get("filter_entity_id") - if entity_ids: - entity_ids = entity_ids.lower().split(",") + entity_ids_str = request.query.get("filter_entity_id") + entity_ids = None + if entity_ids_str: + entity_ids = entity_ids_str.lower().split(",") include_start_time_state = "skip_initial_state" not in request.query significant_changes_only = ( request.query.get("significant_changes_only", "1") != "0" diff --git a/homeassistant/components/history_stats/sensor.py b/homeassistant/components/history_stats/sensor.py index 9f59f67eb95..8f4a89e3e37 100644 --- a/homeassistant/components/history_stats/sensor.py +++ b/homeassistant/components/history_stats/sensor.py @@ -225,7 +225,7 @@ class HistoryStatsSensor(Entity): self.hass, start, end, str(self._entity_id) ) - if self._entity_id not in history_list.keys(): + if self._entity_id not in history_list: return # Get the first state diff --git a/homeassistant/components/hlk_sw16/translations/nl.json b/homeassistant/components/hlk_sw16/translations/nl.json index 4d00f0bfc74..0569c39321a 100644 --- a/homeassistant/components/hlk_sw16/translations/nl.json +++ b/homeassistant/components/hlk_sw16/translations/nl.json @@ -1,8 +1,17 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "host": "Host", + "password": "Wachtwoord", "username": "Gebruikersnaam" } } diff --git a/homeassistant/components/home_connect/translations/lb.json b/homeassistant/components/home_connect/translations/lb.json index 210c871a1b8..89695b00ccf 100644 --- a/homeassistant/components/home_connect/translations/lb.json +++ b/homeassistant/components/home_connect/translations/lb.json @@ -1,11 +1,11 @@ { "config": { "abort": { - "missing_configuration": "Home Connecz Komponent ass nach net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun.", + "missing_configuration": "Komponent ass nach net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun.", "no_url_available": "Keng URL disponibel. Fir Informatiounen iwwert d\u00ebse Feeler, [kuck H\u00ebllef Sektioun]({docs_url})" }, "create_entry": { - "default": "Erfollegr\u00e4ich mat Home Connect authentifiz\u00e9iert." + "default": "Erfollegr\u00e4ich authentifiz\u00e9iert." }, "step": { "pick_implementation": { diff --git a/homeassistant/components/home_connect/translations/nl.json b/homeassistant/components/home_connect/translations/nl.json new file mode 100644 index 00000000000..41b27cc387f --- /dev/null +++ b/homeassistant/components/home_connect/translations/nl.json @@ -0,0 +1,15 @@ +{ + "config": { + "abort": { + "missing_configuration": "Het component is niet geconfigureerd. Volg de documentatie." + }, + "create_entry": { + "default": "Succesvol geverifieerd" + }, + "step": { + "pick_implementation": { + "title": "Kies de verificatiemethode" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/strings.json b/homeassistant/components/homeassistant/strings.json new file mode 100644 index 00000000000..7da4a5a9d8a --- /dev/null +++ b/homeassistant/components/homeassistant/strings.json @@ -0,0 +1,17 @@ +{ + "system_health": { + "info": { + "arch": "CPU Architecture", + "dev": "Development", + "docker": "Docker", + "hassio": "Supervisor", + "installation_type": "Installation Type", + "os_name": "Operating System Family", + "os_version": "Operating System Version", + "python_version": "Python Version", + "timezone": "Timezone", + "version": "Version", + "virtualenv": "Virtual Environment" + } + } +} diff --git a/homeassistant/components/homeassistant/system_health.py b/homeassistant/components/homeassistant/system_health.py new file mode 100644 index 00000000000..b0245d9beec --- /dev/null +++ b/homeassistant/components/homeassistant/system_health.py @@ -0,0 +1,31 @@ +"""Provide info to system health.""" +from homeassistant.components import system_health +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import system_info + + +@callback +def async_register( + hass: HomeAssistant, register: system_health.SystemHealthRegistration +) -> None: + """Register system health callbacks.""" + register.async_register_info(system_health_info) + + +async def system_health_info(hass): + """Get info for the info page.""" + info = await system_info.async_get_system_info(hass) + + return { + "version": info.get("version"), + "installation_type": info.get("installation_type"), + "dev": info.get("dev"), + "hassio": info.get("hassio"), + "docker": info.get("docker"), + "virtualenv": info.get("virtualenv"), + "python_version": info.get("python_version"), + "os_name": info.get("os_name"), + "os_version": info.get("os_version"), + "arch": info.get("arch"), + "timezone": info.get("timezone"), + } diff --git a/homeassistant/components/homeassistant/translations/af.json b/homeassistant/components/homeassistant/translations/af.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/af.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/bg.json b/homeassistant/components/homeassistant/translations/bg.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/bg.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/ca.json b/homeassistant/components/homeassistant/translations/ca.json index 04b5b760f60..f02939b201e 100644 --- a/homeassistant/components/homeassistant/translations/ca.json +++ b/homeassistant/components/homeassistant/translations/ca.json @@ -1,3 +1,20 @@ { - "title": "Home Assistant" + "system_health": { + "info": { + "arch": "Arquitectura de la CPU", + "chassis": "Xass\u00eds", + "dev": "Desenvolupament", + "docker": "Docker", + "docker_version": "Docker", + "host_os": "Home Assistant OS", + "installation_type": "Tipus d'instal\u00b7laci\u00f3", + "os_name": "Fam\u00edlia del sistema operatiu", + "os_version": "Versi\u00f3 del sistema operatiu", + "python_version": "Versi\u00f3 de Python", + "supervisor": "Supervisor", + "timezone": "Zona hor\u00e0ria", + "version": "Versi\u00f3", + "virtualenv": "Entorn virtual" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/cs.json b/homeassistant/components/homeassistant/translations/cs.json index 04b5b760f60..46bf2c56b4b 100644 --- a/homeassistant/components/homeassistant/translations/cs.json +++ b/homeassistant/components/homeassistant/translations/cs.json @@ -1,3 +1,20 @@ { - "title": "Home Assistant" + "system_health": { + "info": { + "arch": "Architektura procesoru", + "chassis": "\u0160asi", + "dev": "V\u00fdvoj", + "docker": "Docker", + "docker_version": "Docker", + "host_os": "Home Assistant OS", + "installation_type": "Typ instalace", + "os_name": "Rodina opera\u010dn\u00edch syst\u00e9m\u016f", + "os_version": "Verze opera\u010dn\u00edho syst\u00e9mu", + "python_version": "Verze Pythonu", + "supervisor": "Supervisor", + "timezone": "\u010casov\u00e9 p\u00e1smo", + "version": "Verze", + "virtualenv": "Virtu\u00e1ln\u00ed prost\u0159ed\u00ed" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/cy.json b/homeassistant/components/homeassistant/translations/cy.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/cy.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/da.json b/homeassistant/components/homeassistant/translations/da.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/da.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/de.json b/homeassistant/components/homeassistant/translations/de.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/de.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/el.json b/homeassistant/components/homeassistant/translations/el.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/el.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/en.json b/homeassistant/components/homeassistant/translations/en.json index 04b5b760f60..ee029772d21 100644 --- a/homeassistant/components/homeassistant/translations/en.json +++ b/homeassistant/components/homeassistant/translations/en.json @@ -1,3 +1,21 @@ { - "title": "Home Assistant" -} \ No newline at end of file + "system_health": { + "info": { + "arch": "CPU Architecture", + "chassis": "Chassis", + "dev": "Development", + "docker": "Docker", + "docker_version": "Docker", + "hassio": "Supervisor", + "host_os": "Home Assistant OS", + "installation_type": "Installation Type", + "os_name": "Operating System Family", + "os_version": "Operating System Version", + "python_version": "Python Version", + "supervisor": "Supervisor", + "timezone": "Timezone", + "version": "Version", + "virtualenv": "Virtual Environment" + } + } +} diff --git a/homeassistant/components/homeassistant/translations/es-419.json b/homeassistant/components/homeassistant/translations/es-419.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/es-419.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/es.json b/homeassistant/components/homeassistant/translations/es.json index 04b5b760f60..1829d16d510 100644 --- a/homeassistant/components/homeassistant/translations/es.json +++ b/homeassistant/components/homeassistant/translations/es.json @@ -1,3 +1,21 @@ { - "title": "Home Assistant" + "system_health": { + "info": { + "arch": "Arquitectura de CPU", + "chassis": "Chasis", + "dev": "Desarrollo", + "docker": "Docker", + "docker_version": "Docker", + "hassio": "Supervisor", + "host_os": "SO Home Assistant", + "installation_type": "Tipo de instalaci\u00f3n", + "os_name": "Nombre del Sistema Operativo", + "os_version": "Versi\u00f3n del Sistema Operativo", + "python_version": "Versi\u00f3n de Python", + "supervisor": "Supervisor", + "timezone": "Zona horaria", + "version": "Versi\u00f3n", + "virtualenv": "Entorno virtual" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/et.json b/homeassistant/components/homeassistant/translations/et.json index 04b5b760f60..7bdecd0178f 100644 --- a/homeassistant/components/homeassistant/translations/et.json +++ b/homeassistant/components/homeassistant/translations/et.json @@ -1,3 +1,20 @@ { - "title": "Home Assistant" + "system_health": { + "info": { + "arch": "Protsessori arhitektuur", + "chassis": "Korpus", + "dev": "Arendus", + "docker": "Docker", + "docker_version": "Docker", + "host_os": "Home Assistant OS", + "installation_type": "Paigalduse t\u00fc\u00fcp", + "os_name": "Operatsioonis\u00fcsteemi j\u00e4rk", + "os_version": "Operatsioonis\u00fcsteemi versioon", + "python_version": "Pythoni versioon", + "supervisor": "Haldur", + "timezone": "Ajav\u00f6\u00f6nd", + "version": "Versioon", + "virtualenv": "Virtuaalne keskkond" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/eu.json b/homeassistant/components/homeassistant/translations/eu.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/eu.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/fa.json b/homeassistant/components/homeassistant/translations/fa.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/fa.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/fi.json b/homeassistant/components/homeassistant/translations/fi.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/fi.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/fr.json b/homeassistant/components/homeassistant/translations/fr.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/fr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/he.json b/homeassistant/components/homeassistant/translations/he.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/he.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/hr.json b/homeassistant/components/homeassistant/translations/hr.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/hr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/hu.json b/homeassistant/components/homeassistant/translations/hu.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/hu.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/hy.json b/homeassistant/components/homeassistant/translations/hy.json deleted file mode 100644 index d4578360f53..00000000000 --- a/homeassistant/components/homeassistant/translations/hy.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "\u054f\u0576\u0561\u0575\u056b\u0576 \u0585\u0563\u0576\u0561\u056f\u0561\u0576" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/is.json b/homeassistant/components/homeassistant/translations/is.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/is.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/it.json b/homeassistant/components/homeassistant/translations/it.json index 04b5b760f60..80f7b39d210 100644 --- a/homeassistant/components/homeassistant/translations/it.json +++ b/homeassistant/components/homeassistant/translations/it.json @@ -1,3 +1,20 @@ { - "title": "Home Assistant" + "system_health": { + "info": { + "arch": "Architettura della CPU", + "chassis": "Telaio", + "dev": "Sviluppo", + "docker": "Docker", + "docker_version": "Docker", + "host_os": "Sistema Operativo di Home Assistant", + "installation_type": "Tipo di installazione", + "os_name": "Nome del Sistema Operativo", + "os_version": "Versione del Sistema Operativo", + "python_version": "Versione Python", + "supervisor": "Supervisore", + "timezone": "Fuso orario", + "version": "Versione", + "virtualenv": "Ambiente virtuale" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/ko.json b/homeassistant/components/homeassistant/translations/ko.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/ko.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/lb.json b/homeassistant/components/homeassistant/translations/lb.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/lb.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/lt.json b/homeassistant/components/homeassistant/translations/lt.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/lt.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/lv.json b/homeassistant/components/homeassistant/translations/lv.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/lv.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/nb.json b/homeassistant/components/homeassistant/translations/nb.json deleted file mode 100644 index d8a4c453015..00000000000 --- a/homeassistant/components/homeassistant/translations/nb.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/nl.json b/homeassistant/components/homeassistant/translations/nl.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/nl.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/nn.json b/homeassistant/components/homeassistant/translations/nn.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/nn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/no.json b/homeassistant/components/homeassistant/translations/no.json index d8a4c453015..72bba59116c 100644 --- a/homeassistant/components/homeassistant/translations/no.json +++ b/homeassistant/components/homeassistant/translations/no.json @@ -1,3 +1,20 @@ { - "title": "" + "system_health": { + "info": { + "arch": "CPU-arkitektur", + "chassis": "Kabinett", + "dev": "Utvikling", + "docker": "", + "docker_version": "", + "host_os": "", + "installation_type": "Installasjonstype", + "os_name": "Familie for operativsystem", + "os_version": "Operativsystemversjon", + "python_version": "Python versjon", + "supervisor": "", + "timezone": "Tidssone", + "version": "Versjon", + "virtualenv": "Virtuelt milj\u00f8" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/pl.json b/homeassistant/components/homeassistant/translations/pl.json index 04b5b760f60..e65756cfc83 100644 --- a/homeassistant/components/homeassistant/translations/pl.json +++ b/homeassistant/components/homeassistant/translations/pl.json @@ -1,3 +1,20 @@ { - "title": "Home Assistant" + "system_health": { + "info": { + "arch": "Architektura procesora", + "chassis": "Wersja komputera", + "dev": "Wersja rozwojowa", + "docker": "Docker", + "docker_version": "Wersja Dockera", + "host_os": "System operacyjny HA", + "installation_type": "Typ instalacji", + "os_name": "Rodzina systemu operacyjnego", + "os_version": "Wersja systemu operacyjnego", + "python_version": "Wersja Pythona", + "supervisor": "Supervisor", + "timezone": "Strefa czasowa", + "version": "Wersja", + "virtualenv": "\u015arodowisko wirtualne" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/pt-BR.json b/homeassistant/components/homeassistant/translations/pt-BR.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/pt-BR.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/pt.json b/homeassistant/components/homeassistant/translations/pt.json index d8a4c453015..1b30839faff 100644 --- a/homeassistant/components/homeassistant/translations/pt.json +++ b/homeassistant/components/homeassistant/translations/pt.json @@ -1,3 +1,19 @@ { - "title": "" + "system_health": { + "info": { + "arch": "Arquitetura do Processador", + "dev": "Desenvolvimento", + "docker": "Docker", + "docker_version": "Docker", + "host_os": "Sistema Operativo do Home Assistant", + "installation_type": "Tipo de Instala\u00e7\u00e3o", + "os_name": "Nome do Sistema Operativo", + "os_version": "Vers\u00e3o do Sistema Operativo", + "python_version": "Vers\u00e3o Python", + "supervisor": "Supervisor", + "timezone": "Fuso hor\u00e1rio", + "version": "Vers\u00e3o", + "virtualenv": "Ambiente Virtual" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/ro.json b/homeassistant/components/homeassistant/translations/ro.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/ro.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/ru.json b/homeassistant/components/homeassistant/translations/ru.json index 04b5b760f60..76af5da7d13 100644 --- a/homeassistant/components/homeassistant/translations/ru.json +++ b/homeassistant/components/homeassistant/translations/ru.json @@ -1,3 +1,20 @@ { - "title": "Home Assistant" + "system_health": { + "info": { + "arch": "\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0426\u041f", + "chassis": "\u0428\u0430\u0441\u0441\u0438", + "dev": "\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438", + "docker": "Docker", + "docker_version": "Docker", + "host_os": "Home Assistant OS", + "installation_type": "\u0422\u0438\u043f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438", + "os_name": "\u0421\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c", + "os_version": "\u0412\u0435\u0440\u0441\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b", + "python_version": "\u0412\u0435\u0440\u0441\u0438\u044f Python", + "supervisor": "Supervisor", + "timezone": "\u0427\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441", + "version": "\u0412\u0435\u0440\u0441\u0438\u044f", + "virtualenv": "\u0412\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/sk.json b/homeassistant/components/homeassistant/translations/sk.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/sk.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/sl.json b/homeassistant/components/homeassistant/translations/sl.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/sl.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/sv.json b/homeassistant/components/homeassistant/translations/sv.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/sv.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/th.json b/homeassistant/components/homeassistant/translations/th.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/th.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/tr.json b/homeassistant/components/homeassistant/translations/tr.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/tr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/uk.json b/homeassistant/components/homeassistant/translations/uk.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/uk.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/vi.json b/homeassistant/components/homeassistant/translations/vi.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/vi.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/zh-Hans.json b/homeassistant/components/homeassistant/translations/zh-Hans.json deleted file mode 100644 index 04b5b760f60..00000000000 --- a/homeassistant/components/homeassistant/translations/zh-Hans.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Home Assistant" -} \ No newline at end of file diff --git a/homeassistant/components/homeassistant/translations/zh-Hant.json b/homeassistant/components/homeassistant/translations/zh-Hant.json index 04b5b760f60..2bc13851390 100644 --- a/homeassistant/components/homeassistant/translations/zh-Hant.json +++ b/homeassistant/components/homeassistant/translations/zh-Hant.json @@ -1,3 +1,20 @@ { - "title": "Home Assistant" + "system_health": { + "info": { + "arch": "CPU \u67b6\u69cb", + "chassis": "Chassis", + "dev": "\u958b\u767c\u7248", + "docker": "Docker", + "docker_version": "Docker", + "host_os": "Home Assistant OS", + "installation_type": "\u5b89\u88dd\u985e\u578b", + "os_name": "\u4f5c\u696d\u7cfb\u7d71\u540d\u7a31", + "os_version": "\u4f5c\u696d\u7cfb\u7d71\u7248\u672c", + "python_version": "Python \u7248\u672c", + "supervisor": "Supervisor", + "timezone": "\u6642\u5340", + "version": "\u7248\u672c", + "virtualenv": "\u865b\u64ec\u74b0\u5883" + } + } } \ No newline at end of file diff --git a/homeassistant/components/homeassistant/triggers/time.py b/homeassistant/components/homeassistant/triggers/time.py index adfe592319b..b636a7a3590 100644 --- a/homeassistant/components/homeassistant/triggers/time.py +++ b/homeassistant/components/homeassistant/triggers/time.py @@ -4,7 +4,14 @@ from functools import partial import voluptuous as vol -from homeassistant.const import CONF_AT, CONF_PLATFORM +from homeassistant.components import sensor +from homeassistant.const import ( + ATTR_DEVICE_CLASS, + CONF_AT, + CONF_PLATFORM, + STATE_UNAVAILABLE, + STATE_UNKNOWN, +) from homeassistant.core import HassJob, callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers.event import ( @@ -18,8 +25,8 @@ import homeassistant.util.dt as dt_util _TIME_TRIGGER_SCHEMA = vol.Any( cv.time, - vol.All(str, cv.entity_domain("input_datetime")), - msg="Expected HH:MM, HH:MM:SS or Entity ID from domain 'input_datetime'", + vol.All(str, cv.entity_domain(("input_datetime", "sensor"))), + msg="Expected HH:MM, HH:MM:SS or Entity ID with domain 'input_datetime' or 'sensor'", ) TRIGGER_SCHEMA = vol.Schema( @@ -60,14 +67,16 @@ async def async_attach_trigger(hass, config, action, automation_info): def update_entity_trigger(entity_id, new_state=None): """Update the entity trigger for the entity_id.""" # If a listener was already set up for entity, remove it. - remove = entities.get(entity_id) + remove = entities.pop(entity_id, None) if remove: remove() - removes.remove(remove) remove = None + if not new_state: + return + # Check state of entity. If valid, set up a listener. - if new_state: + if new_state.domain == "input_datetime": has_date = new_state.attributes["has_date"] if has_date: year = new_state.attributes["year"] @@ -111,16 +120,32 @@ async def async_attach_trigger(hass, config, action, automation_info): minute=minute, second=second, ) + elif ( + new_state.domain == "sensor" + and new_state.attributes.get(ATTR_DEVICE_CLASS) + == sensor.DEVICE_CLASS_TIMESTAMP + and new_state.state not in (STATE_UNAVAILABLE, STATE_UNKNOWN) + ): + trigger_dt = dt_util.parse_datetime(new_state.state) + + if trigger_dt is not None and trigger_dt > dt_util.utcnow(): + remove = async_track_point_in_time( + hass, + partial( + time_automation_listener, + f"time set in {entity_id}", + entity_id=entity_id, + ), + trigger_dt, + ) # Was a listener set up? if remove: - removes.append(remove) - - entities[entity_id] = remove + entities[entity_id] = remove for at_time in config[CONF_AT]: if isinstance(at_time, str): - # input_datetime entity + # entity update_entity_trigger(at_time, new_state=hass.states.get(at_time)) else: # datetime.time @@ -144,6 +169,8 @@ async def async_attach_trigger(hass, config, action, automation_info): @callback def remove_track_time_changes(): """Remove tracked time changes.""" + for remove in entities.values(): + remove() for remove in removes: remove() diff --git a/homeassistant/components/homekit/__init__.py b/homeassistant/components/homekit/__init__.py index 742e41213a7..2a0638642ed 100644 --- a/homeassistant/components/homekit/__init__.py +++ b/homeassistant/components/homekit/__init__.py @@ -355,6 +355,7 @@ def _async_register_events_and_services(hass: HomeAssistant): async def async_handle_homekit_service_start(service): """Handle start HomeKit service call.""" + tasks = [] for entry_id in hass.data[DOMAIN]: if HOMEKIT not in hass.data[DOMAIN][entry_id]: continue @@ -368,7 +369,8 @@ def _async_register_events_and_services(hass: HomeAssistant): "been stopped" ) continue - await homekit.async_start() + tasks.append(homekit.async_start()) + await asyncio.gather(*tasks) hass.services.async_register( DOMAIN, SERVICE_HOMEKIT_START, async_handle_homekit_service_start @@ -505,7 +507,7 @@ class HomeKit: # The bridge itself counts as an accessory if len(self.bridge.accessories) + 1 >= MAX_DEVICES: _LOGGER.warning( - "Cannot add %s as this would exceeded the %d device limit. Consider using the filter option", + "Cannot add %s as this would exceed the %d device limit. Consider using the filter option", state.entity_id, MAX_DEVICES, ) diff --git a/homeassistant/components/homekit/const.py b/homeassistant/components/homekit/const.py index 3a0ba43e9cb..77c5dbff0f9 100644 --- a/homeassistant/components/homekit/const.py +++ b/homeassistant/components/homekit/const.py @@ -28,6 +28,8 @@ ATTR_MANUFACTURER = "manufacturer" ATTR_MODEL = "model" ATTR_SOFTWARE_VERSION = "sw_version" ATTR_KEY_NAME = "key_name" +# Current attribute used by homekit_controller +ATTR_OBSTRUCTION_DETECTED = "obstruction-detected" # #### Config #### CONF_HOMEKIT_MODE = "mode" @@ -45,6 +47,7 @@ CONF_LINKED_BATTERY_CHARGING_SENSOR = "linked_battery_charging_sensor" CONF_LINKED_DOORBELL_SENSOR = "linked_doorbell_sensor" CONF_LINKED_MOTION_SENSOR = "linked_motion_sensor" CONF_LINKED_HUMIDITY_SENSOR = "linked_humidity_sensor" +CONF_LINKED_OBSTRUCTION_SENSOR = "linked_obstruction_sensor" CONF_LOW_BATTERY_THRESHOLD = "low_battery_threshold" CONF_MAX_FPS = "max_fps" CONF_MAX_HEIGHT = "max_height" @@ -192,6 +195,7 @@ CHAR_MODEL = "Model" CHAR_MOTION_DETECTED = "MotionDetected" CHAR_MUTE = "Mute" CHAR_NAME = "Name" +CHAR_OBSTRUCTION_DETECTED = "ObstructionDetected" CHAR_OCCUPANCY_DETECTED = "OccupancyDetected" CHAR_ON = "On" CHAR_OUTLET_IN_USE = "OutletInUse" diff --git a/homeassistant/components/homekit/strings.json b/homeassistant/components/homekit/strings.json index 9b453949027..5270ac69704 100644 --- a/homeassistant/components/homekit/strings.json +++ b/homeassistant/components/homekit/strings.json @@ -7,7 +7,7 @@ }, "init": { "data": { - "mode": "Mode", + "mode": "[%key:common::config_flow::data::mode%]", "include_domains": "[%key:component::homekit::config::step::user::data::include_domains%]" }, "description": "HomeKit can be configured expose a bridge or a single accessory. In accessory mode, only a single entity can be used. Accessory mode is required for media players with the TV device class to function properly. Entities in the \u201cDomains to include\u201d will be exposed to HomeKit. You will be able to select which entities to include or exclude from this list on the next screen.", @@ -15,7 +15,7 @@ }, "include_exclude": { "data": { - "mode": "Mode", + "mode": "[%key:common::config_flow::data::mode%]", "entities": "Entities" }, "description": "Choose the entities to be exposed. In accessory mode, only a single entity is exposed. In bridge include mode, all entities in the domain will be exposed unless specific entities are selected. In bridge exclude mode, all entities in the domain will be exposed except for the excluded entities.", diff --git a/homeassistant/components/homekit/translations/af.json b/homeassistant/components/homekit/translations/af.json new file mode 100644 index 00000000000..a478a973df9 --- /dev/null +++ b/homeassistant/components/homekit/translations/af.json @@ -0,0 +1,11 @@ +{ + "options": { + "step": { + "init": { + "data": { + "mode": "Modus" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/ca.json b/homeassistant/components/homekit/translations/ca.json index 452cfc33365..63f461ea344 100644 --- a/homeassistant/components/homekit/translations/ca.json +++ b/homeassistant/components/homekit/translations/ca.json @@ -35,13 +35,6 @@ "description": "Comprova les c\u00e0meres que suporten fluxos nadius H.264. Si alguna c\u00e0mera not proporciona una sortida H.264, el sistema transcodificar\u00e0 el v\u00eddeo a H.264 per a HomeKit. La transcodificaci\u00f3 necessita una CPU potent i probablement no funcioni en ordinadors petits (SBC).", "title": "Selecci\u00f3 del c\u00f2dec de v\u00eddeo de c\u00e0mera" }, - "exclude": { - "data": { - "exclude_entities": "Entitats a excloure" - }, - "description": "Selecciona les entitats que NO vulguis que siguin enlla\u00e7ades.", - "title": "Exclusi\u00f3 d'entitats de l'enlla\u00e7 en dominis seleccionats" - }, "include_exclude": { "data": { "entities": "Entitats", @@ -63,6 +56,5 @@ "title": "Ajusta les opcions de HomeKit" } } - }, - "title": "Enlla\u00e7 HomeKit" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/cs.json b/homeassistant/components/homekit/translations/cs.json index d0bb01c9887..c070c852f09 100644 --- a/homeassistant/components/homekit/translations/cs.json +++ b/homeassistant/components/homekit/translations/cs.json @@ -31,18 +31,12 @@ "description": "Zkontrolujte v\u0161echny kamery, kter\u00e9 podporuj\u00ed nativn\u00ed streamy H.264. Pokud kamera nepodporuje stream H.264, syst\u00e9m video p\u0159ek\u00f3duje pro HomeKit na H.264. P\u0159ek\u00f3dov\u00e1n\u00ed vy\u017eaduje v\u00fdkonn\u00fd procesor a je pravd\u011bpodobn\u00e9, \u017ee nebude fungovat na po\u010d\u00edta\u010d\u00edch s jednou z\u00e1kladn\u00ed deskou.", "title": "Vyberte videokodek kamery." }, - "exclude": { - "data": { - "exclude_entities": "Entity, kter\u00e9 maj\u00ed b\u00fdt vylou\u010deny" - }, - "description": "Vyberte entity, kter\u00e9 NECHCETE p\u0159emostit.", - "title": "Vylou\u010dit entity ve vybran\u00fdch dom\u00e9n\u00e1ch z p\u0159emost\u011bn\u00ed" - }, "include_exclude": { "data": { "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": { @@ -57,6 +51,5 @@ "title": "Upravte mo\u017enosti HomeKit" } } - }, - "title": "HomeKit Bridge" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/de.json b/homeassistant/components/homekit/translations/de.json index 2a5b3ff8978..9b1ec14a1dd 100644 --- a/homeassistant/components/homekit/translations/de.json +++ b/homeassistant/components/homekit/translations/de.json @@ -5,13 +5,13 @@ }, "step": { "pairing": { - "title": "HomeKit Bridge verbinden\n" + "title": "HomeKit verbinden" }, "user": { "data": { "include_domains": "Einzubeziehende Domains" }, - "title": "HomeKit Bridge aktivieren\n" + "title": "HomeKit aktivieren" } } }, @@ -29,11 +29,6 @@ }, "title": "W\u00e4hlen Sie den Kamera-Video-Codec." }, - "exclude": { - "data": { - "exclude_entities": "Auszuschlie\u00dfende Entit\u00e4ten" - } - }, "include_exclude": { "data": { "entities": "Entit\u00e4ten", @@ -44,6 +39,7 @@ "data": { "mode": "Modus" }, + "description": "HomeKit kann so konfiguriert werden, dass eine Br\u00fccke oder ein einzelnes Zubeh\u00f6r verf\u00fcgbar gemacht wird. Im Zubeh\u00f6rmodus kann nur eine einzelne Entit\u00e4t verwendet werden. F\u00fcr Media Player mit der TV-Ger\u00e4teklasse ist ein Zubeh\u00f6rmodus erforderlich, damit sie ordnungsgem\u00e4\u00df funktionieren. Entit\u00e4ten in den \"einzuschlie\u00dfenden Dom\u00e4nen\" werden f\u00fcr HomeKit verf\u00fcgbar gemacht. Auf dem n\u00e4chsten Bildschirm k\u00f6nnen Sie ausw\u00e4hlen, welche Entit\u00e4ten in diese Liste aufgenommen oder aus dieser ausgeschlossen werden sollen.", "title": "W\u00e4hlen Sie die zu \u00fcberbr\u00fcckenden Dom\u00e4nen aus." }, "yaml": { @@ -51,6 +47,5 @@ "title": "Passen Sie die HomeKit Bridge-Optionen an" } } - }, - "title": "HomeKit Bridge" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/en.json b/homeassistant/components/homekit/translations/en.json index 00a59d7dbd9..39aa3522025 100644 --- a/homeassistant/components/homekit/translations/en.json +++ b/homeassistant/components/homekit/translations/en.json @@ -35,13 +35,6 @@ "description": "Check all cameras that support native H.264 streams. If the camera does not output a H.264 stream, the system will transcode the video to H.264 for HomeKit. Transcoding requires a performant CPU and is unlikely to work on single board computers.", "title": "Select camera video codec." }, - "exclude": { - "data": { - "exclude_entities": "Entities to exclude" - }, - "description": "Choose the entities that you do NOT want to be bridged.", - "title": "Exclude entities in selected domains from bridge" - }, "include_exclude": { "data": { "entities": "Entities", @@ -63,6 +56,5 @@ "title": "Adjust HomeKit Options" } } - }, - "title": "HomeKit Bridge" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/es-419.json b/homeassistant/components/homekit/translations/es-419.json index 9288849b8ee..45e42250177 100644 --- a/homeassistant/components/homekit/translations/es-419.json +++ b/homeassistant/components/homekit/translations/es-419.json @@ -35,13 +35,6 @@ "description": "Verifique todas las c\u00e1maras que admiten transmisiones H.264 nativas. Si la c\u00e1mara no emite una transmisi\u00f3n H.264, el sistema transcodificar\u00e1 el video a H.264 para HomeKit. La transcodificaci\u00f3n requiere una CPU de alto rendimiento y es poco probable que funcione en computadoras de placa \u00fanica.", "title": "Seleccione el c\u00f3dec de video de la c\u00e1mara." }, - "exclude": { - "data": { - "exclude_entities": "Entidades a excluir" - }, - "description": "Seleccione las entidades que NO desea puentear.", - "title": "Excluir entidades en dominios seleccionados del puente" - }, "init": { "data": { "include_domains": "Dominios para incluir" @@ -54,6 +47,5 @@ "title": "Ajuste las opciones de puente de HomeKit" } } - }, - "title": "Puente HomeKit" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/es.json b/homeassistant/components/homekit/translations/es.json index 7b8b7dbacc3..aeb75f838c1 100644 --- a/homeassistant/components/homekit/translations/es.json +++ b/homeassistant/components/homekit/translations/es.json @@ -35,13 +35,6 @@ "description": "Verifique todas las c\u00e1maras que admiten transmisiones H.264 nativas. Si la c\u00e1mara no emite una transmisi\u00f3n H.264, el sistema transcodificar\u00e1 el video a H.264 para HomeKit. La transcodificaci\u00f3n requiere una CPU de alto rendimiento y es poco probable que funcione en ordenadores de placa \u00fanica.", "title": "Seleccione el c\u00f3dec de video de la c\u00e1mara." }, - "exclude": { - "data": { - "exclude_entities": "Entidades a excluir" - }, - "description": "Elija las entidades que NO desea puentear.", - "title": "Excluir entidades en dominios seleccionados de bridge" - }, "include_exclude": { "data": { "entities": "Entidades", @@ -63,6 +56,5 @@ "title": "Ajustar las opciones del puente HomeKit" } } - }, - "title": "Pasarela Homekit" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/et.json b/homeassistant/components/homekit/translations/et.json index a712eee9438..76a78602bd3 100644 --- a/homeassistant/components/homekit/translations/et.json +++ b/homeassistant/components/homekit/translations/et.json @@ -1,6 +1,40 @@ { + "config": { + "abort": { + "port_name_in_use": "Sama nime v\u00f5i pordiga tarvik v\u00f5i sild on juba konfigureeritud." + }, + "step": { + "pairing": { + "description": "Niipea kui {name} on valmis, on sidumine saadaval jaotises \"Notifications\" kui \"HomeKit Bridge Setup\".", + "title": "HomeKiti sidumine" + }, + "user": { + "data": { + "auto_start": "Autostart (keela, kui kasutad Z-Wave'i v\u00f5i muud viivitatud k\u00e4ivituss\u00fcsteemi)", + "include_domains": "Kaasatavad domeenid" + }, + "description": "HomeKiti integreerimine v\u00f5imaldab teil p\u00e4\u00e4seda juurde HomeKiti \u00fcksustele Home Assistant. Sildire\u017eiimis on HomeKit Bridges piiratud 150 lisaseadmega, sealhulgas sild ise. Kui soovid \u00fchendada rohkem lisatarvikuid, on soovitatav kasutada erinevate domeenide jaoks mitut HomeKiti silda. \u00dcksuse \u00fcksikasjalik konfiguratsioon on esmase silla jaoks saadaval ainult YAML-i kaudu.", + "title": "Aktiveeri HomeKit" + } + } + }, "options": { "step": { + "advanced": { + "data": { + "auto_start": "Autostart (keela, kui kasutad Z-Wave'i v\u00f5i muud viivitatud k\u00e4ivituss\u00fcsteemi)", + "safe_mode": "Turvare\u017eiim (luba ainult siis, kui sidumine nurjub)" + }, + "description": "Neid s\u00e4tteid tuleb muuta ainult siis kui HomeKit ei t\u00f6\u00f6ta.", + "title": "T\u00e4psem seadistamine" + }, + "cameras": { + "data": { + "camera_copy": "Kaamerad, mis toetavad riistvaralist H.264 voogu" + }, + "description": "Vali k\u00f5iki kaameraid, mis toetavad kohalikku H.264 voogu. Kui kaamera ei edasta H.264 voogu, kodeerib s\u00fcsteem video HomeKiti jaoks versioonile H.264. \u00dcmberkodeerimine n\u00f5uab j\u00f5udsat protsessorit ja t\u00f5en\u00e4oliselt ei t\u00f6\u00f6ta see \u00fcheplaadilistes arvutites.", + "title": "Vali kaamera videokoodek." + }, "include_exclude": { "data": { "entities": "Olemid", @@ -11,10 +45,16 @@ }, "init": { "data": { + "include_domains": "Kaasatavad domeenid", "mode": "Re\u017eiim" - } + }, + "description": "HomeKiti saab seadistada silla v\u00f5i \u00fche lisaseadme avaldamiseks. Lisare\u017eiimis saab kasutada ainult \u00fchte \u00fcksust. Teleriseadmete klassiga meediumipleierite n\u00f5uetekohaseks toimimiseks on vaja lisare\u017eiimi. \u201eKaasatavate domeenide\u201d \u00fcksused puutuvad kokku HomeKitiga. J\u00e4rgmisel ekraanil saad valida, millised \u00fcksused sellesse loendisse lisada v\u00f5i sellest v\u00e4lja j\u00e4tta.", + "title": "Valige avaldatavad domeenid." + }, + "yaml": { + "description": "Seda sisestust juhitakse YAML-i kaudu", + "title": "Kohanda HomeKiti suvandeid" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/fi.json b/homeassistant/components/homekit/translations/fi.json index a19444d73f1..49a8c521a38 100644 --- a/homeassistant/components/homekit/translations/fi.json +++ b/homeassistant/components/homekit/translations/fi.json @@ -12,6 +12,5 @@ "title": "Lis\u00e4asetukset" } } - }, - "title": "HomeKit-silta" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/fr.json b/homeassistant/components/homekit/translations/fr.json index 4bac36a8467..be7d30c30ee 100644 --- a/homeassistant/components/homekit/translations/fr.json +++ b/homeassistant/components/homekit/translations/fr.json @@ -35,16 +35,18 @@ "description": "V\u00e9rifiez toutes les cam\u00e9ras prenant en charge les flux H.264 natifs. Si la cam\u00e9ra ne produit pas de flux H.264, le syst\u00e8me transcodera la vid\u00e9o en H.264 pour HomeKit. Le transcodage n\u00e9cessite un processeur performant et il est peu probable qu'il fonctionne sur des ordinateurs \u00e0 carte unique.", "title": "S\u00e9lectionnez le codec vid\u00e9o de la cam\u00e9ra." }, - "exclude": { + "include_exclude": { "data": { - "exclude_entities": "Entit\u00e9s \u00e0 exclure" + "entities": "Entit\u00e9s", + "mode": "Mode" }, - "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" + "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." @@ -54,6 +56,5 @@ "title": "Ajuster les options de la passerelle HomeKit" } } - }, - "title": "Passerelle HomeKit" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/it.json b/homeassistant/components/homekit/translations/it.json index 7f85eb85c63..7e9c8a05b9d 100644 --- a/homeassistant/components/homekit/translations/it.json +++ b/homeassistant/components/homekit/translations/it.json @@ -35,13 +35,6 @@ "description": "Controllare tutte le telecamere che supportano i flussi H.264 nativi. Se la videocamera non emette uno stream H.264, il sistema provveder\u00e0 a transcodificare il video in H.264 per HomeKit. La transcodifica richiede una CPU performante ed \u00e8 improbabile che funzioni su computer a scheda singola.", "title": "Seleziona il codec video della videocamera." }, - "exclude": { - "data": { - "exclude_entities": "Entit\u00e0 da escludere" - }, - "description": "Scegliere le entit\u00e0 che NON si desidera collegare.", - "title": "Escludere le entit\u00e0 dal bridge nei domini selezionati " - }, "include_exclude": { "data": { "entities": "Entit\u00e0", @@ -63,6 +56,5 @@ "title": "Modifica le opzioni di HomeKit" } } - }, - "title": "HomeKit Bridge" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/ko.json b/homeassistant/components/homekit/translations/ko.json index 5922fac7af6..7020cb163e2 100644 --- a/homeassistant/components/homekit/translations/ko.json +++ b/homeassistant/components/homekit/translations/ko.json @@ -35,13 +35,6 @@ "description": "\ub124\uc774\ud2f0\ube0c H.264 \uc2a4\ud2b8\ub9bc\uc744 \uc9c0\uc6d0\ud558\ub294 \ubaa8\ub4e0 \uce74\uba54\ub77c\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694. \uce74\uba54\ub77c\uac00 H.264 \uc2a4\ud2b8\ub9bc\uc744 \ucd9c\ub825\ud558\uc9c0 \uc54a\uc73c\uba74 \uc2dc\uc2a4\ud15c\uc740 \ube44\ub514\uc624\ub97c HomeKit \uc6a9 H.264 \ud3ec\ub9f7\uc73c\ub85c \ubcc0\ud658\uc2dc\ud0b5\ub2c8\ub2e4. \ud2b8\ub79c\uc2a4\ucf54\ub529 \ubcc0\ud658\uc5d0\ub294 \ub192\uc740 CPU \uc131\ub2a5\uc774 \ud544\uc694\ud558\uba70 \ub77c\uc988\ubca0\ub9ac\ud30c\uc774\uc640 \uac19\uc740 \ub2e8\uc77c \ubcf4\ub4dc \ucef4\ud4e8\ud130\uc5d0\uc11c\ub294 \uc791\ub3d9\ud558\uc9c0 \uc54a\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4.", "title": "\uce74\uba54\ub77c \ube44\ub514\uc624 \ucf54\ub371 \uc120\ud0dd\ud558\uae30" }, - "exclude": { - "data": { - "exclude_entities": "\uc81c\uc678\ud560 \uad6c\uc131\uc694\uc18c" - }, - "description": "\ube0c\ub9ac\uc9c0\ud558\uc9c0 \uc54a\uc73c\ub824\ub294 \uad6c\uc131\uc694\uc18c\ub97c \uc120\ud0dd\ud574\uc8fc\uc138\uc694.", - "title": "\ube0c\ub9ac\uc9c0\uc5d0\uc11c \uc120\ud0dd\ud55c \ub3c4\uba54\uc778\uc758 \uad6c\uc131\uc694\uc18c \uc81c\uc678\ud558\uae30" - }, "init": { "data": { "include_domains": "\ud3ec\ud568\ud560 \ub3c4\uba54\uc778" @@ -54,6 +47,5 @@ "title": "HomeKit \ube0c\ub9ac\uc9c0 \uc635\uc158 \uc870\uc815\ud558\uae30" } } - }, - "title": "HomeKit \ube0c\ub9ac\uc9c0" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/lb.json b/homeassistant/components/homekit/translations/lb.json index dd2583a2ad3..97c1bc23aa8 100644 --- a/homeassistant/components/homekit/translations/lb.json +++ b/homeassistant/components/homekit/translations/lb.json @@ -1,20 +1,20 @@ { "config": { "abort": { - "port_name_in_use": "Eng Bridge mat d\u00ebsem Numm oder Port ass sch konfigur\u00e9iert." + "port_name_in_use": "Een Accessoire oder eng Bridge mat d\u00ebsem Numm oder Port ass sch konfigur\u00e9iert." }, "step": { "pairing": { "description": "Soubaal {name} bridge prett ass, ass Kopplung disponibel an den 'Notifikatioune' als \"HomeKit Bridge Setup\".", - "title": "Pair Homekit Bridge" + "title": "Pair Homekit" }, "user": { "data": { "auto_start": "Autostart (d\u00e9aktiv\u00e9ier falls Z-Wave oder een aanere verz\u00f6gerte Start System benotzt g\u00ebtt)", "include_domains": "Domaine d\u00e9i solle abegraff ginn." }, - "description": "Eng HomeKit Bridge erlaabt et Home Assistant Entit\u00e9iten am HomeKit z'acc\u00e9d\u00e9ieren.HomeKit Bridges sinn op 150 Accessoire limit\u00e9iert, mat der Bridge selwer. Falls d'Bridge m\u00e9i w\u00e9i d\u00e9i max. Unzuel vun Accessoire soll \u00ebnnerst\u00ebtzen ass et recommand\u00e9iert verschidden HomeKit Bridges fir verschidden Domaine anzesetzen. Eng detaill\u00e9iert Konfiguratioun ass n\u00ebmme via YAML fir d\u00e9i prim\u00e4r Bridge verf\u00fcgbar.", - "title": "HomeKit Bridge aktiv\u00e9ieren" + "description": "HomeKit Integratioun erlaabt et Home Assistant Entit\u00e9iten am HomeKit z'acc\u00e9d\u00e9ieren. HomeKit Bridges sinn op 150 Accessoire limit\u00e9iert, mat der Bridge selwer. Falls d'Bridge m\u00e9i w\u00e9i d\u00e9i max. Unzuel vun Accessoire soll \u00ebnnerst\u00ebtzen ass et recommand\u00e9iert verschidden HomeKit Bridges fir verschidden Domaine anzesetzen. Eng detaill\u00e9iert Konfiguratioun ass n\u00ebmme via YAML fir d\u00e9i prim\u00e4r Bridge verf\u00fcgbar.", + "title": "HomeKit aktiv\u00e9ieren" } } }, @@ -25,7 +25,7 @@ "auto_start": "Autostart (d\u00e9aktiv\u00e9ier falls Z-Wave oder een aanere verz\u00f6gerte Start System benotzt g\u00ebtt)", "safe_mode": "Safe Mode (n\u00ebmmen aktiv\u00e9ieren wann Kopplung net geht)" }, - "description": "D\u00ebs Astellungen brauche n\u00ebmmen ajust\u00e9iert ze ginn fals d'HomeKit Bridge net funktion\u00e9iert.", + "description": "D\u00ebs Astellungen brauche n\u00ebmmen ajust\u00e9iert ze ginn falls HomeKit net funktion\u00e9iert.", "title": "Erweidert Konfiguratioun" }, "cameras": { @@ -35,25 +35,26 @@ "description": "Iwwerpr\u00e9if all Kamera op nativ H.264 \u00cbnnerst\u00ebtzung. Falls d'Kamera keng H.264 Stream Ausgab huet, transkod\u00e9iert de System de Video op H.264 fir Homekit. Transkod\u00e9iere ben\u00e9idegt eng performant CPU an w\u00e4ert net anst\u00e4nneg op Single Board Computer funktion\u00e9ieren.", "title": "Kamera Video Codec auswielen." }, - "exclude": { + "include_exclude": { "data": { - "exclude_entities": "Entit\u00e9iten d\u00e9i ausgeschloss solle ginn" + "entities": "Entit\u00e9iten", + "mode": "Modus" }, - "description": "Wiel d'Entit\u00e9iten aus d\u00e9i NET sollen iwwerbr\u00e9ckt ginn.", - "title": "Entit\u00e9iten aus den ausgewielten Domaine vun der Bridge ausschl\u00e9issen" + "description": "Entit\u00e9iten auswielen d\u00e9i expos\u00e9iert solle ginn. Am Acessoire Modus g\u00ebtt n\u00ebmmen eng eenzeg Entit\u00e9it expos\u00e9iert. Am Bridge include Modus, ginn all Entit\u00e9iten vum Domaine expos\u00e9iert ausser spezifesch ausgewielten Entit\u00e9iten. Am Bride Exclude Modus, ginn all Entit\u00e9ite vum Domaine expos\u00e9iert ausser d\u00e9i ausgeschlossen Entit\u00e9iten.", + "title": "Entit\u00e9iten auswielen d\u00e9i expos\u00e9iert solle ginn" }, "init": { "data": { - "include_domains": "Domaine d\u00e9i solle ageschloss ginn" + "include_domains": "Domaine d\u00e9i solle ageschloss ginn", + "mode": "Modus" }, - "description": "Entit\u00e9iten an den \"Domaine fir anzeschl\u00e9issen\" ginn op HomeKit iwwerbr\u00e9ckt. Am n\u00e4chste Schr\u00ebtt k\u00ebnnen d'Entit\u00e9iten ausgewielt ginn d\u00e9i sollen vun d\u00ebser L\u00ebscht ausgeschloss ginn.", - "title": "Domaine auswielen fir an d'Bridge" + "description": "HomeKit kann entweder als Bridge oder Single Accessoire konfigur\u00e9iert ginn. Am Acessoire Modus ka n\u00ebmmen eng eenzeg Entit\u00e9it benotzt ginn. D\u00ebse Modus ass n\u00e9ideg fir de korretke Betrib vu Medie Spiller vun der TV Klasse. Entit\u00e9ite an der \"Domaine fir z'expos\u00e9ieren\" ginn mat HomeKit expos\u00e9iert. Du kanns am n\u00e4chste Schr\u00ebtt auswielen w\u00e9ieng Entit\u00e9ite aus oder ageschloss solle ginn.", + "title": "Domaine auswielen fir z'expos\u00e9ieren" }, "yaml": { "description": "D\u00ebs Entr\u00e9e ass via YAML kontroll\u00e9iert", - "title": "HomeKit Bridge Optioune ajust\u00e9ieren" + "title": "HomeKit Optioune ajust\u00e9ieren" } } - }, - "title": "HomeKit Bridge" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/nl.json b/homeassistant/components/homekit/translations/nl.json index 3c3a019c3ed..487544cd5b5 100644 --- a/homeassistant/components/homekit/translations/nl.json +++ b/homeassistant/components/homekit/translations/nl.json @@ -5,12 +5,15 @@ }, "step": { "pairing": { + "description": "Zodra de {name} klaar is, is het koppelen beschikbaar in \"Meldingen\" als \"HomeKit Bridge Setup\".", "title": "Koppel HomeKit Bridge" }, "user": { "data": { - "auto_start": "Automatisch starten (uitschakelen als u Z-Wave of een ander vertraagd startsysteem gebruikt)" + "auto_start": "Automatisch starten (uitschakelen als u Z-Wave of een ander vertraagd startsysteem gebruikt)", + "include_domains": "Domeinen om op te nemen" }, + "description": "De HomeKit-integratie geeft u toegang tot uw Home Assistant-entiteiten in HomeKit. In bridge-modus zijn HomeKit-bruggen beperkt tot 150 accessoires per exemplaar, inclusief de brug zelf. Als u meer dan het maximale aantal accessoires wilt overbruggen, is het aan te raden om meerdere HomeKit-bridges voor verschillende domeinen te gebruiken. Gedetailleerde entiteitsconfiguratie is alleen beschikbaar via YAML voor de primaire bridge.", "title": "Activeer HomeKit Bridge" } } @@ -19,22 +22,24 @@ "step": { "advanced": { "data": { + "auto_start": "Autostart (uitschakelen bij gebruik van Z-Wave of een ander vertraagd startsysteem)", "safe_mode": "Veilige modus (alleen inschakelen als het koppelen mislukt)" }, "description": "Deze instellingen hoeven alleen te worden aangepast als HomeKit niet functioneert.", "title": "Geavanceerde configuratie" }, - "exclude": { + "cameras": { "data": { - "exclude_entities": "Uit te sluiten entiteiten" + "camera_copy": "Camera's die native H.264-streams ondersteunen" }, - "description": "Kies de entiteiten die u NIET wilt overbruggen.", - "title": "Entiteiten in geselecteerde domeinen uitsluiten van bridge" + "description": "Controleer alle camera's die native H.264-streams ondersteunen. Als de camera geen H.264-stream uitvoert, transcodeert het systeem de video naar H.264 voor HomeKit. Transcodering vereist een performante CPU en het is onwaarschijnlijk dat dit werkt op computers met \u00e9\u00e9n bord.", + "title": "Selecteer de videocodec van de camera." }, "init": { "data": { "include_domains": "Op te nemen domeinen" }, + "description": "HomeKit kan worden geconfigureerd om een brug of een enkel accessoire te tonen. In de accessoiremodus kan slechts \u00e9\u00e9n entiteit worden gebruikt. De accessoiremodus is vereist om mediaspelers met de tv-apparaatklasse correct te laten werken. Entiteiten in de \"Op te nemen domeinen\" zullen worden blootgesteld aan HomeKit. U kunt op het volgende scherm selecteren welke entiteiten u wilt opnemen of uitsluiten van deze lijst.", "title": "Selecteer domeinen om zichtbaar te maken." }, "yaml": { @@ -42,6 +47,5 @@ "title": "Pas de HomeKit Bridge-opties aan" } } - }, - "title": "HomeKit Bridge" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/no.json b/homeassistant/components/homekit/translations/no.json index 6380493d67c..7eff4d37668 100644 --- a/homeassistant/components/homekit/translations/no.json +++ b/homeassistant/components/homekit/translations/no.json @@ -35,13 +35,6 @@ "description": "Sjekk alle kameraer som st\u00f8tter opprinnelige H.264-str\u00f8mmer. Hvis kameraet ikke sender ut en H.264-str\u00f8m, vil systemet omkode videoen til H.264 for HomeKit. Transkoding krever en potent prosessor og er usannsynlig \u00e5 fungere p\u00e5 enkeltkortdatamaskiner som Raspberry Pi o.l.", "title": "Velg videokodek for kamera." }, - "exclude": { - "data": { - "exclude_entities": "Entiteter \u00e5 ekskludere" - }, - "description": "Velg entitetene du IKKE vil koble til broen.", - "title": "Ekskluder entiteter i utvalgte domener fra bro" - }, "include_exclude": { "data": { "entities": "Entiteter", @@ -63,6 +56,5 @@ "title": "Juster HomeKit-alternativer" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/pl.json b/homeassistant/components/homekit/translations/pl.json index 218ff81d402..3210f0f4430 100644 --- a/homeassistant/components/homekit/translations/pl.json +++ b/homeassistant/components/homekit/translations/pl.json @@ -6,7 +6,7 @@ "step": { "pairing": { "description": "Gdy tylko {name} b\u0119dzie gotowy, opcja parowania b\u0119dzie dost\u0119pna w \u201ePowiadomieniach\u201d jako \u201eKonfiguracja mostka HomeKit\u201d.", - "title": "Sparuj z HomeKit" + "title": "Parowanie z HomeKit" }, "user": { "data": { @@ -35,13 +35,6 @@ "description": "Sprawd\u017a, czy wszystkie kamery obs\u0142uguj\u0105 kodek H.264. Je\u015bli kamera nie wysy\u0142a strumienia skompresowanego kodekiem H.264, system b\u0119dzie transkodowa\u0142 wideo do H.264 dla HomeKit. Transkodowanie wymaga wydajnego procesora i jest ma\u0142o prawdopodobne, aby dzia\u0142a\u0142o na komputerach jednop\u0142ytkowych.", "title": "Wyb\u00f3r kodeka wideo kamery" }, - "exclude": { - "data": { - "exclude_entities": "Wykluczone encje" - }, - "description": "Wybierz encje, kt\u00f3rych NIE chcesz zmostkowa\u0107.", - "title": "Wykluczenie encji z wybranych domen" - }, "include_exclude": { "data": { "entities": "Encje", @@ -63,6 +56,5 @@ "title": "Dostosowywanie opcji HomeKit" } } - }, - "title": "Mostek HomeKit" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/pt-BR.json b/homeassistant/components/homekit/translations/pt-BR.json index 149c16d4288..1ef802a9202 100644 --- a/homeassistant/components/homekit/translations/pt-BR.json +++ b/homeassistant/components/homekit/translations/pt-BR.json @@ -6,11 +6,6 @@ }, "cameras": { "title": "Selecione o codec de v\u00eddeo da c\u00e2mera." - }, - "exclude": { - "data": { - "exclude_entities": "Entidades para excluir" - } } } } diff --git a/homeassistant/components/homekit/translations/ru.json b/homeassistant/components/homekit/translations/ru.json index 87175265299..3cb5e84936a 100644 --- a/homeassistant/components/homekit/translations/ru.json +++ b/homeassistant/components/homekit/translations/ru.json @@ -35,13 +35,6 @@ "description": "\u0415\u0441\u043b\u0438 \u043a\u0430\u043c\u0435\u0440\u0430 \u043d\u0435 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u043f\u043e\u0442\u043e\u043a H.264, \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u0442 \u0432\u0438\u0434\u0435\u043e \u0432 H.264 \u0434\u043b\u044f HomeKit. \u0422\u0440\u0430\u043d\u0441\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u044b\u0441\u043e\u043a\u043e\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430 \u0438 \u0432\u0440\u044f\u0434 \u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 \u043e\u0434\u043d\u043e\u043f\u043b\u0430\u0442\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430\u0445.", "title": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0432\u0438\u0434\u0435\u043e\u043a\u043e\u0434\u0435\u043a \u043a\u0430\u043c\u0435\u0440\u044b." }, - "exclude": { - "data": { - "exclude_entities": "\u0418\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u044b" - }, - "description": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u041d\u0415 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u044b \u0432 HomeKit.", - "title": "\u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043c\u0435\u043d\u0430\u0445" - }, "include_exclude": { "data": { "entities": "\u041e\u0431\u044a\u0435\u043a\u0442\u044b", @@ -63,6 +56,5 @@ "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 HomeKit" } } - }, - "title": "HomeKit Bridge" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/sl.json b/homeassistant/components/homekit/translations/sl.json index 0416e80b98d..af2823da6d4 100644 --- a/homeassistant/components/homekit/translations/sl.json +++ b/homeassistant/components/homekit/translations/sl.json @@ -28,12 +28,17 @@ "description": "Te nastavitve je treba prilagoditi le, \u010de most HomeKit ni funkcionalen.", "title": "Napredna konfiguracija" }, - "exclude": { + "cameras": { "data": { - "exclude_entities": "Subjekti, ki jih je treba izklju\u010diti" + "camera_copy": "Kamere, ki podpirajo izvorne tokove H.264" }, - "description": "Izberite entitete, ki jih NE \u017eelite premostiti.", - "title": "Iz mostu izklju\u010dite subjekte izbranih domen" + "title": "Izberite video kodek kamere." + }, + "include_exclude": { + "data": { + "entities": "Entitete" + }, + "title": "Izberite entitete, ki jih \u017eelite izpostaviti" }, "init": { "data": { @@ -47,6 +52,5 @@ "title": "Prilagodi mo\u017enosti mosta HomeKit." } } - }, - "title": "HomeKit Most" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/sv.json b/homeassistant/components/homekit/translations/sv.json index 7b03ac36f3b..5aa9507a85d 100644 --- a/homeassistant/components/homekit/translations/sv.json +++ b/homeassistant/components/homekit/translations/sv.json @@ -9,6 +9,5 @@ "title": "V\u00e4lj kamerans videoavkodare." } } - }, - "title": "HomeKit-brygga" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/zh-Hans.json b/homeassistant/components/homekit/translations/zh-Hans.json index 4e421f3261a..d11234f4c6d 100644 --- a/homeassistant/components/homekit/translations/zh-Hans.json +++ b/homeassistant/components/homekit/translations/zh-Hans.json @@ -35,13 +35,6 @@ "description": "\u67e5\u627e\u6240\u6709\u652f\u6301\u539f\u751f H.264 \u63a8\u6d41\u7684\u6444\u50cf\u673a\u3002\u5982\u679c\u6444\u50cf\u673a\u8f93\u51fa\u7684\u4e0d\u662f H.264 \u6d41\uff0c\u7cfb\u7edf\u4f1a\u5c06\u89c6\u9891\u8f6c\u7801\u4e3a H.264 \u4ee5\u4f9b HomeKit \u4f7f\u7528\u3002\u8f6c\u7801\u9700\u8981\u9ad8\u6027\u80fd\u7684 CPU\uff0c\u56e0\u6b64\u5728\u5f00\u53d1\u677f\u8ba1\u7b97\u673a\u4e0a\u5f88\u96be\u5b8c\u6210\u3002", "title": "\u8bf7\u9009\u62e9\u6444\u50cf\u673a\u7684\u89c6\u9891\u7f16\u7801\u3002" }, - "exclude": { - "data": { - "exclude_entities": "\u8981\u6392\u9664\u7684\u5b9e\u4f53" - }, - "description": "\u9009\u62e9\u4e0d\u9700\u8981\u6865\u63a5\u7684\u5b9e\u4f53\u3002", - "title": "\u5bf9\u9009\u62e9\u7684\u57df\u6392\u9664\u5b9e\u4f53" - }, "include_exclude": { "data": { "entities": "\u5b9e\u4f53", @@ -63,6 +56,5 @@ "title": "\u8c03\u6574 HomeKit \u9009\u9879" } } - }, - "title": "HomeKit \u6865\u63a5\u5668" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/zh-Hant.json b/homeassistant/components/homekit/translations/zh-Hant.json index f8c78e39b25..e3e9247e7c4 100644 --- a/homeassistant/components/homekit/translations/zh-Hant.json +++ b/homeassistant/components/homekit/translations/zh-Hant.json @@ -35,13 +35,6 @@ "description": "\u6aa2\u67e5\u6240\u6709\u652f\u63f4\u539f\u751f H.264 \u4e32\u6d41\u4e4b\u651d\u5f71\u6a5f\u3002\u5047\u5982\u651d\u5f71\u6a5f\u4e0d\u652f\u63f4 H.264 \u4e32\u6d41\u3001\u7cfb\u7d71\u5c07\u6703\u91dd\u5c0d Homekit \u9032\u884c H.264 \u8f49\u78bc\u3002\u8f49\u78bc\u5c07\u9700\u8981\u4f7f\u7528 CPU \u9032\u884c\u904b\u7b97\u3001\u55ae\u6676\u7247\u96fb\u8166\u53ef\u80fd\u6703\u906d\u9047\u6548\u80fd\u554f\u984c\u3002", "title": "\u9078\u64c7\u651d\u5f71\u6a5f\u7de8\u78bc\u3002" }, - "exclude": { - "data": { - "exclude_entities": "\u6392\u9664\u5be6\u9ad4" - }, - "description": "\u9078\u64c7\u4e0d\u9032\u884c\u6a4b\u63a5\u7684\u5be6\u9ad4\u3002", - "title": "\u65bc\u6240\u9078 Domain \u4e2d\u6240\u8981\u6392\u9664\u7684\u5be6\u9ad4" - }, "include_exclude": { "data": { "entities": "\u5be6\u9ad4", @@ -63,6 +56,5 @@ "title": "\u8abf\u6574 HomeKit \u9078\u9805" } } - }, - "title": "HomeKit Bridge" + } } \ No newline at end of file diff --git a/homeassistant/components/homekit/type_covers.py b/homeassistant/components/homekit/type_covers.py index d8d8da5a974..75cabf14483 100644 --- a/homeassistant/components/homekit/type_covers.py +++ b/homeassistant/components/homekit/type_covers.py @@ -26,22 +26,26 @@ from homeassistant.const import ( SERVICE_STOP_COVER, STATE_CLOSED, STATE_CLOSING, + STATE_ON, STATE_OPEN, STATE_OPENING, ) from homeassistant.core import callback +from homeassistant.helpers.event import async_track_state_change_event from .accessories import TYPES, HomeAccessory, debounce from .const import ( + ATTR_OBSTRUCTION_DETECTED, CHAR_CURRENT_DOOR_STATE, CHAR_CURRENT_POSITION, CHAR_CURRENT_TILT_ANGLE, CHAR_HOLD_POSITION, + CHAR_OBSTRUCTION_DETECTED, CHAR_POSITION_STATE, CHAR_TARGET_DOOR_STATE, CHAR_TARGET_POSITION, CHAR_TARGET_TILT_ANGLE, - DEVICE_PRECISION_LEEWAY, + CONF_LINKED_OBSTRUCTION_SENSOR, HK_DOOR_CLOSED, HK_DOOR_CLOSING, HK_DOOR_OPEN, @@ -74,7 +78,6 @@ DOOR_TARGET_HASS_TO_HK = { STATE_CLOSING: HK_DOOR_CLOSED, } - _LOGGER = logging.getLogger(__name__) @@ -98,8 +101,55 @@ class GarageDoorOpener(HomeAccessory): self.char_target_state = serv_garage_door.configure_char( CHAR_TARGET_DOOR_STATE, value=0, setter_callback=self.set_state ) + self.char_obstruction_detected = serv_garage_door.configure_char( + CHAR_OBSTRUCTION_DETECTED, value=False + ) + + self.linked_obstruction_sensor = self.config.get(CONF_LINKED_OBSTRUCTION_SENSOR) + if self.linked_obstruction_sensor: + self._async_update_obstruction_state( + self.hass.states.get(self.linked_obstruction_sensor) + ) + self.async_update_state(state) + async def run_handler(self): + """Handle accessory driver started event. + + Run inside the Home Assistant event loop. + """ + if self.linked_obstruction_sensor: + async_track_state_change_event( + self.hass, + [self.linked_obstruction_sensor], + self._async_update_obstruction_event, + ) + + await super().run_handler() + + @callback + def _async_update_obstruction_event(self, event): + """Handle state change event listener callback.""" + self._async_update_obstruction_state(event.data.get("new_state")) + + @callback + def _async_update_obstruction_state(self, new_state): + """Handle linked obstruction sensor state change to update HomeKit value.""" + if not new_state: + return + + detected = new_state.state == STATE_ON + if self.char_obstruction_detected.value == detected: + return + + self.char_obstruction_detected.set_value(detected) + _LOGGER.debug( + "%s: Set linked obstruction %s sensor to %d", + self.entity_id, + self.linked_obstruction_sensor, + detected, + ) + def set_state(self, value): """Change garage state if call came from HomeKit.""" _LOGGER.debug("%s: Set state to %d", self.entity_id, value) @@ -121,6 +171,13 @@ class GarageDoorOpener(HomeAccessory): target_door_state = DOOR_TARGET_HASS_TO_HK.get(hass_state) current_door_state = DOOR_CURRENT_HASS_TO_HK.get(hass_state) + if ATTR_OBSTRUCTION_DETECTED in new_state.attributes: + obstruction_detected = ( + new_state.attributes[ATTR_OBSTRUCTION_DETECTED] is True + ) + if self.char_obstruction_detected.value != obstruction_detected: + self.char_obstruction_detected.set_value(obstruction_detected) + if ( target_door_state is not None and self.char_target_state.value != target_door_state @@ -147,7 +204,6 @@ class OpeningDeviceBase(HomeAccessory): self.features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) self._supports_stop = self.features & SUPPORT_STOP - self._homekit_target_tilt = None self.chars = [] if self._supports_stop: self.chars.append(CHAR_HOLD_POSITION) @@ -180,7 +236,6 @@ class OpeningDeviceBase(HomeAccessory): @debounce def set_tilt(self, value): """Set tilt to value if call came from HomeKit.""" - self._homekit_target_tilt = value _LOGGER.info("%s: Set tilt to %d", self.entity_id, value) # HomeKit sends values between -90 and 90. @@ -203,17 +258,8 @@ class OpeningDeviceBase(HomeAccessory): current_tilt = int(current_tilt) if self.char_current_tilt.value != current_tilt: self.char_current_tilt.set_value(current_tilt) - - # We have to assume that the device has worse precision than HomeKit. - # If it reports back a state that is only _close_ to HK's requested - # state, we'll "fix" what HomeKit requested so that it won't appear - # out of sync. - if self._homekit_target_tilt is None or abs( - current_tilt - self._homekit_target_tilt < DEVICE_PRECISION_LEEWAY - ): - if self.char_target_tilt.value != current_tilt: - self.char_target_tilt.set_value(current_tilt) - self._homekit_target_tilt = None + if self.char_target_tilt.value != current_tilt: + self.char_target_tilt.set_value(current_tilt) class OpeningDevice(OpeningDeviceBase, HomeAccessory): @@ -226,7 +272,6 @@ class OpeningDevice(OpeningDeviceBase, HomeAccessory): """Initialize a WindowCovering accessory object.""" super().__init__(*args, category=category, service=service) state = self.hass.states.get(self.entity_id) - self._homekit_target = None self.char_current_position = self.serv_cover.configure_char( CHAR_CURRENT_POSITION, value=0 @@ -243,8 +288,6 @@ class OpeningDevice(OpeningDeviceBase, HomeAccessory): def move_cover(self, value): """Move cover to value if call came from HomeKit.""" _LOGGER.debug("%s: Set position to %d", self.entity_id, value) - self._homekit_target = value - params = {ATTR_ENTITY_ID: self.entity_id, ATTR_POSITION: value} self.call_service(DOMAIN, SERVICE_SET_COVER_POSITION, params, value) @@ -256,28 +299,12 @@ class OpeningDevice(OpeningDeviceBase, HomeAccessory): current_position = int(current_position) if self.char_current_position.value != current_position: self.char_current_position.set_value(current_position) + if self.char_target_position.value != current_position: + self.char_target_position.set_value(current_position) - # We have to assume that the device has worse precision than HomeKit. - # If it reports back a state that is only _close_ to HK's requested - # state, we'll "fix" what HomeKit requested so that it won't appear - # out of sync. - if ( - self._homekit_target is None - or abs(current_position - self._homekit_target) - < DEVICE_PRECISION_LEEWAY - ): - if self.char_target_position.value != current_position: - self.char_target_position.set_value(current_position) - self._homekit_target = None - if new_state.state == STATE_OPENING: - if self.char_position_state.value != HK_POSITION_GOING_TO_MAX: - self.char_position_state.set_value(HK_POSITION_GOING_TO_MAX) - elif new_state.state == STATE_CLOSING: - if self.char_position_state.value != HK_POSITION_GOING_TO_MIN: - self.char_position_state.set_value(HK_POSITION_GOING_TO_MIN) - else: - if self.char_position_state.value != HK_POSITION_STOPPED: - self.char_position_state.set_value(HK_POSITION_STOPPED) + position_state = _hass_state_to_position_start(new_state.state) + if self.char_position_state.value != position_state: + self.char_position_state.set_value(position_state) super().async_update_state(new_state) @@ -368,14 +395,17 @@ class WindowCoveringBasic(OpeningDeviceBase, HomeAccessory): self.char_current_position.set_value(hk_position) if self.char_target_position.value != hk_position: self.char_target_position.set_value(hk_position) - if new_state.state == STATE_OPENING: - if self.char_position_state.value != HK_POSITION_GOING_TO_MAX: - self.char_position_state.set_value(HK_POSITION_GOING_TO_MAX) - elif new_state.state == STATE_CLOSING: - if self.char_position_state.value != HK_POSITION_GOING_TO_MIN: - self.char_position_state.set_value(HK_POSITION_GOING_TO_MIN) - else: - if self.char_position_state.value != HK_POSITION_STOPPED: - self.char_position_state.set_value(HK_POSITION_STOPPED) + position_state = _hass_state_to_position_start(new_state.state) + if self.char_position_state.value != position_state: + self.char_position_state.set_value(position_state) super().async_update_state(new_state) + + +def _hass_state_to_position_start(state): + """Convert hass state to homekit position state.""" + if state == STATE_OPENING: + return HK_POSITION_GOING_TO_MAX + if state == STATE_CLOSING: + return HK_POSITION_GOING_TO_MIN + return HK_POSITION_STOPPED diff --git a/homeassistant/components/homekit/util.py b/homeassistant/components/homekit/util.py index 2199371c00d..453ae13d846 100644 --- a/homeassistant/components/homekit/util.py +++ b/homeassistant/components/homekit/util.py @@ -37,6 +37,7 @@ from .const import ( CONF_LINKED_DOORBELL_SENSOR, CONF_LINKED_HUMIDITY_SENSOR, CONF_LINKED_MOTION_SENSOR, + CONF_LINKED_OBSTRUCTION_SENSOR, CONF_LOW_BATTERY_THRESHOLD, CONF_MAX_FPS, CONF_MAX_HEIGHT, @@ -138,6 +139,15 @@ HUMIDIFIER_SCHEMA = BASIC_INFO_SCHEMA.extend( {vol.Optional(CONF_LINKED_HUMIDITY_SENSOR): cv.entity_domain(sensor.DOMAIN)} ) + +COVER_SCHEMA = BASIC_INFO_SCHEMA.extend( + { + vol.Optional(CONF_LINKED_OBSTRUCTION_SENSOR): cv.entity_domain( + binary_sensor.DOMAIN + ) + } +) + CODE_SCHEMA = BASIC_INFO_SCHEMA.extend( {vol.Optional(ATTR_CODE, default=None): vol.Any(None, cv.string)} ) @@ -247,6 +257,9 @@ def validate_entity_config(values): elif domain == "humidifier": config = HUMIDIFIER_SCHEMA(config) + elif domain == "cover": + config = COVER_SCHEMA(config) + else: config = BASIC_INFO_SCHEMA(config) @@ -344,7 +357,7 @@ class HomeKitSpeedMapping: 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/homekit_controller/cover.py b/homeassistant/components/homekit_controller/cover.py index db824ea060d..a79ef5d1ee7 100644 --- a/homeassistant/components/homekit_controller/cover.py +++ b/homeassistant/components/homekit_controller/cover.py @@ -116,9 +116,7 @@ class HomeKitGarageDoorCover(HomeKitEntity, CoverEntity): obstruction_detected = self.service.value( CharacteristicsTypes.OBSTRUCTION_DETECTED ) - if not obstruction_detected: - return {} - return {"obstruction-detected": obstruction_detected} + return {"obstruction-detected": obstruction_detected is True} class HomeKitWindowCover(HomeKitEntity, CoverEntity): diff --git a/homeassistant/components/homekit_controller/translations/bg.json b/homeassistant/components/homekit_controller/translations/bg.json index bca0eeec380..8e2762f9f32 100644 --- a/homeassistant/components/homekit_controller/translations/bg.json +++ b/homeassistant/components/homekit_controller/translations/bg.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "\u0413\u0440\u0435\u0448\u0435\u043d HomeKit \u043a\u043e\u0434. \u041c\u043e\u043b\u044f, \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u0442\u0435 \u0433\u043e \u0438 \u043e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e.", - "busy_error": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u043e\u0442\u043a\u0430\u0437\u0432\u0430 \u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u0438 \u0441\u0434\u0432\u043e\u044f\u0432\u0430\u043d\u0435, \u0442\u044a\u0439 \u043a\u0430\u0442\u043e \u0432\u0435\u0447\u0435 \u0441\u0435 \u0441\u0434\u0432\u043e\u044f \u0441 \u0434\u0440\u0443\u0433 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440.", "max_peers_error": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u043e\u0442\u043a\u0430\u0437\u0430 \u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u0438 \u0441\u0434\u0432\u043e\u044f\u0432\u0430\u043d\u0435, \u0442\u044a\u0439 \u043a\u0430\u0442\u043e \u043d\u044f\u043c\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0437\u0430 \u0441\u0434\u0432\u043e\u044f\u0432\u0430\u043d\u0435.", - "max_tries_error": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u043e\u0442\u043a\u0430\u0437\u0432\u0430 \u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u0438 \u0441\u0434\u0432\u043e\u044f\u0432\u0430\u043d\u0435, \u0442\u044a\u0439 \u043a\u0430\u0442\u043e \u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e \u043f\u043e\u0432\u0435\u0447\u0435 \u043e\u0442 100 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0438 \u043e\u043f\u0438\u0442\u0430 \u0437\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0430\u0446\u0438\u044f.", "pairing_failed": "\u0412\u044a\u0437\u043d\u0438\u043a\u043d\u0430 \u043d\u0435\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0435\u043d\u043e \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u043e\u043f\u0438\u0442 \u0437\u0430 \u0441\u0434\u0432\u043e\u044f\u0432\u0430\u043d\u0435 \u0441 \u0442\u043e\u0432\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e. \u0422\u043e\u0432\u0430 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043d \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0438\u043b\u0438 \u0432\u0430\u0448\u0435\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043c\u043e\u0436\u0435 \u0434\u0430 \u043d\u0435 \u0441\u0435 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u0430.", "unable_to_pair": "\u041d\u0435\u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442 \u0437\u0430 \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435, \u043c\u043e\u043b\u044f \u043e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e.", "unknown_error": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u0441\u044a\u043e\u0431\u0449\u0438 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430. \u0421\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435\u0442\u043e \u0431\u0435 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e." diff --git a/homeassistant/components/homekit_controller/translations/ca.json b/homeassistant/components/homekit_controller/translations/ca.json index 8b1dd8eca18..0ce5c2b2ba3 100644 --- a/homeassistant/components/homekit_controller/translations/ca.json +++ b/homeassistant/components/homekit_controller/translations/ca.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "Codi HomeKit incorrecte. Verifica'l i torna-ho a provar.", - "busy_error": "El dispositiu ha refusat la vinculaci\u00f3 perqu\u00e8 actualment ho est\u00e0 intentant amb un altre controlador diferent.", "max_peers_error": "El dispositiu ha refusat la vinculaci\u00f3 perqu\u00e8 no t\u00e9 suficient espai lliure.", - "max_tries_error": "El dispositiu ha refusat la vinculaci\u00f3 perqu\u00e8 ha rebut m\u00e9s de 100 intents d'autenticaci\u00f3 fallits.", "pairing_failed": "S'ha produ\u00eft un error mentre s'intentava la vinculaci\u00f3 amb aquest dispositiu. Pot ser que sigui un error temporal o pot ser que el teu dispositiu encara no sigui compatible.", - "protocol_error": "Error en comunicar-se amb l'accessori. \u00c9s possible que el dispositiu no estigui en mode de vinculaci\u00f3, potser cal pr\u00e9mer un bot\u00f3 f\u00edsic o virtual.", "unable_to_pair": "No s'ha pogut vincular, torna-ho a provar.", "unknown_error": "El dispositiu ha em\u00e8s un error desconegut. Vinculaci\u00f3 fallida." }, @@ -41,10 +38,6 @@ "description": "\u00c9s possible que el dispositiu no estigui en mode de vinculaci\u00f3, potser cal pr\u00e9mer un bot\u00f3 f\u00edsic o virtual. Assegura't que el dispositiu est\u00e0 en mode vinculaci\u00f3 o prova de reiniciar-lo, despr\u00e9s, segueix amb la vinculaci\u00f3.", "title": "Error en comunicar-se amb l'accessori" }, - "try_pair_later": { - "description": "Assegura't que el dispositiu estigui en mode vinculaci\u00f3 o prova de reiniciar-lo, despr\u00e9s continua reiniciant la vinculaci\u00f3.", - "title": "Vinculaci\u00f3 no disponible" - }, "user": { "data": { "device": "Dispositiu" diff --git a/homeassistant/components/homekit_controller/translations/cs.json b/homeassistant/components/homekit_controller/translations/cs.json index 3b38689af5a..9a2159eda05 100644 --- a/homeassistant/components/homekit_controller/translations/cs.json +++ b/homeassistant/components/homekit_controller/translations/cs.json @@ -7,15 +7,13 @@ "already_paired": "Toto p\u0159\u00edslu\u0161enstv\u00ed je ji\u017e sp\u00e1rov\u00e1no s jin\u00fdm za\u0159\u00edzen\u00edm. Resetujte p\u0159\u00edslu\u0161enstv\u00ed a zkuste to znovu.", "ignored_model": "Podpora pro tento model je v HomeKit blokov\u00e1na, proto\u017ee je k dispozici nativn\u00ed integrace s v\u00edce funkcemi.", "invalid_config_entry": "Toto za\u0159\u00edzen\u00ed vypad\u00e1, \u017ee je p\u0159ipraven\u00e9 ke sp\u00e1rov\u00e1n\u00ed, ale v Home Assistant ji\u017e existuje konfliktn\u00ed polo\u017eka konfigurace, kterou je t\u0159eba nejprve odebrat.", + "invalid_properties": "Neplatn\u00e9 vlastnosti ozn\u00e1men\u00e9 za\u0159\u00edzen\u00edm.", "no_devices": "Nebyla nalezena \u017e\u00e1dn\u00e1 nesp\u00e1rov\u00e1 za\u0159\u00edzen\u00ed" }, "error": { "authentication_error": "Nespr\u00e1vn\u00fd HomeKit k\u00f3d. Zkontrolujte to a zkuste to znovu.", - "busy_error": "Za\u0159\u00edzen\u00ed odm\u00edtlo p\u0159idat p\u00e1rov\u00e1n\u00ed, proto\u017ee je ji\u017e sp\u00e1rov\u00e1no s jin\u00fdm ovlada\u010dem.", "max_peers_error": "Za\u0159\u00edzen\u00ed odm\u00edtlo p\u0159idat p\u00e1rov\u00e1n\u00ed, proto\u017ee nem\u00e1 voln\u00e9 \u00falo\u017ei\u0161t\u011b pro p\u00e1rov\u00e1n\u00ed.", - "max_tries_error": "Za\u0159\u00edzen\u00ed odm\u00edtlo p\u0159idat p\u00e1rov\u00e1n\u00ed, proto\u017ee p\u0159ijalo v\u00edce ne\u017e 100 ne\u00fasp\u011b\u0161n\u00fdch pokus\u016f o ov\u011b\u0159en\u00ed.", "pairing_failed": "P\u0159i pokusu o sp\u00e1rov\u00e1n\u00ed s t\u00edmto za\u0159\u00edzen\u00edm do\u0161lo k neo\u010dek\u00e1van\u00e9 chyb\u011b. M\u016f\u017ee se jednat o do\u010dasn\u00e9 selh\u00e1n\u00ed nebo va\u0161e za\u0159\u00edzen\u00ed nemus\u00ed b\u00fdt aktu\u00e1ln\u011b podporov\u00e1no.", - "protocol_error": "P\u0159i komunikaci s p\u0159\u00edslu\u0161enstv\u00edm do\u0161lo k chyb\u011b. Za\u0159\u00edzen\u00ed nemus\u00ed b\u00fdt v re\u017eimu p\u00e1rov\u00e1n\u00ed a m\u016f\u017ee vy\u017eadovat fyzick\u00e9 nebo virtu\u00e1ln\u00ed stisknut\u00ed tla\u010d\u00edtka.", "unable_to_pair": "Nelze sp\u00e1rovat, zkuste to pros\u00edm znovu.", "unknown_error": "Za\u0159\u00edzen\u00ed nahl\u00e1silo nezn\u00e1mou chybu. P\u00e1rov\u00e1n\u00ed se nezda\u0159ilo." }, @@ -40,9 +38,6 @@ "description": "Za\u0159\u00edzen\u00ed nemus\u00ed b\u00fdt v re\u017eimu p\u00e1rov\u00e1n\u00ed a m\u016f\u017ee vy\u017eadovat fyzick\u00e9 nebo virtu\u00e1ln\u00ed stisknut\u00ed tla\u010d\u00edtka. Ujist\u011bte se, \u017ee je za\u0159\u00edzen\u00ed v re\u017eimu p\u00e1rov\u00e1n\u00ed, nebo zkuste za\u0159\u00edzen\u00ed restartovat a pot\u00e9 pokra\u010dujte v p\u00e1rov\u00e1n\u00ed.", "title": "P\u0159i komunikaci s p\u0159\u00edslu\u0161enstv\u00edm do\u0161lo k chyb\u011b" }, - "try_pair_later": { - "title": "P\u00e1rov\u00e1n\u00ed nen\u00ed k dispozici" - }, "user": { "data": { "device": "Za\u0159\u00edzen\u00ed" diff --git a/homeassistant/components/homekit_controller/translations/da.json b/homeassistant/components/homekit_controller/translations/da.json index 4794b5acc44..1ea9ad343cf 100644 --- a/homeassistant/components/homekit_controller/translations/da.json +++ b/homeassistant/components/homekit_controller/translations/da.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "Forkert HomeKit-kode. Kontroller den og pr\u00f8v igen.", - "busy_error": "Enheden n\u00e6gtede at parre da den allerede er parret med en anden controller.", "max_peers_error": "Enheden n\u00e6gtede at parre da den ikke har nok frit parringslagerplads.", - "max_tries_error": "Enheden n\u00e6gtede at parre da den har modtaget mere end 100 mislykkede godkendelsesfors\u00f8g.", "pairing_failed": "En uh\u00e5ndteret fejl opstod under fors\u00f8g p\u00e5 at parre med denne enhed. Dette kan v\u00e6re en midlertidig fejl eller din enhed muligvis ikke underst\u00f8ttes i \u00f8jeblikket.", "unable_to_pair": "Kunne ikke parre, pr\u00f8v venligst igen.", "unknown_error": "Enhed rapporterede en ukendt fejl. Parring mislykkedes." diff --git a/homeassistant/components/homekit_controller/translations/de.json b/homeassistant/components/homekit_controller/translations/de.json index 6ee03a37f88..3d5c538b62b 100644 --- a/homeassistant/components/homekit_controller/translations/de.json +++ b/homeassistant/components/homekit_controller/translations/de.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "Ung\u00fcltiger HomeKit Code, \u00fcberpr\u00fcfe bitte den Code und versuche es erneut.", - "busy_error": "Das Ger\u00e4t weigerte sich, das Kopplung durchzuf\u00fchren, da es bereits mit einem anderen Controller gekoppelt ist.", "max_peers_error": "Das Ger\u00e4t weigerte sich, die Kopplung durchzuf\u00fchren, da es keinen freien Kopplungs-Speicher hat.", - "max_tries_error": "Das Ger\u00e4t hat sich geweigert die Kopplung durchzuf\u00fchren, da es mehr als 100 erfolglose Authentifizierungsversuche erhalten hat.", "pairing_failed": "Beim Versuch dieses Ger\u00e4t zu koppeln ist ein Fehler aufgetreten. Dies kann ein vor\u00fcbergehender Fehler sein oder das Ger\u00e4t wird derzeit m\u00f6glicherweise nicht unterst\u00fctzt.", "unable_to_pair": "Koppeln fehltgeschlagen, bitte versuche es erneut", "unknown_error": "Das Ger\u00e4t meldete einen unbekannten Fehler. Die Kopplung ist fehlgeschlagen." diff --git a/homeassistant/components/homekit_controller/translations/en.json b/homeassistant/components/homekit_controller/translations/en.json index 3d7e237c733..90d4356e40f 100644 --- a/homeassistant/components/homekit_controller/translations/en.json +++ b/homeassistant/components/homekit_controller/translations/en.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "Incorrect HomeKit code. Please check it and try again.", - "busy_error": "Device refused to add pairing as it is already pairing with another controller.", "max_peers_error": "Device refused to add pairing as it has no free pairing storage.", - "max_tries_error": "Device refused to add pairing as it has received more than 100 unsuccessful authentication attempts.", "pairing_failed": "An unhandled error occurred while attempting to pair with this device. This may be a temporary failure or your device may not be supported currently.", - "protocol_error": "Error communicating with the accessory. Device may not be in pairing mode and may require a physical or virtual button press.", "unable_to_pair": "Unable to pair, please try again.", "unknown_error": "Device reported an unknown error. Pairing failed." }, @@ -41,10 +38,6 @@ "description": "The device may not be in pairing mode and may require a physical or virtual button press. Ensure the device is in pairing mode or try restarting the device, then continue to resume pairing.", "title": "Error communicating with the accessory" }, - "try_pair_later": { - "description": "Ensure the device is in pairing mode or try restarting the device, then continue to re-start pairing.", - "title": "Pairing Unavailable" - }, "user": { "data": { "device": "Device" diff --git a/homeassistant/components/homekit_controller/translations/es-419.json b/homeassistant/components/homekit_controller/translations/es-419.json index a10c6eaa04f..dd01103c8f4 100644 --- a/homeassistant/components/homekit_controller/translations/es-419.json +++ b/homeassistant/components/homekit_controller/translations/es-419.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "C\u00f3digo de HomeKit incorrecto. Por favor revisalo e int\u00e9ntalo de nuevo.", - "busy_error": "El dispositivo se neg\u00f3 a agregar el emparejamiento ya que ya se est\u00e1 emparejando con otro controlador.", "max_peers_error": "El dispositivo se neg\u00f3 a agregar emparejamiento ya que no tiene almacenamiento de emparejamiento libre.", - "max_tries_error": "El dispositivo se neg\u00f3 a agregar el emparejamiento ya que recibi\u00f3 m\u00e1s de 100 intentos de autenticaci\u00f3n fallidos.", "pairing_failed": "Se produjo un error no controlado al intentar vincularse con este dispositivo. Esto puede ser una falla temporal o su dispositivo puede no ser compatible actualmente.", "unable_to_pair": "No se puede vincular, por favor intente nuevamente.", "unknown_error": "El dispositivo inform\u00f3 un error desconocido. Vinculaci\u00f3n fallida." diff --git a/homeassistant/components/homekit_controller/translations/es.json b/homeassistant/components/homekit_controller/translations/es.json index a1e61245ace..9f5f40bd199 100644 --- a/homeassistant/components/homekit_controller/translations/es.json +++ b/homeassistant/components/homekit_controller/translations/es.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "C\u00f3digo HomeKit incorrecto. Por favor, compru\u00e9belo e int\u00e9ntelo de nuevo.", - "busy_error": "El dispositivo rechaz\u00f3 el emparejamiento porque ya est\u00e1 emparejado con otro controlador.", "max_peers_error": "El dispositivo rechaz\u00f3 el emparejamiento ya que no tiene almacenamiento de emparejamientos libres.", - "max_tries_error": "El dispositivo rechaz\u00f3 el emparejamiento ya que ha recibido m\u00e1s de 100 intentos de autenticaci\u00f3n fallidos.", "pairing_failed": "Se ha producido un error no controlado al intentar emparejarse con este dispositivo. Esto puede ser un fallo temporal o que tu dispositivo no est\u00e9 admitido en este momento.", - "protocol_error": "Error de comunicaci\u00f3n con el accesorio. El dispositivo puede no estar en modo de emparejamiento y puede requerir una pulsaci\u00f3n de bot\u00f3n f\u00edsica o virtual.", "unable_to_pair": "No se ha podido emparejar, por favor int\u00e9ntelo de nuevo.", "unknown_error": "El dispositivo report\u00f3 un error desconocido. La vinculaci\u00f3n ha fallado." }, @@ -41,10 +38,6 @@ "description": "Es posible que el dispositivo no est\u00e9 en modo de emparejamiento y que requiera que se presione un bot\u00f3n f\u00edsico o virtual. Aseg\u00farate de que el dispositivo est\u00e1 en modo de emparejamiento o intenta reiniciar el dispositivo, luego contin\u00faa para reanudar el emparejamiento.", "title": "Error al comunicarse con el accesorio" }, - "try_pair_later": { - "description": "Aseg\u00farate de que el dispositivo est\u00e1 en modo de emparejamiento o reinicia el dispositivo y vuelve a intentar el emparejamiento.", - "title": "Emparejamiento no disponible" - }, "user": { "data": { "device": "Dispositivo" diff --git a/homeassistant/components/homekit_controller/translations/et.json b/homeassistant/components/homekit_controller/translations/et.json index 51977a7fcfd..40537554ee2 100644 --- a/homeassistant/components/homekit_controller/translations/et.json +++ b/homeassistant/components/homekit_controller/translations/et.json @@ -1,10 +1,50 @@ { "config": { "abort": { + "accessory_not_found_error": "Sidumist ei saa lisada kuna seadet ei ole enam leitav.", "already_configured": "Lisaseade on selle kontrolleriga juba seadistatud.", "already_in_progress": "Seadistamine on juba k\u00e4imas", "already_paired": "See lisaseade on juba teise seadmega seotud. L\u00e4htesta lisaseade ja proovi uuesti.", - "invalid_properties": "Seade tagastas vigase oleku." + "ignored_model": "Selle mudeli HomeKiti tugi on blokeeritud, kuna saadaval on t\u00e4iuslikum t\u00e4ielik sidumine.", + "invalid_config_entry": "See seade on valmis sidumiseks kuid Home Assistant-is on juba vastuoluline seadeikirje mis tuleb esmalt eemaldada.", + "invalid_properties": "Seade tagastas vigase oleku.", + "no_devices": "Sidumata seadmeid ei leitud" + }, + "error": { + "authentication_error": "Vale HomeKiti kood. Kontrolli seda ja proovi uuesti.", + "max_peers_error": "Seade keeldus sidumist lisamast kuna puudub piisav salvestusruum.", + "pairing_failed": "Selle seadmega sidumise katsel ilmnes tundmatu t\u00f5rge. See v\u00f5ib olla ajutine t\u00f5rge v\u00f5i tseadet ei toetata praegu.", + "unable_to_pair": "Ei saa siduda, proovi uuesti.", + "unknown_error": "Seade teatas tundmatust t\u00f5rkest. Sidumine nurjus." + }, + "flow_title": "{name} HomeKitAccessory Protocol abil", + "step": { + "busy_error": { + "description": "Katkesta sidumine k\u00f5igis kontrollerites v\u00f5i proovi seade taask\u00e4ivitada ja j\u00e4tka sidumist.", + "title": "Seade \u00fchendub juba teise kontrolleriga" + }, + "max_tries_error": { + "description": "Seade on saanud \u00fcle 100 eba\u00f5nnestunud autentimise katset. Proovi seade taask\u00e4ivitada ja j\u00e4tka sidumist.", + "title": "Autentimiskatsete piirarv on \u00fcletatud" + }, + "pair": { + "data": { + "pairing_code": "Sidumiskood" + }, + "description": "HomeKiti kontroller suhtleb seadmega {name} kohtv\u00f5rgu kaudu, kasutades turvalist kr\u00fcpteeritud \u00fchendust ilma eraldi HomeKiti kontrolleri v\u00f5i iCloudita. Selle lisaseadme kasutamiseks sisesta oma HomeKiti sidumiskood (vormingus XXX-XX-XXX). See kood on tavaliselt seadmel v\u00f5i pakendil.", + "title": "Seadme sidumine HomeKiti tarvikuprotokolli kaudu" + }, + "protocol_error": { + "description": "Seade ei pruugi olla sidumisre\u017eiimis ja v\u00f5ib vajada f\u00fc\u00fcsilist v\u00f5i virtuaalset nupuvajutust. Veendu, et seade oleks sidumisre\u017eiimis v\u00f5i proovi seade taask\u00e4ivitada, seej\u00e4rel j\u00e4tka sidumist.", + "title": "Viga lisaseadmega suhtlemisel" + }, + "user": { + "data": { + "device": "Seade" + }, + "description": "HomeKiti kontroller suhtleb kohtv\u00f5rgu kaudu turvalise kr\u00fcpteeritud \u00fchenduse abil ilma eraldi HomeKiti kontrolleri v\u00f5i iCloudita. Vali seade, millega soovid siduda:", + "title": "Seadme valik" + } } }, "device_automation": { @@ -26,5 +66,6 @@ "long_press": "\" {subtype} \" on pikalt alla vajutatud", "single_press": "\" {subtype} \" on vajutatud" } - } + }, + "title": "HomeKit kontroller" } \ No newline at end of file diff --git a/homeassistant/components/homekit_controller/translations/fr.json b/homeassistant/components/homekit_controller/translations/fr.json index 9634fb784f7..5ae7a0faafd 100644 --- a/homeassistant/components/homekit_controller/translations/fr.json +++ b/homeassistant/components/homekit_controller/translations/fr.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "Code HomeKit incorrect. S'il vous pla\u00eet v\u00e9rifier et essayez \u00e0 nouveau.", - "busy_error": "L'appareil a refus\u00e9 d'ajouter le couplage car il est d\u00e9j\u00e0 coupl\u00e9 avec un autre contr\u00f4leur.", "max_peers_error": "L'appareil a refus\u00e9 d'ajouter le couplage car il ne dispose pas de stockage de couplage libre.", - "max_tries_error": "Le p\u00e9riph\u00e9rique a refus\u00e9 d'ajouter le couplage car il a re\u00e7u plus de 100 tentatives d'authentification infructueuses.", "pairing_failed": "Une erreur non g\u00e9r\u00e9e s'est produite lors de la tentative d'appairage avec cet appareil. Il se peut qu'il s'agisse d'une panne temporaire ou que votre appareil ne soit pas pris en charge actuellement.", - "protocol_error": "Erreur de communication avec l'accessoire. L'appareil peut ne pas \u00eatre en mode d'appairage et peut n\u00e9cessiter une pression sur un bouton physique ou virtuel.", "unable_to_pair": "Impossible d'appairer, veuillez r\u00e9essayer.", "unknown_error": "L'appareil a signal\u00e9 une erreur inconnue. L'appairage a \u00e9chou\u00e9." }, @@ -41,10 +38,6 @@ "description": "L\u2019appareil peut ne pas \u00eatre en mode appairement et peut n\u00e9cessiter une pression sur un bouton physique ou virtuel. Assurez-vous que l\u2019appareil est en mode appariement ou essayez de red\u00e9marrer l\u2019appareil, puis continuez \u00e0 reprendre l\u2019appariement.", "title": "Erreur de communication avec l\u2019accessoire" }, - "try_pair_later": { - "description": "Assurez-vous que l'appareil est en mode de couplage ou essayez de red\u00e9marrer l'appareil, puis continuez \u00e0 red\u00e9marrer le couplage.", - "title": "Couplage indisponible" - }, "user": { "data": { "device": "Appareil" diff --git a/homeassistant/components/homekit_controller/translations/hu.json b/homeassistant/components/homekit_controller/translations/hu.json index c6d81d985bb..49e6fc53231 100644 --- a/homeassistant/components/homekit_controller/translations/hu.json +++ b/homeassistant/components/homekit_controller/translations/hu.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "Helytelen HomeKit k\u00f3d. K\u00e9rj\u00fck, ellen\u0151rizze, \u00e9s pr\u00f3b\u00e1lja \u00fajra.", - "busy_error": "Az eszk\u00f6z megtagadta a p\u00e1ros\u00edt\u00e1s hozz\u00e1ad\u00e1s\u00e1t, mivel m\u00e1r p\u00e1ros\u00edtva van egy m\u00e1sik vez\u00e9rl\u0151vel.", "max_peers_error": "Az eszk\u00f6z megtagadta a p\u00e1ros\u00edt\u00e1s hozz\u00e1ad\u00e1s\u00e1t, mivel nincs ingyenes p\u00e1ros\u00edt\u00e1si t\u00e1rhely.", - "max_tries_error": "Az eszk\u00f6z megtagadta a p\u00e1ros\u00edt\u00e1s hozz\u00e1ad\u00e1s\u00e1t, mivel t\u00f6bb mint 100 sikertelen hiteles\u00edt\u00e9si k\u00eds\u00e9rletet kapott.", "pairing_failed": "Nem kezelt hiba t\u00f6rt\u00e9nt az eszk\u00f6zzel val\u00f3 p\u00e1ros\u00edt\u00e1s sor\u00e1n. Lehet, hogy ez \u00e1tmeneti hiba, vagy az eszk\u00f6z jelenleg m\u00e9g nem t\u00e1mogatott.", "unable_to_pair": "Nem siker\u00fclt p\u00e1ros\u00edtani, pr\u00f3b\u00e1ld \u00fajra.", "unknown_error": "Az eszk\u00f6z ismeretlen hib\u00e1t jelentett. A p\u00e1ros\u00edt\u00e1s sikertelen." diff --git a/homeassistant/components/homekit_controller/translations/it.json b/homeassistant/components/homekit_controller/translations/it.json index e3f0a5c820e..38a3bfccd10 100644 --- a/homeassistant/components/homekit_controller/translations/it.json +++ b/homeassistant/components/homekit_controller/translations/it.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "Codice HomeKit errato. Per favore, controllate e riprovate.", - "busy_error": "Il dispositivo ha rifiutato di aggiungere l'abbinamento in quanto \u00e8 gi\u00e0 associato a un altro controller.", "max_peers_error": "Il dispositivo ha rifiutato di aggiungere l'abbinamento in quanto non dispone di una memoria libera per esso.", - "max_tries_error": "Il dispositivo ha rifiutato di aggiungere l'abbinamento poich\u00e9 ha ricevuto pi\u00f9 di 100 tentativi di autenticazione non riusciti.", "pairing_failed": "Si \u00e8 verificato un errore non gestito durante il tentativo di abbinamento con questo dispositivo. Potrebbe trattarsi di un errore temporaneo o il dispositivo potrebbe non essere attualmente supportato.", - "protocol_error": "Errore di comunicazione con l'accessorio. Il dispositivo potrebbe non essere in modalit\u00e0 di associazione e potrebbe richiedere la pressione di un pulsante fisico o virtuale.", "unable_to_pair": "Impossibile abbinare, per favore riprova.", "unknown_error": "Il dispositivo ha riportato un errore sconosciuto. L'abbinamento non \u00e8 riuscito." }, @@ -41,10 +38,6 @@ "description": "Il dispositivo potrebbe non essere in modalit\u00e0 di associazione e potrebbe richiedere una pressione di un pulsante fisico o virtuale. Assicurati che il dispositivo sia in modalit\u00e0 di associazione o prova a riavviarlo, quindi continua a riprendere l'associazione.", "title": "Errore di comunicazione con l'accessorio" }, - "try_pair_later": { - "description": "Verificare che il dispositivo sia in modalit\u00e0 di associazione o provare a riavviarlo, quindi continuare ad avviare nuovamente l'associazione.", - "title": "Associazione non disponibile" - }, "user": { "data": { "device": "Dispositivo" diff --git a/homeassistant/components/homekit_controller/translations/ko.json b/homeassistant/components/homekit_controller/translations/ko.json index a70a6269bb6..2c41447b5a0 100644 --- a/homeassistant/components/homekit_controller/translations/ko.json +++ b/homeassistant/components/homekit_controller/translations/ko.json @@ -12,9 +12,7 @@ }, "error": { "authentication_error": "HomeKit \ucf54\ub4dc\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ud655\uc778 \ud6c4 \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694.", - "busy_error": "\uae30\uae30\uac00 \uc774\ubbf8 \ub2e4\ub978 \ucee8\ud2b8\ub864\ub7ec\uc640 \ud398\uc5b4\ub9c1 \uc911\uc774\ubbc0\ub85c \ud398\uc5b4\ub9c1 \ucd94\uac00\ub97c \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", "max_peers_error": "\uae30\uae30\uc5d0 \ube44\uc5b4\uc788\ub294 \ud398\uc5b4\ub9c1 \uc7a5\uc18c\uac00 \uc5c6\uc5b4 \ud398\uc5b4\ub9c1 \ucd94\uac00\ub97c \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", - "max_tries_error": "\uae30\uae30\uac00 \uc2e4\ud328\ud55c \uc778\uc99d \uc2dc\ub3c4 \ud69f\uc218\uac00 100 \ud68c\ub97c \ucd08\uacfc\ud558\uc5ec \ud398\uc5b4\ub9c1\uc744 \ucd94\uac00\ub97c \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", "pairing_failed": "\uc774 \uae30\uae30\uc640 \ud398\uc5b4\ub9c1\uc744 \uc2dc\ub3c4\ud558\ub294 \uc911 \ucc98\ub9ac\ub418\uc9c0 \uc54a\uc740 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \uc77c\uc2dc\uc801\uc778 \uc624\ub958\uc774\uac70\ub098 \ud604\uc7ac \uc9c0\uc6d0\ub418\uc9c0 \uc54a\ub294 \uae30\uae30 \uc77c \uc218 \uc788\uc2b5\ub2c8\ub2e4.", "unable_to_pair": "\ud398\uc5b4\ub9c1 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694.", "unknown_error": "\uae30\uae30\uc5d0\uc11c \uc54c \uc218\uc5c6\ub294 \uc624\ub958\ub97c \ubcf4\uace0\ud588\uc2b5\ub2c8\ub2e4. \ud398\uc5b4\ub9c1\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4." diff --git a/homeassistant/components/homekit_controller/translations/lb.json b/homeassistant/components/homekit_controller/translations/lb.json index 7625d0c561e..f39c04c2c01 100644 --- a/homeassistant/components/homekit_controller/translations/lb.json +++ b/homeassistant/components/homekit_controller/translations/lb.json @@ -3,7 +3,7 @@ "abort": { "accessory_not_found_error": "D'Kupplung kann net dob\u00e4igesat ginn, well den Apparat net m\u00e9i siichtbar ass", "already_configured": "Accessoire ass schon mat d\u00ebsem Kontroller konfigur\u00e9iert.", - "already_in_progress": "Konfiguratioun fir d\u00ebsen Apparat ass schonn am gaang.", + "already_in_progress": "Konfiguratioun's Oflas ass schon am gaang", "already_paired": "D\u00ebsen Accessoire ass schonn mat engem aneren Apparat verbonnen. S\u00ebtzt den Apparat op Wierksastellungen zer\u00e9ck an prob\u00e9iert nach emol w.e.g.", "ignored_model": "HomeKit Support fir d\u00ebse Modell ass block\u00e9iert well eng m\u00e9i komplett nativ Integratioun disponibel ass.", "invalid_config_entry": "D\u00ebsen Apparat mellt sech prett fir ze verbanne mee et g\u00ebtt schonn eng Entr\u00e9e am Home Assistant d\u00e9i ee Konflikt duerstellt welch fir d'\u00e9ischt muss erausgeholl ginn.", @@ -12,15 +12,12 @@ }, "error": { "authentication_error": "Ong\u00ebltege HomeKit Code. Iwwerpr\u00e9ift d\u00ebsen an prob\u00e9iert w.e.g. nach emol.", - "busy_error": "Den Apparat huet en Kupplungs Versuch refus\u00e9iert, well en scho mat engem anere Kontroller verbonnen ass.", "max_peers_error": "Den Apparat huet den Kupplungs Versuch refus\u00e9iert well et keng fr\u00e4i Pairing Memoire huet.", - "max_tries_error": "Den Apparat huet den Kupplungs Versuch refus\u00e9iert well et m\u00e9i w\u00e9i 100 net erfollegr\u00e4ich Authentifikatioun's Versich erhalen huet.", "pairing_failed": "Eng onerwaarte Feeler ass opgetruede beim Kupplung's Versuch mat d\u00ebsem Apparat. D\u00ebst kann e tempor\u00e4re Feeler sinn oder D\u00e4in Apparat g\u00ebtt aktuell net \u00ebnnerst\u00ebtzt.", - "protocol_error": "Feeler bei der Kommunikatioun mam Accessoire. Apparat ass vill\u00e4icht net am Kopplungs Modus a ben\u00e9idegt een Drock op ee Kn\u00e4ppchen.", "unable_to_pair": "Feeler beim verbannen, prob\u00e9iert w.e.g. nach emol.", "unknown_error": "Apparat mellt een onbekannte Feeler. Verbindung net m\u00e9iglech." }, - "flow_title": "HomeKit Accessoire: {name}", + "flow_title": "{name} via HomeKit Accessoire Protokoll", "step": { "busy_error": { "description": "Briech d'Kopplung op all Kontroller of, oder start den Apparat fr\u00ebsch, da versich et nach emol mat der Kopplung.", @@ -34,23 +31,19 @@ "data": { "pairing_code": "Pairing Code" }, - "description": "Gitt \u00e4ren HomeKit pairing Code (am Format XXX-XX-XXX) an fir d\u00ebsen Accessoire ze benotzen", - "title": "Mam HomeKit Accessoire verbannen" + "description": "HomeKit Kontroller kommuniz\u00e9iert mat {name} iwwert lokal Netzwierk m\u00ebttels enger ges\u00e9cherter verschl\u00ebsselter Verbindung ouni ee separate HomeKit Kontroller oder iCloud. G\u00ebff dain HomeKit Kopplung Code (am Format XXX-XX-XXX) an fir den Accessoire ze benotzen. De Code ass normalerweis um Apparat selwer oder op senger K\u00ebscht.", + "title": "Een Apparat via Homekit Accessoire Protokoll kopplen" }, "protocol_error": { "description": "Den Apparat ass vill\u00e4icht net am Kopplungs Modus an et muss ee Kn\u00e4ppche gedr\u00e9ckt ginn. Stell s\u00e9cher dass den Apparat am Kopplung Modus ass oder prob\u00e9ier den Apparat fr\u00ebsch ze starten, da versich et nach emol mat der Kopplung.", "title": "Feeler bei der Kommunikatioun mam Accessoire" }, - "try_pair_later": { - "description": "Stell s\u00e9cher dass den Apparat sech am Kopplungs Modus bef\u00ebnnt oder prob\u00e9ier den Apparat fr\u00ebsch ze starten, da prob\u00e9ier nach emol mat der Kopplung.", - "title": "Kopplung net m\u00e9iglech" - }, "user": { "data": { "device": "Apparat" }, - "description": "Wielt den Apparat aus dee soll verbonne ginn", - "title": "Mam HomeKit Accessoire verbannen" + "description": "HomeKit Kontroller kommuniz\u00e9iert mat {name} iwwert lokal Netzwierk m\u00ebttels enger ges\u00e9cherter verschl\u00ebsselter Verbindung ouni ee separate HomeKit Kontroller oder iCloud. Wiel den Apparat aus fir ze koppelen:", + "title": "Appart auswiel" } } }, diff --git a/homeassistant/components/homekit_controller/translations/nl.json b/homeassistant/components/homekit_controller/translations/nl.json index 84f5495cca7..ce4279229ab 100644 --- a/homeassistant/components/homekit_controller/translations/nl.json +++ b/homeassistant/components/homekit_controller/translations/nl.json @@ -12,9 +12,7 @@ }, "error": { "authentication_error": "Onjuiste HomeKit-code. Controleer het en probeer het opnieuw.", - "busy_error": "Het apparaat weigerde om koppelingen toe te voegen, omdat het al gekoppeld is met een andere controller.", "max_peers_error": "Apparaat heeft geweigerd om koppelingen toe te voegen omdat het geen vrije koppelingsopslag heeft.", - "max_tries_error": "Apparaat weigerde pairing toe te voegen omdat het meer dan 100 niet-succesvolle authenticatiepogingen heeft ontvangen.", "pairing_failed": "Er deed zich een fout voor tijdens het koppelen met dit apparaat. Dit kan een tijdelijke storing zijn of uw apparaat wordt mogelijk momenteel niet ondersteund.", "unable_to_pair": "Kan niet koppelen, probeer het opnieuw.", "unknown_error": "Apparaat meldde een onbekende fout. Koppelen mislukt." diff --git a/homeassistant/components/homekit_controller/translations/no.json b/homeassistant/components/homekit_controller/translations/no.json index ac09303a349..b0680ea5ba0 100644 --- a/homeassistant/components/homekit_controller/translations/no.json +++ b/homeassistant/components/homekit_controller/translations/no.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "Ugyldig HomeKit kode. Vennligst sjekk den og pr\u00f8v igjen.", - "busy_error": "Enheten nekter \u00e5 sammenkoble da den allerede er sammenkoblet med en annen kontroller.", "max_peers_error": "Enheten nekter \u00e5 sammenkoble da den ikke har ledig sammenkoblingslagring.", - "max_tries_error": "Enheten nekter \u00e5 sammenkoble da den har mottatt mer enn 100 mislykkede godkjenningsfors\u00f8k.", "pairing_failed": "En uh\u00e5ndtert feil oppstod under fors\u00f8k p\u00e5 \u00e5 koble til denne enheten. Dette kan v\u00e6re en midlertidig feil, eller at enheten din kan ikke st\u00f8ttes for \u00f8yeblikket.", - "protocol_error": "Feil under kommunikasjon med tilbeh\u00f8ret. Enheten er kanskje ikke i paringsmodus og kan kreve et fysisk eller virtuelt knappetrykk.", "unable_to_pair": "Kunne ikke koble til, vennligst pr\u00f8v igjen.", "unknown_error": "Enheten rapporterte en ukjent feil. Sammenkobling mislyktes." }, @@ -41,10 +38,6 @@ "description": "Enheten er kanskje ikke i paringsmodus og kan kreve et fysisk eller virtuelt knappetrykk. Kontroller at enheten er i paringsmodus eller pr\u00f8v \u00e5 starte enheten p\u00e5 nytt, og fortsett deretter \u00e5 fortsette paringen.", "title": "Feil ved kommunikasjon med tilbeh\u00f8ret" }, - "try_pair_later": { - "description": "Kontroller at enheten er i paringsmodus eller pr\u00f8v \u00e5 starte enheten p\u00e5 nytt, og fortsett deretter \u00e5 starte paringen p\u00e5 nytt.", - "title": "Paring utilgjengelig" - }, "user": { "data": { "device": "Enhet" diff --git a/homeassistant/components/homekit_controller/translations/pl.json b/homeassistant/components/homekit_controller/translations/pl.json index 359b3b4b02c..50fdf6a17e4 100644 --- a/homeassistant/components/homekit_controller/translations/pl.json +++ b/homeassistant/components/homekit_controller/translations/pl.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "Niepoprawny kod parowania HomeKit. Sprawd\u017a go i spr\u00f3buj ponownie.", - "busy_error": "Urz\u0105dzenie odm\u00f3wi\u0142o parowania, poniewa\u017c jest ju\u017c powi\u0105zane z innym kontrolerem", "max_peers_error": "Urz\u0105dzenie odm\u00f3wi\u0142o parowania, poniewa\u017c nie ma wolnej pami\u0119ci parowania", - "max_tries_error": "Urz\u0105dzenie odm\u00f3wi\u0142o dodania parowania, poniewa\u017c otrzyma\u0142o ponad 100 nieudanych pr\u00f3b uwierzytelnienia", "pairing_failed": "Wyst\u0105pi\u0142 nieobs\u0142ugiwany b\u0142\u0105d podczas pr\u00f3by sparowania z tym urz\u0105dzeniem. Mo\u017ce to by\u0107 tymczasowa awaria lub urz\u0105dzenie mo\u017ce nie by\u0107 obecnie obs\u0142ugiwane.", - "protocol_error": "B\u0142\u0105d w komunikacji z urz\u0105dzeniem. Urz\u0105dzenie mo\u017ce nie by\u0107 w trybie parowania i mo\u017ce wymaga\u0107 fizycznego lub wirtualnego naci\u015bni\u0119cia przycisku.", "unable_to_pair": "Nie mo\u017cna sparowa\u0107, spr\u00f3buj ponownie", "unknown_error": "Urz\u0105dzenie zg\u0142osi\u0142o nieznany b\u0142\u0105d. Parowanie nie powiod\u0142o si\u0119." }, @@ -41,10 +38,6 @@ "description": "Urz\u0105dzenie mo\u017ce nie by\u0107 w trybie parowania i mo\u017ce wymaga\u0107 fizycznego lub wirtualnego naci\u015bni\u0119cia przycisku. Upewnij si\u0119, \u017ce urz\u0105dzenie jest w trybie parowania lub spr\u00f3buj je ponownie uruchomi\u0107, a nast\u0119pnie wzn\u00f3w parowanie.", "title": "B\u0142\u0105d komunikacji z akcesorium" }, - "try_pair_later": { - "description": "Upewnij si\u0119, \u017ce urz\u0105dzenie jest w trybie parowania lub spr\u00f3buj ponownie uruchomi\u0107 urz\u0105dzenie, a nast\u0119pnie spr\u00f3buj ponownego parowania.", - "title": "Parowanie niedost\u0119pne" - }, "user": { "data": { "device": "Urz\u0105dzenie" @@ -56,17 +49,17 @@ }, "device_automation": { "trigger_subtype": { - "button1": "Przycisk 1", - "button10": "Przycisk 10", - "button2": "Przycisk 2", - "button3": "Przycisk 3", - "button4": "Przycisk 4", - "button5": "Przycisk 5", - "button6": "Przycisk 6", - "button7": "Przycisk 7", - "button8": "Przycisk 8", - "button9": "Przycisk 9", - "doorbell": "Dzwonek do drzwi" + "button1": "przycisk 1", + "button10": "przycisk 10", + "button2": "przycisk 2", + "button3": "przycisk 3", + "button4": "przycisk 4", + "button5": "przycisk 5", + "button6": "przycisk 6", + "button7": "przycisk 7", + "button8": "przycisk 8", + "button9": "przycisk 9", + "doorbell": "dzwonek do drzwi" }, "trigger_type": { "double_press": "\"{subtype}\" naci\u015bni\u0119ty dwukrotnie", diff --git a/homeassistant/components/homekit_controller/translations/pt-BR.json b/homeassistant/components/homekit_controller/translations/pt-BR.json index b420e8eafeb..55f4b71f7b2 100644 --- a/homeassistant/components/homekit_controller/translations/pt-BR.json +++ b/homeassistant/components/homekit_controller/translations/pt-BR.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "C\u00f3digo HomeKit incorreto. Por favor verifique e tente novamente.", - "busy_error": "O dispositivo recusou-se a adicionar o emparelhamento, uma vez que j\u00e1 est\u00e1 emparelhando com outro controlador.", "max_peers_error": "O dispositivo recusou-se a adicionar o emparelhamento, pois n\u00e3o tem armazenamento de emparelhamento gratuito.", - "max_tries_error": "O dispositivo recusou-se a adicionar o emparelhamento, uma vez que recebeu mais de 100 tentativas de autentica\u00e7\u00e3o malsucedidas.", "pairing_failed": "Ocorreu um erro sem tratamento ao tentar emparelhar com este dispositivo. Isso pode ser uma falha tempor\u00e1ria ou o dispositivo pode n\u00e3o ser suportado no momento.", "unable_to_pair": "N\u00e3o \u00e9 poss\u00edvel parear, tente novamente.", "unknown_error": "O dispositivo relatou um erro desconhecido. O pareamento falhou." diff --git a/homeassistant/components/homekit_controller/translations/pt.json b/homeassistant/components/homekit_controller/translations/pt.json index f4ffbf157bd..deeb376e5e0 100644 --- a/homeassistant/components/homekit_controller/translations/pt.json +++ b/homeassistant/components/homekit_controller/translations/pt.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "C\u00f3digo incorreto do HomeKit. Por favor, verifique e tente novamente.", - "busy_error": "O dispositivo recusou-se a adicionar emparelhamento, pois j\u00e1 est\u00e1 emparelhado com outro controlador.", "max_peers_error": "O dispositivo recusou-se a adicionar o emparelhamento, pois n\u00e3o possui espa\u00e7o livre para o emparelhamento.", - "max_tries_error": "O dispositivo recusou-se a emparelhar por ter recebido mais de 100 tentativas de autentica\u00e7\u00e3o mal sucedidas.", "pairing_failed": "Ocorreu um erro n\u00e3o tratado ao tentar emparelhar com este dispositivo. Poder\u00e1 ser uma falha tempor\u00e1ria ou o dispositivo pode n\u00e3o ser suportado agora.", "unable_to_pair": "N\u00e3o foi poss\u00edvel emparelhar, por favor, tente novamente.", "unknown_error": "O dispositivo reportou um erro desconhecido. O emparelhamento falhou." diff --git a/homeassistant/components/homekit_controller/translations/ru.json b/homeassistant/components/homekit_controller/translations/ru.json index 791dfc36cb4..16e4c611efe 100644 --- a/homeassistant/components/homekit_controller/translations/ru.json +++ b/homeassistant/components/homekit_controller/translations/ru.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043e\u0434 HomeKit. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043a\u043e\u0434 \u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437.", - "busy_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u043e \u0441 \u0434\u0440\u0443\u0433\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c.", "max_peers_error": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043e\u0442\u043a\u043b\u043e\u043d\u0438\u043b\u043e \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u0438\u0437-\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430.", - "max_tries_error": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043e\u0442\u043a\u043b\u043e\u043d\u0438\u043b\u043e \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043e \u0431\u043e\u043b\u0435\u0435 100 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u044b\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.", "pairing_failed": "\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u0431\u043e\u0439 \u0438\u043b\u0438 \u0412\u0430\u0448\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0435\u0449\u0435 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f.", - "protocol_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0430\u043a\u0441\u0435\u0441\u0441\u0443\u0430\u0440\u043e\u043c. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043e \u0432 \u0440\u0435\u0436\u0438\u043c \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0440\u0435\u0436\u0438\u043c\u0430 \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0438\u043b\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438.", "unable_to_pair": "\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437.", "unknown_error": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441\u043e\u043e\u0431\u0449\u0438\u043b\u043e \u043e \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0435. \u0421\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c." }, @@ -41,10 +38,6 @@ "description": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u044f \u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0438\u043b\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u044f, \u0438\u043b\u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e, \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435 \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435.", "title": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0430\u043a\u0441\u0435\u0441\u0441\u0443\u0430\u0440\u043e\u043c." }, - "try_pair_later": { - "description": "\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0438 \u043d\u0430\u0447\u043d\u0438\u0442\u0435 \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e.", - "title": "\u0421\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e" - }, "user": { "data": { "device": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e" diff --git a/homeassistant/components/homekit_controller/translations/sl.json b/homeassistant/components/homekit_controller/translations/sl.json index 4dcd1d485c3..5d4576774da 100644 --- a/homeassistant/components/homekit_controller/translations/sl.json +++ b/homeassistant/components/homekit_controller/translations/sl.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "Nepravilna koda HomeKit. Preverite in poskusite znova.", - "busy_error": "Naprava je zavrnila seznanjanje, saj se \u017ee povezuje z drugim krmilnikom.", "max_peers_error": "Naprava je zavrnila seznanjanje, saj nima prostega pomnilnika za seznanjanje.", - "max_tries_error": "Napravaje zavrnila seznanjanje, saj je prejela ve\u010d kot 100 neuspe\u0161nih poskusov overjanja.", "pairing_failed": "Med poskusom seznanitev s to napravo je pri\u0161lo do napake. To je lahko za\u010dasna napaka ali pa va\u0161a naprava trenutno ni podprta.", "unable_to_pair": "Ni mogo\u010de seznaniti. Poskusite znova.", "unknown_error": "Naprava je sporo\u010dila neznano napako. Seznanjanje ni uspelo." @@ -36,5 +34,20 @@ } } }, + "device_automation": { + "trigger_subtype": { + "button1": "Gumb 1", + "button10": "Gumb 10", + "button2": "Gumb 2", + "button3": "Gumb 3", + "button4": "Gumb 4", + "button5": "Gumb 5", + "button6": "Gumb 6", + "button7": "Gumb 7", + "button8": "Gumb 8", + "button9": "Gumb 9", + "doorbell": "Zvonec" + } + }, "title": "HomeKit oprema" } \ No newline at end of file diff --git a/homeassistant/components/homekit_controller/translations/sv.json b/homeassistant/components/homekit_controller/translations/sv.json index e57d61dcdb6..71425e0f208 100644 --- a/homeassistant/components/homekit_controller/translations/sv.json +++ b/homeassistant/components/homekit_controller/translations/sv.json @@ -11,9 +11,7 @@ }, "error": { "authentication_error": "Felaktig HomeKit-kod. V\u00e4nligen kontrollera och f\u00f6rs\u00f6k igen.", - "busy_error": "Enheten nekade parning d\u00e5 den redan \u00e4r parad med annan controller.", "max_peers_error": "Enheten nekade parningsf\u00f6rs\u00f6ket d\u00e5 det inte finns n\u00e5got parningsminnesutrymme kvar", - "max_tries_error": "Enheten nekade parningen d\u00e5 den har emottagit mer \u00e4n 100 misslyckade autentiseringsf\u00f6rs\u00f6k", "pairing_failed": "Ett ok\u00e4nt fel uppstod n\u00e4r parningsf\u00f6rs\u00f6ket gjordes med den h\u00e4r enheten. Det h\u00e4r kan vara ett tillf\u00e4lligt fel, eller s\u00e5 st\u00f6ds inte din enhet i nul\u00e4get.", "unable_to_pair": "Det g\u00e5r inte att para ihop, f\u00f6rs\u00f6k igen.", "unknown_error": "Enheten rapporterade ett ok\u00e4nt fel. Parning misslyckades." diff --git a/homeassistant/components/homekit_controller/translations/zh-Hans.json b/homeassistant/components/homekit_controller/translations/zh-Hans.json index ee7df324f44..624050e7146 100644 --- a/homeassistant/components/homekit_controller/translations/zh-Hans.json +++ b/homeassistant/components/homekit_controller/translations/zh-Hans.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "HomeKit \u4ee3\u7801\u4e0d\u6b63\u786e\u3002\u8bf7\u68c0\u67e5\u540e\u91cd\u8bd5\u3002", - "busy_error": "\u8bbe\u5907\u62d2\u7edd\u914d\u5bf9\uff0c\u56e0\u4e3a\u5b83\u5df2\u7ecf\u4e0e\u53e6\u4e00\u4e2a\u63a7\u5236\u5668\u914d\u5bf9\u3002", "max_peers_error": "\u8bbe\u5907\u62d2\u7edd\u914d\u5bf9\uff0c\u56e0\u4e3a\u5b83\u6ca1\u6709\u7a7a\u95f2\u7684\u914d\u5bf9\u5b58\u50a8\u7a7a\u95f4\u3002", - "max_tries_error": "\u8bbe\u5907\u62d2\u7edd\u914d\u5bf9\uff0c\u56e0\u4e3a\u5b83\u5df2\u6536\u5230\u8d85\u8fc7 100 \u6b21\u5931\u8d25\u7684\u8eab\u4efd\u8ba4\u8bc1\u3002", "pairing_failed": "\u5c1d\u8bd5\u4e0e\u6b64\u8bbe\u5907\u914d\u5bf9\u65f6\u53d1\u751f\u672a\u5904\u7406\u7684\u9519\u8bef\u3002\u8fd9\u53ef\u80fd\u662f\u6682\u65f6\u6027\u6545\u969c\uff0c\u4e5f\u53ef\u80fd\u662f\u60a8\u7684\u8bbe\u5907\u76ee\u524d\u4e0d\u88ab\u652f\u6301\u3002", - "protocol_error": "\u4e0e\u914d\u4ef6\u901a\u8baf\u65f6\u51fa\u9519\u3002\u8bbe\u5907\u53ef\u80fd\u672a\u5904\u4e8e\u914d\u5bf9\u6a21\u5f0f\uff0c\u53ef\u80fd\u9700\u8981\u6309\u4e0b\u7269\u7406\u6216\u865a\u62df\u6309\u94ae\u3002", "unable_to_pair": "\u65e0\u6cd5\u914d\u5bf9\uff0c\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002", "unknown_error": "\u8bbe\u5907\u62a5\u544a\u4e86\u672a\u77e5\u9519\u8bef\u3002\u914d\u5bf9\u5931\u8d25\u3002" }, @@ -41,10 +38,6 @@ "description": "\u8bbe\u5907\u53ef\u80fd\u672a\u5904\u4e8e\u914d\u5bf9\u6a21\u5f0f\uff0c\u53ef\u80fd\u9700\u8981\u6309\u4e0b\u7269\u7406\u6216\u865a\u62df\u6309\u94ae\u3002\u8bf7\u786e\u4fdd\u8bbe\u5907\u5904\u4e8e\u914d\u5bf9\u6a21\u5f0f\uff0c\u6216\u5c1d\u8bd5\u91cd\u65b0\u542f\u52a8\u8bbe\u5907\uff0c\u7136\u540e\u7ee7\u7eed\u914d\u5bf9\u3002", "title": "\u4e0e\u914d\u4ef6\u901a\u4fe1\u65f6\u51fa\u9519" }, - "try_pair_later": { - "description": "\u8bf7\u786e\u4fdd\u8bbe\u5907\u5904\u4e8e\u914d\u5bf9\u6a21\u5f0f\uff0c\u6216\u5c1d\u8bd5\u91cd\u65b0\u542f\u52a8\u8bbe\u5907\uff0c\u7136\u540e\u91cd\u65b0\u542f\u52a8\u914d\u5bf9\u3002", - "title": "\u65e0\u6cd5\u914d\u5bf9" - }, "user": { "data": { "device": "\u8bbe\u5907" diff --git a/homeassistant/components/homekit_controller/translations/zh-Hant.json b/homeassistant/components/homekit_controller/translations/zh-Hant.json index ded672bd838..75c46125c14 100644 --- a/homeassistant/components/homekit_controller/translations/zh-Hant.json +++ b/homeassistant/components/homekit_controller/translations/zh-Hant.json @@ -12,11 +12,8 @@ }, "error": { "authentication_error": "Homekit \u4ee3\u78bc\u932f\u8aa4\uff0c\u8acb\u78ba\u5b9a\u5f8c\u518d\u8a66\u4e00\u6b21\u3002", - "busy_error": "\u8a2d\u5099\u5df2\u7d93\u8207\u5176\u4ed6\u63a7\u5236\u5668\u914d\u5c0d\uff0c\u62d2\u7d55\u9032\u884c\u914d\u5c0d\u3002", "max_peers_error": "\u8a2d\u5099\u5df2\u7121\u5269\u9918\u914d\u5c0d\u7a7a\u9593\uff0c\u62d2\u7d55\u9032\u884c\u914d\u5c0d\u3002", - "max_tries_error": "\u8a2d\u5099\u6536\u5230\u8d85\u904e 100 \u6b21\u672a\u6210\u529f\u8a8d\u8b49\u5f8c\uff0c\u62d2\u7d55\u9032\u884c\u914d\u5c0d\u3002", "pairing_failed": "\u7576\u8a66\u5716\u8207\u8a2d\u5099\u914d\u5c0d\u6642\u767c\u751f\u7121\u6cd5\u8655\u7406\u932f\u8aa4\uff0c\u53ef\u80fd\u50c5\u70ba\u66ab\u6642\u5931\u6548\u3001\u6216\u8005\u8a2d\u5099\u76ee\u524d\u4e0d\u652f\u63f4\u3002", - "protocol_error": "\u8207\u8a2d\u5099\u901a\u8a0a\u6642\u767c\u751f\u932f\u8aa4\u3002\u8a2d\u5099\u53ef\u80fd\u4e26\u672a\u8655\u65bc\u914d\u5c0d\u6a21\u5f0f\u3001\u4e26\u9700\u8981\u6309\u4e0b\u5be6\u9ad4\u6216\u865b\u64ec\u6309\u9215\u3002", "unable_to_pair": "\u7121\u6cd5\u914d\u5c0d\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", "unknown_error": "\u8a2d\u5099\u56de\u5831\u672a\u77e5\u932f\u8aa4\u3002\u914d\u5c0d\u5931\u6557\u3002" }, @@ -41,10 +38,6 @@ "description": "\u8a2d\u5099\u4e26\u672a\u8655\u65bc\u914d\u5c0d\u6a21\u5f0f\uff0c\u53ef\u80fd\u9700\u8981\u6309\u4e0b\u5be6\u9ad4\u6216\u865b\u64ec\u6309\u9215\u3002\u8acb\u78ba\u5b9a\u8a2d\u5099\u5df2\u7d93\u8655\u65bc\u914d\u5c0d\u6a21\u5f0f\u3001\u6216\u91cd\u555f\u8a2d\u5099\uff0c\u7136\u5f8c\u518d\u7e7c\u7e8c\u914d\u5c0d\u3002", "title": "\u8207\u914d\u4ef6\u901a\u8a0a\u932f\u8aa4" }, - "try_pair_later": { - "description": "\u8acb\u78ba\u5b9a\u8a2d\u5099\u8655\u65bc\u914d\u5c0d\u6a21\u5f0f\u4e2d\u6216\u91cd\u555f\u8a2d\u5099\uff0c\u7136\u5f8c\u91cd\u65b0\u958b\u59cb\u914d\u5c0d\u3002", - "title": "\u914d\u5c0d\u7121\u6cd5\u4f7f\u7528" - }, "user": { "data": { "device": "\u8a2d\u5099" diff --git a/homeassistant/components/homematic/__init__.py b/homeassistant/components/homematic/__init__.py index 2dd8349dcfc..1f727bab4e1 100644 --- a/homeassistant/components/homematic/__init__.py +++ b/homeassistant/components/homematic/__init__.py @@ -258,7 +258,7 @@ def setup(hass, config): # Init homematic hubs entity_hubs = [] - for hub_name in conf[CONF_HOSTS].keys(): + for hub_name in conf[CONF_HOSTS]: entity_hubs.append(HMHub(hass, homematic, hub_name)) def _hm_service_virtualkey(service): diff --git a/homeassistant/components/homematicip_cloud/__init__.py b/homeassistant/components/homematicip_cloud/__init__.py index 2b078966ee8..7ea6a4fe0b4 100644 --- a/homeassistant/components/homematicip_cloud/__init__.py +++ b/homeassistant/components/homematicip_cloud/__init__.py @@ -1,11 +1,14 @@ """Support for HomematicIP Cloud devices.""" +import logging + import voluptuous as vol from homeassistant import config_entries from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_NAME, EVENT_HOMEASSISTANT_STOP -from homeassistant.helpers import device_registry as dr +from homeassistant.helpers import device_registry as dr, entity_registry as er import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity_registry import async_entries_for_config_entry from homeassistant.helpers.typing import ConfigType, HomeAssistantType from .const import ( @@ -20,6 +23,8 @@ from .generic_entity import HomematicipGenericEntity # noqa: F401 from .hap import HomematicipAuth, HomematicipHAP # noqa: F401 from .services import async_setup_services, async_unload_services +_LOGGER = logging.getLogger(__name__) + CONFIG_SCHEMA = vol.Schema( { vol.Optional(DOMAIN, default=[]): vol.All( @@ -83,6 +88,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool return False await async_setup_services(hass) + await async_remove_obsolete_entities(hass, entry, hap) # Register on HA stop event to gracefully shutdown HomematicIP Cloud connection hap.reset_connection_listener = hass.bus.async_listen_once( @@ -91,16 +97,16 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool # Register hap as device in registry. device_registry = await dr.async_get_registry(hass) + home = hap.home - # Add the HAP name from configuration if set. - hapname = home.label if not home.name else f"{home.name} {home.label}" + hapname = home.label if home.label != entry.unique_id else f"Home-{home.label}" + device_registry.async_get_or_create( config_entry_id=entry.entry_id, identifiers={(DOMAIN, home.id)}, manufacturer="eQ-3", + # Add the name from config entry. name=hapname, - model=home.modelType, - sw_version=home.currentAPVersion, ) return True @@ -113,3 +119,23 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> boo await async_unload_services(hass) return await hap.async_reset() + + +async def async_remove_obsolete_entities( + hass: HomeAssistantType, entry: ConfigEntry, hap: HomematicipHAP +): + """Remove obsolete entities from entity registry.""" + + if hap.home.currentAPVersion < "2.2.12": + return + + entity_registry = await er.async_get_registry(hass) + er_entries = async_entries_for_config_entry(entity_registry, entry.entry_id) + for er_entry in er_entries: + if er_entry.unique_id.startswith("HomematicipAccesspointStatus"): + entity_registry.async_remove(er_entry.entity_id) + continue + + for hapid in hap.home.accessPointUpdateStates: + if er_entry.unique_id == f"HomematicipBatterySensor_{hapid}": + entity_registry.async_remove(er_entry.entity_id) diff --git a/homeassistant/components/homematicip_cloud/binary_sensor.py b/homeassistant/components/homematicip_cloud/binary_sensor.py index da5bf844e08..12bca8378c3 100644 --- a/homeassistant/components/homematicip_cloud/binary_sensor.py +++ b/homeassistant/components/homematicip_cloud/binary_sensor.py @@ -20,6 +20,7 @@ from homematicip.aio.device import ( AsyncWeatherSensor, AsyncWeatherSensorPlus, AsyncWeatherSensorPro, + AsyncWiredInput32, ) from homematicip.aio.group import AsyncSecurityGroup, AsyncSecurityZoneGroup from homematicip.base.enums import SmokeDetectorAlarmType, WindowState @@ -85,7 +86,14 @@ async def async_setup_entry( entities.append(HomematicipAccelerationSensor(hap, device)) if isinstance(device, AsyncTiltVibrationSensor): entities.append(HomematicipTiltVibrationSensor(hap, device)) - if isinstance(device, (AsyncContactInterface, AsyncFullFlushContactInterface)): + if isinstance(device, AsyncWiredInput32): + for channel in range(1, 33): + entities.append( + HomematicipMultiContactInterface(hap, device, channel=channel) + ) + elif isinstance( + device, (AsyncContactInterface, AsyncFullFlushContactInterface) + ): entities.append(HomematicipContactInterface(hap, device)) if isinstance( device, @@ -138,7 +146,15 @@ class HomematicipCloudConnectionSensor(HomematicipGenericEntity, BinarySensorEnt def __init__(self, hap: HomematicipHAP) -> None: """Initialize the cloud connection sensor.""" - super().__init__(hap, hap.home, "Cloud Connection") + super().__init__(hap, hap.home) + + @property + def name(self) -> str: + """Return the name cloud connection entity.""" + + name = "Cloud Connection" + # Add a prefix to the name if the homematic ip home has a name. + return name if not self._home.name else f"{self._home.name} {name}" @property def device_info(self) -> Dict[str, Any]: @@ -205,6 +221,29 @@ class HomematicipTiltVibrationSensor(HomematicipBaseActionSensor): """Representation of the HomematicIP tilt vibration sensor.""" +class HomematicipMultiContactInterface(HomematicipGenericEntity, BinarySensorEntity): + """Representation of the HomematicIP multi room/area contact interface.""" + + def __init__(self, hap: HomematicipHAP, device, channel: int) -> None: + """Initialize the multi contact entity.""" + super().__init__(hap, device, channel=channel) + + @property + def device_class(self) -> str: + """Return the class of this sensor.""" + return DEVICE_CLASS_OPENING + + @property + def is_on(self) -> bool: + """Return true if the contact interface is on/open.""" + if self._device.functionalChannels[self._channel].windowState is None: + return None + return ( + self._device.functionalChannels[self._channel].windowState + != WindowState.CLOSED + ) + + class HomematicipContactInterface(HomematicipGenericEntity, BinarySensorEntity): """Representation of the HomematicIP contact interface.""" diff --git a/homeassistant/components/homematicip_cloud/hap.py b/homeassistant/components/homematicip_cloud/hap.py index 164997d5582..151807391b9 100644 --- a/homeassistant/components/homematicip_cloud/hap.py +++ b/homeassistant/components/homematicip_cloud/hap.py @@ -240,8 +240,9 @@ class HomematicipHAP: home = AsyncHome(hass.loop, async_get_clientsession(hass)) home.name = name - home.label = "Access Point" - home.modelType = "HmIP-HAP" + # Use the title of the config entry as title for the home. + home.label = self.config_entry.title + home.modelType = "HomematicIP Cloud Home" home.set_auth_token(authtoken) try: diff --git a/homeassistant/components/homematicip_cloud/manifest.json b/homeassistant/components/homematicip_cloud/manifest.json index 3ecf668e449..30ca5165c85 100644 --- a/homeassistant/components/homematicip_cloud/manifest.json +++ b/homeassistant/components/homematicip_cloud/manifest.json @@ -3,7 +3,7 @@ "name": "HomematicIP Cloud", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/homematicip_cloud", - "requirements": ["homematicip==0.11.0"], + "requirements": ["homematicip==0.12.1"], "codeowners": ["@SukramJ"], "quality_scale": "platinum" } diff --git a/homeassistant/components/homematicip_cloud/sensor.py b/homeassistant/components/homematicip_cloud/sensor.py index 66e0e1afd70..9e202302c10 100644 --- a/homeassistant/components/homematicip_cloud/sensor.py +++ b/homeassistant/components/homematicip_cloud/sensor.py @@ -6,6 +6,7 @@ from homematicip.aio.device import ( AsyncFullFlushSwitchMeasuring, AsyncHeatingThermostat, AsyncHeatingThermostatCompact, + AsyncHomeControlAccessPoint, AsyncLightSensor, AsyncMotionDetectorIndoor, AsyncMotionDetectorOutdoor, @@ -39,7 +40,6 @@ from homeassistant.const import ( from homeassistant.helpers.typing import HomeAssistantType from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericEntity -from .generic_entity import ATTR_IS_GROUP, ATTR_MODEL_TYPE from .hap import HomematicipHAP ATTR_CURRENT_ILLUMINATION = "current_illumination" @@ -63,8 +63,10 @@ async def async_setup_entry( ) -> None: """Set up the HomematicIP Cloud sensors from a config entry.""" hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id] - entities = [HomematicipAccesspointStatus(hap)] + entities = [] for device in hap.home.devices: + if isinstance(device, AsyncHomeControlAccessPoint): + entities.append(HomematicipAccesspointDutyCycle(hap, device)) if isinstance(device, (AsyncHeatingThermostat, AsyncHeatingThermostatCompact)): entities.append(HomematicipHeatingThermostat(hap, device)) entities.append(HomematicipTemperatureSensor(hap, device)) @@ -119,23 +121,12 @@ async def async_setup_entry( async_add_entities(entities) -class HomematicipAccesspointStatus(HomematicipGenericEntity): +class HomematicipAccesspointDutyCycle(HomematicipGenericEntity): """Representation of then HomeMaticIP access point.""" - def __init__(self, hap: HomematicipHAP) -> None: + def __init__(self, hap: HomematicipHAP, device) -> None: """Initialize access point status entity.""" - super().__init__(hap, device=hap.home, post="Duty Cycle") - - @property - def device_info(self) -> Dict[str, Any]: - """Return device specific attributes.""" - # Adds a sensor to the existing HAP device - return { - "identifiers": { - # Serial numbers of Homematic IP device - (HMIPC_DOMAIN, self._home.id) - } - } + super().__init__(hap, device, post="Duty Cycle") @property def icon(self) -> str: @@ -145,28 +136,13 @@ class HomematicipAccesspointStatus(HomematicipGenericEntity): @property def state(self) -> float: """Return the state of the access point.""" - return self._home.dutyCycle - - @property - def available(self) -> bool: - """Return if access point is available.""" - return self._home.connected + return self._device.dutyCycleLevel @property def unit_of_measurement(self) -> str: """Return the unit this state is expressed in.""" return PERCENTAGE - @property - def device_state_attributes(self) -> Dict[str, Any]: - """Return the state attributes of the access point.""" - state_attr = super().device_state_attributes - - state_attr[ATTR_MODEL_TYPE] = "HmIP-HAP" - state_attr[ATTR_IS_GROUP] = False - - return state_attr - class HomematicipHeatingThermostat(HomematicipGenericEntity): """Representation of the HomematicIP heating thermostat.""" diff --git a/homeassistant/components/homematicip_cloud/switch.py b/homeassistant/components/homematicip_cloud/switch.py index 22fd1c25078..72f9f94c210 100644 --- a/homeassistant/components/homematicip_cloud/switch.py +++ b/homeassistant/components/homematicip_cloud/switch.py @@ -12,6 +12,7 @@ from homematicip.aio.device import ( AsyncPlugableSwitchMeasuring, AsyncPrintedCircuitBoardSwitch2, AsyncPrintedCircuitBoardSwitchBattery, + AsyncWiredSwitch8, ) from homematicip.aio.group import AsyncExtendedLinkedSwitchingGroup, AsyncSwitchingGroup @@ -40,6 +41,9 @@ async def async_setup_entry( device, (AsyncPlugableSwitchMeasuring, AsyncFullFlushSwitchMeasuring) ): entities.append(HomematicipSwitchMeasuring(hap, device)) + elif isinstance(device, AsyncWiredSwitch8): + for channel in range(1, 9): + entities.append(HomematicipMultiSwitch(hap, device, channel=channel)) elif isinstance( device, ( @@ -70,6 +74,27 @@ async def async_setup_entry( async_add_entities(entities) +class HomematicipMultiSwitch(HomematicipGenericEntity, SwitchEntity): + """Representation of the HomematicIP multi switch.""" + + def __init__(self, hap: HomematicipHAP, device, channel: int) -> None: + """Initialize the multi switch device.""" + super().__init__(hap, device, channel=channel) + + @property + def is_on(self) -> bool: + """Return true if switch is on.""" + return self._device.functionalChannels[self._channel].on + + async def async_turn_on(self, **kwargs) -> None: + """Turn the switch on.""" + await self._device.turn_on(self._channel) + + async def async_turn_off(self, **kwargs) -> None: + """Turn the switch off.""" + await self._device.turn_off(self._channel) + + class HomematicipSwitch(HomematicipGenericEntity, SwitchEntity): """Representation of the HomematicIP switch.""" @@ -146,24 +171,3 @@ class HomematicipSwitchMeasuring(HomematicipSwitch): if self._device.energyCounter is None: return 0 return round(self._device.energyCounter) - - -class HomematicipMultiSwitch(HomematicipGenericEntity, SwitchEntity): - """Representation of the HomematicIP multi switch.""" - - def __init__(self, hap: HomematicipHAP, device, channel: int) -> None: - """Initialize the multi switch device.""" - super().__init__(hap, device, channel=channel) - - @property - def is_on(self) -> bool: - """Return true if switch is on.""" - return self._device.functionalChannels[self._channel].on - - async def async_turn_on(self, **kwargs) -> None: - """Turn the switch on.""" - await self._device.turn_on(self._channel) - - async def async_turn_off(self, **kwargs) -> None: - """Turn the switch off.""" - await self._device.turn_off(self._channel) diff --git a/homeassistant/components/homematicip_cloud/translations/ca.json b/homeassistant/components/homematicip_cloud/translations/ca.json index 0725ee11afb..56198f37717 100644 --- a/homeassistant/components/homematicip_cloud/translations/ca.json +++ b/homeassistant/components/homematicip_cloud/translations/ca.json @@ -6,7 +6,6 @@ "unknown": "Error inesperat" }, "error": { - "invalid_pin": "Codi PIN inv\u00e0lid, torna-ho a provar.", "invalid_sgtin_or_pin": "Codi PIN o SGTIN inv\u00e0lid, torna-ho a provar.", "press_the_button": "Si us plau, prem el bot\u00f3 blau.", "register_failed": "Error al registrar, torna-ho a provar.", diff --git a/homeassistant/components/homematicip_cloud/translations/cs.json b/homeassistant/components/homematicip_cloud/translations/cs.json index 4fd386ba37a..b30af554a24 100644 --- a/homeassistant/components/homematicip_cloud/translations/cs.json +++ b/homeassistant/components/homematicip_cloud/translations/cs.json @@ -6,7 +6,6 @@ "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "error": { - "invalid_pin": "Neplatn\u00fd PIN, zkuste to pros\u00edm znovu.", "invalid_sgtin_or_pin": "Neplatn\u00fd k\u00f3d SGTIN nebo PIN, zkuste to pros\u00edm znovu.", "press_the_button": "Stiskn\u011bte modr\u00e9 tla\u010d\u00edtko.", "register_failed": "Registrace se nezda\u0159ila, zkuste to znovu.", @@ -22,7 +21,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/homematicip_cloud/translations/de.json b/homeassistant/components/homematicip_cloud/translations/de.json index 0718f629164..c421620fd98 100644 --- a/homeassistant/components/homematicip_cloud/translations/de.json +++ b/homeassistant/components/homematicip_cloud/translations/de.json @@ -6,7 +6,6 @@ "unknown": "Ein unbekannter Fehler ist aufgetreten." }, "error": { - "invalid_pin": "Ung\u00fcltige PIN, bitte versuche es erneut.", "invalid_sgtin_or_pin": "Ung\u00fcltige PIN, bitte versuche es erneut.", "press_the_button": "Bitte dr\u00fccke die blaue Taste.", "register_failed": "Registrierung fehlgeschlagen, bitte versuche es erneut.", diff --git a/homeassistant/components/homematicip_cloud/translations/el.json b/homeassistant/components/homematicip_cloud/translations/el.json deleted file mode 100644 index 843d590e7e0..00000000000 --- a/homeassistant/components/homematicip_cloud/translations/el.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "error": { - "invalid_pin": "\u039c\u03b7 \u03ad\u03b3\u03ba\u03c5\u03c1\u03bf PIN, \u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03be\u03b1\u03bd\u03ac." - } - } -} \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/translations/en.json b/homeassistant/components/homematicip_cloud/translations/en.json index bf469d406ea..6297e4ef661 100644 --- a/homeassistant/components/homematicip_cloud/translations/en.json +++ b/homeassistant/components/homematicip_cloud/translations/en.json @@ -6,7 +6,6 @@ "unknown": "Unexpected error" }, "error": { - "invalid_pin": "Invalid PIN, please try again.", "invalid_sgtin_or_pin": "Invalid SGTIN or PIN Code, please try again.", "press_the_button": "Please press the blue button.", "register_failed": "Failed to register, please try again.", diff --git a/homeassistant/components/homematicip_cloud/translations/es.json b/homeassistant/components/homematicip_cloud/translations/es.json index 980b0964d83..28a084a7ee9 100644 --- a/homeassistant/components/homematicip_cloud/translations/es.json +++ b/homeassistant/components/homematicip_cloud/translations/es.json @@ -6,7 +6,6 @@ "unknown": "Se ha producido un error desconocido." }, "error": { - "invalid_pin": "PIN no v\u00e1lido, por favor int\u00e9ntalo de nuevo.", "invalid_sgtin_or_pin": "PIN no v\u00e1lido, por favor int\u00e9ntalo de nuevo.", "press_the_button": "Por favor, pulsa el bot\u00f3n azul", "register_failed": "No se pudo registrar, por favor int\u00e9ntalo de nuevo.", diff --git a/homeassistant/components/homematicip_cloud/translations/et.json b/homeassistant/components/homematicip_cloud/translations/et.json index 3d88f62eedc..7446f7cc78a 100644 --- a/homeassistant/components/homematicip_cloud/translations/et.json +++ b/homeassistant/components/homematicip_cloud/translations/et.json @@ -6,8 +6,7 @@ "unknown": "Tundmatu viga" }, "error": { - "invalid_pin": "Vale PIN-kood. Palun proovige uuesti.", - "invalid_sgtin_or_pin": "Vale PIN, palun proovige uuesti", + "invalid_sgtin_or_pin": "Vale PIN, palun proovi uuesti", "press_the_button": "Palun vajuta sinist nuppu.", "register_failed": "Registreerimine nurjus, proovi uuesti.", "timeout_button": "Sinise nupu vajutamise ajal\u00f5pp, proovi uuesti." @@ -17,8 +16,13 @@ "data": { "hapid": "P\u00e4\u00e4supunkti ID (SGTIN)", "name": "Nimi (valikuline, kasutatakse k\u00f5igi seadmete nime eesliitena)", - "pin": "PIN-kood (valikuline)" - } + "pin": "PIN kood (valikuline)" + }, + "title": "Vali HomematicIP p\u00e4\u00e4supunkt" + }, + "link": { + "description": "HomematicIP registreerimiseks Home Assistanti abil vajuta p\u00e4\u00e4supunkti sinist nuppu ja nuppu Esita.\n\n ![Location of button on bridge](/static/images/config_flows/config_homematicip_cloud.png)", + "title": "Lingi p\u00e4\u00e4supunkt" } } } diff --git a/homeassistant/components/homematicip_cloud/translations/fr.json b/homeassistant/components/homematicip_cloud/translations/fr.json index 0c5f54d588a..212206bb298 100644 --- a/homeassistant/components/homematicip_cloud/translations/fr.json +++ b/homeassistant/components/homematicip_cloud/translations/fr.json @@ -6,7 +6,6 @@ "unknown": "Une erreur inconnue s'est produite." }, "error": { - "invalid_pin": "Code PIN invalide, veuillez r\u00e9essayer.", "invalid_sgtin_or_pin": "Code SGTIN ou PIN invalide, veuillez r\u00e9essayer.", "press_the_button": "Veuillez appuyer sur le bouton bleu.", "register_failed": "\u00c9chec d'enregistrement. Veuillez r\u00e9essayer.", diff --git a/homeassistant/components/homematicip_cloud/translations/it.json b/homeassistant/components/homematicip_cloud/translations/it.json index 11b21f8cbe4..80c766becf1 100644 --- a/homeassistant/components/homematicip_cloud/translations/it.json +++ b/homeassistant/components/homematicip_cloud/translations/it.json @@ -6,7 +6,6 @@ "unknown": "Errore imprevisto" }, "error": { - "invalid_pin": "PIN non valido, riprova.", "invalid_sgtin_or_pin": "SGTIN o Codice PIN non valido, si prega di riprovare.", "press_the_button": "Si prega di premere il pulsante blu.", "register_failed": "Registrazione fallita, si prega di riprovare.", diff --git a/homeassistant/components/homematicip_cloud/translations/ko.json b/homeassistant/components/homematicip_cloud/translations/ko.json index 962faa68066..b85b8ac00b1 100644 --- a/homeassistant/components/homematicip_cloud/translations/ko.json +++ b/homeassistant/components/homematicip_cloud/translations/ko.json @@ -6,7 +6,6 @@ "unknown": "\uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" }, "error": { - "invalid_pin": "\uc798\ubabb\ub41c PIN\uc785\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud558\uc2ed\uc2dc\uc624.", "invalid_sgtin_or_pin": "PIN\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694.", "press_the_button": "\ud30c\ub780\uc0c9 \ubc84\ud2bc\uc744 \ub20c\ub7ec\uc8fc\uc138\uc694.", "register_failed": "\ub4f1\ub85d\uc5d0 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694.", diff --git a/homeassistant/components/homematicip_cloud/translations/lb.json b/homeassistant/components/homematicip_cloud/translations/lb.json index 92487c12ea6..ec83f988b07 100644 --- a/homeassistant/components/homematicip_cloud/translations/lb.json +++ b/homeassistant/components/homematicip_cloud/translations/lb.json @@ -1,13 +1,12 @@ { "config": { "abort": { - "already_configured": "Acesspoint ass schon konfigur\u00e9iert", - "connection_aborted": "Konnt sech net mam HMIP Server verbannen", - "unknown": "Onbekannten Feeler opgetrueden" + "already_configured": "Apparat ass schon konfigur\u00e9iert", + "connection_aborted": "Feeler beim verbannen", + "unknown": "Onerwaarte Feeler" }, "error": { - "invalid_pin": "Ong\u00ebltege Pin, prob\u00e9ier w.e.g. nach emol.", - "invalid_sgtin_or_pin": "Ong\u00ebltege Pin, prob\u00e9iert w.e.g. nach emol.", + "invalid_sgtin_or_pin": "Ong\u00ebltege SGTIN oder PIN Code, prob\u00e9ier w.e.g. nach emol.", "press_the_button": "Dr\u00e9ckt w.e.g. de bloe Kn\u00e4ppchen.", "register_failed": "Feeler beim registr\u00e9ieren, prob\u00e9iert w.e.g. nach emol.", "timeout_button": "Z\u00e4itiwwerschreidung beim dr\u00e9cken vum bloe Kn\u00e4ppchen, prob\u00e9iert w.e.g. nach emol." @@ -16,8 +15,8 @@ "init": { "data": { "hapid": "ID vum Accesspoint (SGTIN)", - "name": "Numm (optional, g\u00ebtt als prefixe fir all Apparat benotzt)", - "pin": "Pin Code (Optional)" + "name": "Numm (optionell, g\u00ebtt als prefixe fir all Apparat benotzt)", + "pin": "Pin Code" }, "title": "HomematicIP Accesspoint auswielen" }, diff --git a/homeassistant/components/homematicip_cloud/translations/nb.json b/homeassistant/components/homematicip_cloud/translations/nb.json deleted file mode 100644 index b9c78635b91..00000000000 --- a/homeassistant/components/homematicip_cloud/translations/nb.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "error": { - "invalid_pin": "Ugyldig PIN-kode, pr\u00f8v p\u00e5 nytt." - } - } -} \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/translations/nl.json b/homeassistant/components/homematicip_cloud/translations/nl.json index f16e385c3a0..7127b5c5aae 100644 --- a/homeassistant/components/homematicip_cloud/translations/nl.json +++ b/homeassistant/components/homematicip_cloud/translations/nl.json @@ -6,7 +6,6 @@ "unknown": "Er is een onbekende fout opgetreden." }, "error": { - "invalid_pin": "Ongeldige pincode, probeer het opnieuw.", "invalid_sgtin_or_pin": "Ongeldige PIN-code, probeer het nogmaals.", "press_the_button": "Druk op de blauwe knop.", "register_failed": "Kan niet registreren, gelieve opnieuw te proberen.", diff --git a/homeassistant/components/homematicip_cloud/translations/no.json b/homeassistant/components/homematicip_cloud/translations/no.json index 0c045c61db8..ef171c7b52e 100644 --- a/homeassistant/components/homematicip_cloud/translations/no.json +++ b/homeassistant/components/homematicip_cloud/translations/no.json @@ -6,7 +6,6 @@ "unknown": "Uventet feil" }, "error": { - "invalid_pin": "Ugyldig PIN kode, pr\u00f8v igjen.", "invalid_sgtin_or_pin": "Ugyldig SGTIN eller PIN-kode , pr\u00f8v igjen.", "press_the_button": "Vennligst trykk p\u00e5 den bl\u00e5 knappen.", "register_failed": "Kunne ikke registrere, vennligst pr\u00f8v igjen.", diff --git a/homeassistant/components/homematicip_cloud/translations/pl.json b/homeassistant/components/homematicip_cloud/translations/pl.json index a4ce55ce3d8..7b7cdc05cab 100644 --- a/homeassistant/components/homematicip_cloud/translations/pl.json +++ b/homeassistant/components/homematicip_cloud/translations/pl.json @@ -6,7 +6,6 @@ "unknown": "Nieoczekiwany b\u0142\u0105d" }, "error": { - "invalid_pin": "Nieprawid\u0142owy kod PIN, spr\u00f3buj ponownie", "invalid_sgtin_or_pin": "Nieprawid\u0142owy SGTIN lub kod PIN, spr\u00f3buj ponownie", "press_the_button": "Prosz\u0119 nacisn\u0105\u0107 niebieski przycisk", "register_failed": "Nie uda\u0142o si\u0119 zarejestrowa\u0107, spr\u00f3buj ponownie", diff --git a/homeassistant/components/homematicip_cloud/translations/pt.json b/homeassistant/components/homematicip_cloud/translations/pt.json index f8a69ab709d..645ba242561 100644 --- a/homeassistant/components/homematicip_cloud/translations/pt.json +++ b/homeassistant/components/homematicip_cloud/translations/pt.json @@ -6,7 +6,6 @@ "unknown": "Ocorreu um erro desconhecido." }, "error": { - "invalid_pin": "PIN inv\u00e1lido, por favor, tente novamente.", "invalid_sgtin_or_pin": "PIN inv\u00e1lido. Por favor, tente novamente.", "press_the_button": "Por favor, pressione o bot\u00e3o azul.", "register_failed": "Falha ao registar. Por favor, tente novamente.", diff --git a/homeassistant/components/homematicip_cloud/translations/ru.json b/homeassistant/components/homematicip_cloud/translations/ru.json index 6a012260909..875fe2e8985 100644 --- a/homeassistant/components/homematicip_cloud/translations/ru.json +++ b/homeassistant/components/homematicip_cloud/translations/ru.json @@ -6,7 +6,6 @@ "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "error": { - "invalid_pin": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 PIN-\u043a\u043e\u0434, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430.", "invalid_sgtin_or_pin": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 SGTIN \u0438\u043b\u0438 PIN-\u043a\u043e\u0434, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430.", "press_the_button": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u0441\u0438\u043d\u044e\u044e \u043a\u043d\u043e\u043f\u043a\u0443.", "register_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430.", diff --git a/homeassistant/components/homematicip_cloud/translations/zh-Hant.json b/homeassistant/components/homematicip_cloud/translations/zh-Hant.json index b49c1d6348d..21c896182fd 100644 --- a/homeassistant/components/homematicip_cloud/translations/zh-Hant.json +++ b/homeassistant/components/homematicip_cloud/translations/zh-Hant.json @@ -6,7 +6,6 @@ "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "error": { - "invalid_pin": "PIN \u78bc\u7121\u6548\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", "invalid_sgtin_or_pin": "SGTIN \u6216 PIN \u78bc\u7121\u6548\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", "press_the_button": "\u8acb\u6309\u4e0b\u85cd\u8272\u6309\u9215\u3002", "register_failed": "\u8a3b\u518a\u5931\u6557\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", diff --git a/homeassistant/components/honeywell/manifest.json b/homeassistant/components/honeywell/manifest.json index 52abf20bb2f..1fbaff72426 100644 --- a/homeassistant/components/honeywell/manifest.json +++ b/homeassistant/components/honeywell/manifest.json @@ -3,5 +3,5 @@ "name": "Honeywell Total Connect Comfort (US)", "documentation": "https://www.home-assistant.io/integrations/honeywell", "requirements": ["somecomfort==0.5.2"], - "codeowners": ["@zxdavb"] + "codeowners": [] } diff --git a/homeassistant/components/huawei_lte/translations/bg.json b/homeassistant/components/huawei_lte/translations/bg.json index 86d3f37226f..997c3bc1456 100644 --- a/homeassistant/components/huawei_lte/translations/bg.json +++ b/homeassistant/components/huawei_lte/translations/bg.json @@ -6,15 +6,12 @@ "not_huawei_lte": "\u041d\u0435 \u0435 Huawei LTE \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e" }, "error": { - "connection_failed": "\u0421\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435\u0442\u043e \u0435 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e", "connection_timeout": "\u0412\u0440\u0435\u043c\u0435\u0442\u043e \u0437\u0430 \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0438\u0437\u0442\u0435\u0447\u0435", "incorrect_password": "\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u043d\u0430 \u043f\u0430\u0440\u043e\u043b\u0430", "incorrect_username": "\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435", - "incorrect_username_or_password": "\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435 \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u0430", "invalid_url": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d \u0430\u0434\u0440\u0435\u0441", "login_attempts_exceeded": "\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u043d\u0438\u0442\u0435 \u043e\u043f\u0438\u0442\u0438 \u0437\u0430 \u0432\u043b\u0438\u0437\u0430\u043d\u0435 \u0441\u0430 \u043d\u0430\u0434\u0432\u0438\u0448\u0435\u043d\u0438. \u041c\u043e\u043b\u044f, \u043e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e \u043f\u043e-\u043a\u044a\u0441\u043d\u043e", - "response_error": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043e\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e", - "unknown_connection_error": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e" + "response_error": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043e\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e" }, "step": { "user": { diff --git a/homeassistant/components/huawei_lte/translations/ca.json b/homeassistant/components/huawei_lte/translations/ca.json index 856c3986ed0..86e48641a57 100644 --- a/homeassistant/components/huawei_lte/translations/ca.json +++ b/homeassistant/components/huawei_lte/translations/ca.json @@ -6,17 +6,14 @@ "not_huawei_lte": "No \u00e9s un dispositiu Huawei LTE" }, "error": { - "connection_failed": "La connexi\u00f3 ha fallat", "connection_timeout": "S'ha acabat el temps d'espera de la connexi\u00f3", "incorrect_password": "Contrasenya incorrecta", "incorrect_username": "Nom d'usuari incorrecte", - "incorrect_username_or_password": "Nom d'usuari o contrasenya incorrectes", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", "invalid_url": "URL inv\u00e0lid", "login_attempts_exceeded": "Nombre m\u00e0xim d'intents d'inici de sessi\u00f3 superat, torna-ho a provar m\u00e9s tard", "response_error": "S'ha produ\u00eft un error desconegut del dispositiu", - "unknown": "Error inesperat", - "unknown_connection_error": "S'ha produ\u00eft un error desconegut en connectar-se al dispositiu" + "unknown": "Error inesperat" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/cs.json b/homeassistant/components/huawei_lte/translations/cs.json index e8b09e670b0..298cf182b08 100644 --- a/homeassistant/components/huawei_lte/translations/cs.json +++ b/homeassistant/components/huawei_lte/translations/cs.json @@ -6,17 +6,14 @@ "not_huawei_lte": "Nejedn\u00e1 se o za\u0159\u00edzen\u00ed Huawei LTE" }, "error": { - "connection_failed": "P\u0159ipojen\u00ed se nezda\u0159ilo", "connection_timeout": "\u010casov\u00fd limit spojen\u00ed", "incorrect_password": "Nespr\u00e1vn\u00e9 heslo", "incorrect_username": "Nespr\u00e1vn\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no", - "incorrect_username_or_password": "Nespr\u00e1vn\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no nebo heslo", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "invalid_url": "Neplatn\u00e1 adresa URL", "login_attempts_exceeded": "Maxim\u00e1ln\u00ed pokus o p\u0159ihl\u00e1\u0161en\u00ed byl p\u0159ekro\u010den, zkuste to znovu pozd\u011bji", "response_error": "Nezn\u00e1m\u00e1 chyba ze za\u0159\u00edzen\u00ed", - "unknown": "Neo\u010dek\u00e1van\u00e1 chyba", - "unknown_connection_error": "Nezn\u00e1m\u00e1 chyba p\u0159i p\u0159ipojov\u00e1n\u00ed k za\u0159\u00edzen\u00ed" + "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "flow_title": "Huawei LTE: {name}", "step": { @@ -26,6 +23,7 @@ "url": "URL", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" }, + "description": "Zadejte podrobnosti o p\u0159\u00edstupu k za\u0159\u00edzen\u00ed. Zad\u00e1n\u00ed u\u017eivatelsk\u00e9ho jm\u00e9na a hesla je voliteln\u00e9, ale umo\u017e\u0148uje podporu dal\u0161\u00edch funkc\u00ed integrace. Na druhou stranu m\u016f\u017ee pou\u017eit\u00ed autorizovan\u00e9ho p\u0159ipojen\u00ed zp\u016fsobit probl\u00e9my s p\u0159\u00edstupem k webov\u00e9mu rozhran\u00ed Home Assistant zven\u010d\u00ed, kdy\u017e je integrace aktivn\u00ed, a naopak.", "title": "Konfigurovat Huawei LTE" } } diff --git a/homeassistant/components/huawei_lte/translations/da.json b/homeassistant/components/huawei_lte/translations/da.json index 9f377fba47a..52765ad704a 100644 --- a/homeassistant/components/huawei_lte/translations/da.json +++ b/homeassistant/components/huawei_lte/translations/da.json @@ -6,15 +6,12 @@ "not_huawei_lte": "Ikke en Huawei LTE-enhed" }, "error": { - "connection_failed": "Forbindelsen mislykkedes", "connection_timeout": "Timeout for forbindelse", "incorrect_password": "Forkert adgangskode", "incorrect_username": "Forkert brugernavn", - "incorrect_username_or_password": "Forkert brugernavn eller adgangskode", "invalid_url": "Ugyldig webadresse", "login_attempts_exceeded": "Maksimale loginfors\u00f8g overskredet. Pr\u00f8v igen senere", - "response_error": "Ukendt fejl fra enheden", - "unknown_connection_error": "Ukendt fejl ved tilslutning til enheden" + "response_error": "Ukendt fejl fra enheden" }, "step": { "user": { diff --git a/homeassistant/components/huawei_lte/translations/de.json b/homeassistant/components/huawei_lte/translations/de.json index a0fa9914c47..451720ffb16 100644 --- a/homeassistant/components/huawei_lte/translations/de.json +++ b/homeassistant/components/huawei_lte/translations/de.json @@ -6,15 +6,12 @@ "not_huawei_lte": "Kein Huawei LTE-Ger\u00e4t" }, "error": { - "connection_failed": "Verbindung fehlgeschlagen.", "connection_timeout": "Verbindungszeit\u00fcberschreitung", "incorrect_password": "Ung\u00fcltiges Passwort", "incorrect_username": "Ung\u00fcltiger Benutzername", - "incorrect_username_or_password": "Ung\u00fcltiger Benutzername oder Kennwort", "invalid_url": "Ung\u00fcltige URL", "login_attempts_exceeded": "Maximale Anzahl von Anmeldeversuchen \u00fcberschritten. Bitte versuche es sp\u00e4ter erneut", - "response_error": "Unbekannter Fehler vom Ger\u00e4t", - "unknown_connection_error": "Unbekannter Fehler beim Herstellen der Verbindung zum Ger\u00e4t" + "response_error": "Unbekannter Fehler vom Ger\u00e4t" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/en.json b/homeassistant/components/huawei_lte/translations/en.json index fa66aebeba8..57f32fdd2df 100644 --- a/homeassistant/components/huawei_lte/translations/en.json +++ b/homeassistant/components/huawei_lte/translations/en.json @@ -6,17 +6,14 @@ "not_huawei_lte": "Not a Huawei LTE device" }, "error": { - "connection_failed": "Connection failed", "connection_timeout": "Connection timeout", "incorrect_password": "Incorrect password", "incorrect_username": "Incorrect username", - "incorrect_username_or_password": "Incorrect username or password", "invalid_auth": "Invalid authentication", "invalid_url": "Invalid URL", "login_attempts_exceeded": "Maximum login attempts exceeded, please try again later", "response_error": "Unknown error from device", - "unknown": "Unexpected error", - "unknown_connection_error": "Unknown error connecting to device" + "unknown": "Unexpected error" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/es-419.json b/homeassistant/components/huawei_lte/translations/es-419.json index 5802d36b348..29e7658b8e0 100644 --- a/homeassistant/components/huawei_lte/translations/es-419.json +++ b/homeassistant/components/huawei_lte/translations/es-419.json @@ -6,15 +6,12 @@ "not_huawei_lte": "No es un dispositivo Huawei LTE" }, "error": { - "connection_failed": "La conexi\u00f3n fall\u00f3", "connection_timeout": "El tiempo de conexi\u00f3n expir\u00f3", "incorrect_password": "Contrase\u00f1a incorrecta", "incorrect_username": "Nombre de usuario incorrecto", - "incorrect_username_or_password": "Nombre de usuario o contrase\u00f1a incorrecta", "invalid_url": "URL invalida", "login_attempts_exceeded": "Se han excedido los intentos de inicio de sesi\u00f3n m\u00e1ximos. Vuelva a intentarlo m\u00e1s tarde", - "response_error": "Error desconocido del dispositivo", - "unknown_connection_error": "Error desconocido al conectarse al dispositivo" + "response_error": "Error desconocido del dispositivo" }, "step": { "user": { diff --git a/homeassistant/components/huawei_lte/translations/es.json b/homeassistant/components/huawei_lte/translations/es.json index 289bd7c534c..d283073281d 100644 --- a/homeassistant/components/huawei_lte/translations/es.json +++ b/homeassistant/components/huawei_lte/translations/es.json @@ -6,17 +6,14 @@ "not_huawei_lte": "No es un dispositivo Huawei LTE" }, "error": { - "connection_failed": "Fallo de conexi\u00f3n", "connection_timeout": "Tiempo de espera de la conexi\u00f3n superado", "incorrect_password": "Contrase\u00f1a incorrecta", "incorrect_username": "Nombre de usuario incorrecto", - "incorrect_username_or_password": "Nombre de usuario o contrase\u00f1a incorrectos", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", "invalid_url": "URL no v\u00e1lida", "login_attempts_exceeded": "Se han superado los intentos de inicio de sesi\u00f3n m\u00e1ximos, int\u00e9ntelo de nuevo m\u00e1s tarde.", "response_error": "Error desconocido del dispositivo", - "unknown": "Error inesperado", - "unknown_connection_error": "Error desconocido al conectarse al dispositivo" + "unknown": "Error inesperado" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/et.json b/homeassistant/components/huawei_lte/translations/et.json index cfacbf7b57d..17647ef6877 100644 --- a/homeassistant/components/huawei_lte/translations/et.json +++ b/homeassistant/components/huawei_lte/translations/et.json @@ -2,15 +2,20 @@ "config": { "abort": { "already_configured": "Seade on juba seadistatud", - "already_in_progress": "Seadistamine on juba k\u00e4imas" + "already_in_progress": "Seadistamine on juba k\u00e4imas", + "not_huawei_lte": "Pole Huawei LTE seade" }, "error": { + "connection_timeout": "\u00dchenduse ajal\u00f5pp", "incorrect_password": "Vale salas\u00f5na", "incorrect_username": "Vale kasutajanimi", - "incorrect_username_or_password": "Vale kasutajanimi v\u00f5i salas\u00f5na", "invalid_auth": "Tuvastamise viga", + "invalid_url": "Sobimatu URL", + "login_attempts_exceeded": "Sisselogimiskatsete arv on \u00fcletatud. Proovi hiljem uuesti", + "response_error": "Seade andis tuvastamatu t\u00f5rke", "unknown": "Ootamatu t\u00f5rge" }, + "flow_title": "", "step": { "user": { "data": { @@ -18,7 +23,19 @@ "url": "URL", "username": "Kasutajanimi" }, - "description": "Sisesta seadmele juurdep\u00e4\u00e4su \u00fcksikasjad. Kasutajanime ja salas\u00f5na m\u00e4\u00e4ramine on valikuline kuid v\u00f5imaldab rohkemate sidumisfunktsioonide toetamist. Teisest k\u00fcljest v\u00f5ib volitatud \u00fchenduse kasutamine p\u00f5hjustada probleeme seadme veebiliidese ligip\u00e4\u00e4suga v\u00e4ljastpoolt Home assistant'i kui sidumine on aktiivne ja vastupidi." + "description": "Sisesta seadmele juurdep\u00e4\u00e4su \u00fcksikasjad. Kasutajanime ja salas\u00f5na m\u00e4\u00e4ramine on valikuline kuid v\u00f5imaldab rohkemate sidumisfunktsioonide toetamist. Teisest k\u00fcljest v\u00f5ib volitatud \u00fchenduse kasutamine p\u00f5hjustada probleeme seadme veebiliidese ligip\u00e4\u00e4suga v\u00e4ljastpoolt Home assistant'i kui sidumine on aktiivne ja vastupidi.", + "title": "Huawei LTE seadistamine" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "name": "Teavitusteenuse nimi (muudatus n\u00f5uab taask\u00e4ivitamist)", + "recipient": "SMS teavituse saajad", + "track_new_devices": "Uute seadmete j\u00e4lgimine" + } } } } diff --git a/homeassistant/components/huawei_lte/translations/fr.json b/homeassistant/components/huawei_lte/translations/fr.json index 0662843a918..e598f4a3b86 100644 --- a/homeassistant/components/huawei_lte/translations/fr.json +++ b/homeassistant/components/huawei_lte/translations/fr.json @@ -6,17 +6,14 @@ "not_huawei_lte": "Pas un appareil Huawei LTE" }, "error": { - "connection_failed": "La connexion a \u00e9chou\u00e9", "connection_timeout": "D\u00e9lai de connexion d\u00e9pass\u00e9", "incorrect_password": "Mot de passe incorrect", "incorrect_username": "Nom d'utilisateur incorrect", - "incorrect_username_or_password": "identifiant ou mot de passe incorrect", "invalid_auth": "Authentification invalide", "invalid_url": "URL invalide", "login_attempts_exceeded": "Nombre maximal de tentatives de connexion d\u00e9pass\u00e9, veuillez r\u00e9essayer ult\u00e9rieurement", "response_error": "Erreur inconnue de l'appareil", - "unknown": "Erreur inattendue", - "unknown_connection_error": "Erreur inconnue lors de la connexion \u00e0 l'appareil" + "unknown": "Erreur inattendue" }, "flow_title": "Huawei LTE: {nom}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/hu.json b/homeassistant/components/huawei_lte/translations/hu.json index ec5aa78aefd..90814fea5a5 100644 --- a/homeassistant/components/huawei_lte/translations/hu.json +++ b/homeassistant/components/huawei_lte/translations/hu.json @@ -6,11 +6,9 @@ "not_huawei_lte": "Nem Huawei LTE eszk\u00f6z" }, "error": { - "connection_failed": "Kapcsol\u00f3d\u00e1s sikertelen", "connection_timeout": "Kapcsolat id\u0151t\u00fall\u00e9p\u00e9se", "incorrect_password": "Hib\u00e1s jelsz\u00f3", "incorrect_username": "Helytelen felhaszn\u00e1l\u00f3n\u00e9v", - "incorrect_username_or_password": "Helytelen felhaszn\u00e1l\u00f3n\u00e9v vagy jelsz\u00f3", "invalid_url": "\u00c9rv\u00e9nytelen URL" }, "step": { diff --git a/homeassistant/components/huawei_lte/translations/it.json b/homeassistant/components/huawei_lte/translations/it.json index cf6e97846d3..675cc7ad969 100644 --- a/homeassistant/components/huawei_lte/translations/it.json +++ b/homeassistant/components/huawei_lte/translations/it.json @@ -6,17 +6,14 @@ "not_huawei_lte": "Non \u00e8 un dispositivo Huawei LTE" }, "error": { - "connection_failed": "Connessione fallita", "connection_timeout": "Timeout di connessione", "incorrect_password": "Password errata", "incorrect_username": "Nome utente errato", - "incorrect_username_or_password": "Nome utente o password errati", "invalid_auth": "Autenticazione non valida", "invalid_url": "URL non valido", "login_attempts_exceeded": "Superati i tentativi di accesso massimi, riprovare pi\u00f9 tardi", "response_error": "Errore sconosciuto dal dispositivo", - "unknown": "Errore imprevisto", - "unknown_connection_error": "Errore sconosciuto durante la connessione al dispositivo" + "unknown": "Errore imprevisto" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/ko.json b/homeassistant/components/huawei_lte/translations/ko.json index fd26e454d33..6469bf6a696 100644 --- a/homeassistant/components/huawei_lte/translations/ko.json +++ b/homeassistant/components/huawei_lte/translations/ko.json @@ -6,15 +6,12 @@ "not_huawei_lte": "\ud654\uc6e8\uc774 LTE \uae30\uae30\uac00 \uc544\ub2d9\ub2c8\ub2e4" }, "error": { - "connection_failed": "\uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", "connection_timeout": "\uc811\uc18d \uc2dc\uac04 \ucd08\uacfc", "incorrect_password": "\ube44\ubc00\ubc88\ud638\uac00 \uc77c\uce58\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4", "incorrect_username": "\uc0ac\uc6a9\uc790 \uc774\ub984\uc774 \uc77c\uce58\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4", - "incorrect_username_or_password": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ub610\ub294 \ube44\ubc00\ubc88\ud638\uac00 \uc77c\uce58\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4", "invalid_url": "URL \uc8fc\uc18c\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "login_attempts_exceeded": "\ucd5c\ub300 \ub85c\uadf8\uc778 \uc2dc\ub3c4 \ud69f\uc218\ub97c \ucd08\uacfc\ud588\uc2b5\ub2c8\ub2e4. \ub098\uc911\uc5d0 \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694", - "response_error": "\uae30\uae30\uc5d0\uc11c \uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4", - "unknown_connection_error": "\uae30\uae30\uc5d0 \uc5f0\uacb0\ud558\ub294 \uc911 \uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" + "response_error": "\uae30\uae30\uc5d0\uc11c \uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/lb.json b/homeassistant/components/huawei_lte/translations/lb.json index 4aa8a29bfc2..d6983bed8fc 100644 --- a/homeassistant/components/huawei_lte/translations/lb.json +++ b/homeassistant/components/huawei_lte/translations/lb.json @@ -1,21 +1,19 @@ { "config": { "abort": { - "already_configured": "D\u00ebsen Apparat ass scho konfigur\u00e9iert", - "already_in_progress": "D\u00ebsen Apparat g\u00ebtt scho konfigur\u00e9iert", + "already_configured": "Apparat ass scho konfigur\u00e9iert", + "already_in_progress": "Konfiguratioun's Oflas ass schon am gaang", "not_huawei_lte": "Keen Huawei LTE Apparat" }, "error": { - "connection_failed": "Feeler bei der Verbindung", "connection_timeout": "Z\u00e4it Iwwerschreidung beim verbannen", "incorrect_password": "Ong\u00ebltegt Passwuert", "incorrect_username": "Ong\u00ebltege Benotzernumm", - "incorrect_username_or_password": "Ong\u00ebltege Benotzernumm oder Passwuert", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "invalid_url": "Ong\u00eblteg URL", "login_attempts_exceeded": "Maximal Login Versich iwwerschratt, w.e.g. m\u00e9i sp\u00e9it nach eng K\u00e9ier", "response_error": "Onbekannte Feeler vum Apparat", - "unknown_connection_error": "Onbekannte Feeler beim verbannen mam Apparat" + "unknown": "Onerwaarte Feeler" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/nl.json b/homeassistant/components/huawei_lte/translations/nl.json index d422122185e..dd51fdc1bc5 100644 --- a/homeassistant/components/huawei_lte/translations/nl.json +++ b/homeassistant/components/huawei_lte/translations/nl.json @@ -6,15 +6,14 @@ "not_huawei_lte": "Geen Huawei LTE-apparaat" }, "error": { - "connection_failed": "Verbinding mislukt", "connection_timeout": "Time-out van de verbinding", "incorrect_password": "Onjuist wachtwoord", "incorrect_username": "Onjuiste gebruikersnaam", - "incorrect_username_or_password": "Onjuiste gebruikersnaam of wachtwoord", + "invalid_auth": "Ongeldige authenticatie", "invalid_url": "Ongeldige URL", "login_attempts_exceeded": "Maximale aanmeldingspogingen overschreden, probeer het later opnieuw.", "response_error": "Onbekende fout van het apparaat", - "unknown_connection_error": "Onbekende fout bij verbinden met apparaat" + "unknown": "Onverwachte fout" }, "step": { "user": { diff --git a/homeassistant/components/huawei_lte/translations/no.json b/homeassistant/components/huawei_lte/translations/no.json index f33b8862278..9cd5e164464 100644 --- a/homeassistant/components/huawei_lte/translations/no.json +++ b/homeassistant/components/huawei_lte/translations/no.json @@ -6,17 +6,14 @@ "not_huawei_lte": "Ikke en Huawei LTE-enhet" }, "error": { - "connection_failed": "Tilkoblingen mislyktes", "connection_timeout": "Tilkoblingsavbrudd", "incorrect_password": "Feil passord", "incorrect_username": "Feil brukernavn", - "incorrect_username_or_password": "Feil brukernavn eller passord", "invalid_auth": "Ugyldig godkjenning", "invalid_url": "Ugyldig URL-adresse", "login_attempts_exceeded": "Maksimalt antall p\u00e5loggingsfors\u00f8k er overskredet, vennligst pr\u00f8v igjen senere", "response_error": "Ukjent feil fra enheten", - "unknown": "Uventet feil", - "unknown_connection_error": "Ukjent feil under tilkobling til enhet" + "unknown": "Uventet feil" }, "flow_title": "", "step": { diff --git a/homeassistant/components/huawei_lte/translations/pl.json b/homeassistant/components/huawei_lte/translations/pl.json index 5fe46e184d3..0cc6269c05d 100644 --- a/homeassistant/components/huawei_lte/translations/pl.json +++ b/homeassistant/components/huawei_lte/translations/pl.json @@ -6,17 +6,14 @@ "not_huawei_lte": "To nie jest urz\u0105dzenie Huawei LTE" }, "error": { - "connection_failed": "Po\u0142\u0105czenie nie powiod\u0142o si\u0119", "connection_timeout": "Przekroczono limit czasu pr\u00f3by po\u0142\u0105czenia", "incorrect_password": "Nieprawid\u0142owe has\u0142o", "incorrect_username": "Nieprawid\u0142owa nazwa u\u017cytkownika", - "incorrect_username_or_password": "Nieprawid\u0142owa nazwa u\u017cytkownika lub has\u0142o", "invalid_auth": "Niepoprawne uwierzytelnienie", "invalid_url": "Nieprawid\u0142owy URL", "login_attempts_exceeded": "Przekroczono maksymaln\u0105 liczb\u0119 pr\u00f3b logowania. Spr\u00f3buj ponownie p\u00f3\u017aniej.", "response_error": "Wyst\u0105pi\u0142 nieznany b\u0142\u0105d w urz\u0105dzeniu", - "unknown": "Nieoczekiwany b\u0142\u0105d", - "unknown_connection_error": "Nieznany b\u0142\u0105d podczas \u0142\u0105czenia z urz\u0105dzeniem" + "unknown": "Nieoczekiwany b\u0142\u0105d" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/pt.json b/homeassistant/components/huawei_lte/translations/pt.json index b92752d7d13..81a8804ee40 100644 --- a/homeassistant/components/huawei_lte/translations/pt.json +++ b/homeassistant/components/huawei_lte/translations/pt.json @@ -7,8 +7,7 @@ "error": { "connection_timeout": "Liga\u00e7\u00e3o expirou", "incorrect_password": "Palavra-passe incorreta", - "incorrect_username": "Nome de Utilizador incorreto", - "incorrect_username_or_password": "Nome de utilizador ou palavra passe incorretos" + "incorrect_username": "Nome de Utilizador incorreto" }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/ru.json b/homeassistant/components/huawei_lte/translations/ru.json index 68c025894cd..88457457796 100644 --- a/homeassistant/components/huawei_lte/translations/ru.json +++ b/homeassistant/components/huawei_lte/translations/ru.json @@ -6,17 +6,14 @@ "not_huawei_lte": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c Huawei LTE" }, "error": { - "connection_failed": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.", "connection_timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.", "incorrect_password": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c.", "incorrect_username": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d.", - "incorrect_username_or_password": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c.", "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_url": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 URL-\u0430\u0434\u0440\u0435\u0441.", "login_attempts_exceeded": "\u041f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0432\u0445\u043e\u0434\u0430, \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.", "response_error": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", - "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", - "unknown_connection_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443." + "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "flow_title": "Huawei LTE: {name}", "step": { diff --git a/homeassistant/components/huawei_lte/translations/sl.json b/homeassistant/components/huawei_lte/translations/sl.json index 8898a9123df..07a9b269986 100644 --- a/homeassistant/components/huawei_lte/translations/sl.json +++ b/homeassistant/components/huawei_lte/translations/sl.json @@ -6,15 +6,12 @@ "not_huawei_lte": "Ni naprava Huawei LTE" }, "error": { - "connection_failed": "Povezava ni uspela", "connection_timeout": "\u010casovna omejitev povezave", "incorrect_password": "Nepravilno geslo", "incorrect_username": "Nepravilno uporabni\u0161ko ime", - "incorrect_username_or_password": "Nepravilno uporabni\u0161ko ime ali geslo", "invalid_url": "Neveljaven URL", "login_attempts_exceeded": "Najve\u010d poskusov prijave prese\u017eeno, prosimo, poskusite znova pozneje", - "response_error": "Neznana napaka iz naprave", - "unknown_connection_error": "Neznana napaka pri povezovanju z napravo" + "response_error": "Neznana napaka iz naprave" }, "step": { "user": { diff --git a/homeassistant/components/huawei_lte/translations/sv.json b/homeassistant/components/huawei_lte/translations/sv.json index 15af95e6e9e..3f478c3f826 100644 --- a/homeassistant/components/huawei_lte/translations/sv.json +++ b/homeassistant/components/huawei_lte/translations/sv.json @@ -6,15 +6,12 @@ "not_huawei_lte": "Inte en Huawei LTE-enhet" }, "error": { - "connection_failed": "Anslutningen misslyckades", "connection_timeout": "Timeout f\u00f6r anslutning", "incorrect_password": "Felaktigt l\u00f6senord", "incorrect_username": "Felaktigt anv\u00e4ndarnamn", - "incorrect_username_or_password": "Felaktigt anv\u00e4ndarnamn eller l\u00f6senord", "invalid_url": "Ogiltig URL", "login_attempts_exceeded": "Maximala inloggningsf\u00f6rs\u00f6k har \u00f6verskridits, f\u00f6rs\u00f6k igen senare", - "response_error": "Ok\u00e4nt fel fr\u00e5n enheten", - "unknown_connection_error": "Ok\u00e4nt fel vid anslutning till enheten" + "response_error": "Ok\u00e4nt fel fr\u00e5n enheten" }, "step": { "user": { diff --git a/homeassistant/components/huawei_lte/translations/zh-Hans.json b/homeassistant/components/huawei_lte/translations/zh-Hans.json index 2f499964108..987c53e4d5c 100644 --- a/homeassistant/components/huawei_lte/translations/zh-Hans.json +++ b/homeassistant/components/huawei_lte/translations/zh-Hans.json @@ -1,9 +1,7 @@ { "config": { "error": { - "connection_failed": "\u8fde\u63a5\u5931\u8d25", - "incorrect_username": "\u7528\u6237\u540d\u9519\u8bef", - "incorrect_username_or_password": "\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef" + "incorrect_username": "\u7528\u6237\u540d\u9519\u8bef" } } } \ No newline at end of file diff --git a/homeassistant/components/huawei_lte/translations/zh-Hant.json b/homeassistant/components/huawei_lte/translations/zh-Hant.json index 7dcc0f8851d..f0ea5d28ffb 100644 --- a/homeassistant/components/huawei_lte/translations/zh-Hant.json +++ b/homeassistant/components/huawei_lte/translations/zh-Hant.json @@ -6,17 +6,14 @@ "not_huawei_lte": "\u4e26\u975e\u83ef\u70ba LTE \u8a2d\u5099" }, "error": { - "connection_failed": "\u9023\u7dda\u5931\u6557", "connection_timeout": "\u9023\u7dda\u903e\u6642", "incorrect_password": "\u5bc6\u78bc\u932f\u8aa4", "incorrect_username": "\u4f7f\u7528\u8005\u540d\u7a31\u932f\u8aa4", - "incorrect_username_or_password": "\u4f7f\u7528\u8005\u540d\u7a31\u6216\u5bc6\u78bc\u932f\u8aa4", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", "invalid_url": "\u7db2\u5740\u7121\u6548", "login_attempts_exceeded": "\u5df2\u9054\u5617\u8a66\u767b\u5165\u6700\u5927\u6b21\u6578\uff0c\u8acb\u7a0d\u5f8c\u518d\u8a66", "response_error": "\u4f86\u81ea\u8a2d\u5099\u672a\u77e5\u932f\u8aa4", - "unknown": "\u672a\u9810\u671f\u932f\u8aa4", - "unknown_connection_error": "\u9023\u7dda\u81f3\u8a2d\u5099\u672a\u77e5\u932f\u8aa4" + "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "flow_title": "\u83ef\u70ba LTE\uff1a{name}", "step": { diff --git a/homeassistant/components/hue/device_trigger.py b/homeassistant/components/hue/device_trigger.py index c3dc18cd5df..e65b362f9e7 100644 --- a/homeassistant/components/hue/device_trigger.py +++ b/homeassistant/components/hue/device_trigger.py @@ -160,7 +160,7 @@ async def async_get_triggers(hass, device_id): return triggers = [] - for trigger, subtype in REMOTES[device.model].keys(): + for trigger, subtype in REMOTES[device.model]: triggers.append( { CONF_DEVICE_ID: device_id, diff --git a/homeassistant/components/hue/translations/cs.json b/homeassistant/components/hue/translations/cs.json index 3143924caa0..76606338320 100644 --- a/homeassistant/components/hue/translations/cs.json +++ b/homeassistant/components/hue/translations/cs.json @@ -22,7 +22,7 @@ "title": "Vybrat Hue p\u0159emost\u011bn\u00ed" }, "link": { - "description": "Stiskn\u011bte tla\u010d\u00edtko na p\u0159emost\u011bn\u00ed k registraci Philips Hue v Home Assistant.\n\n! [Um\u00edst\u011bn\u00ed tla\u010d\u00edtka na p\u0159emost\u011bn\u00ed](/ static/images/config_philips_hue.jpg)", + "description": "Stiskn\u011bte tla\u010d\u00edtko na p\u0159emost\u011bn\u00ed k registraci Philips Hue v Home Assistant.\n\n![Um\u00edst\u011bn\u00ed tla\u010d\u00edtka na p\u0159emost\u011bn\u00ed](/static/images/config_philips_hue.jpg)", "title": "P\u0159ipojit Hub" }, "manual": { @@ -47,6 +47,7 @@ "turn_on": "Zapnout" }, "trigger_type": { + "remote_button_long_release": "Tla\u010d\u00edtko \"{subtype}\" uvoln\u011bno po dlouh\u00e9m stisku", "remote_button_short_press": "Stisknuto tla\u010d\u00edtko \"{subtype}\"", "remote_button_short_release": "Uvoln\u011bno tla\u010d\u00edtko \"{subtype}\"", "remote_double_button_long_press": "Oba \"{subtype}\" uvoln\u011bny po dlouh\u00e9m stisku", @@ -57,7 +58,8 @@ "step": { "init": { "data": { - "allow_hue_groups": "Povolit skupiny Hue" + "allow_hue_groups": "Povolit skupiny Hue", + "allow_unreachable": "Povolit nedostupn\u00fdm \u017e\u00e1rovk\u00e1m spr\u00e1vn\u011b hl\u00e1sit jejich stav" } } } diff --git a/homeassistant/components/hue/translations/et.json b/homeassistant/components/hue/translations/et.json index 53695563f8b..fcec56b9d0b 100644 --- a/homeassistant/components/hue/translations/et.json +++ b/homeassistant/components/hue/translations/et.json @@ -7,6 +7,7 @@ "cannot_connect": "\u00dchendus nurjus", "discover_timeout": "Ei leia Philips Hue sildu", "no_bridges": "Philips Hue sildu ei avastatud", + "not_hue_bridge": "See pole Hue sild", "unknown": "Ilmnes tundmatu viga" }, "error": { @@ -27,7 +28,8 @@ "manual": { "data": { "host": "" - } + }, + "title": "Hue silla k\u00e4sitsi seadistamine" } } }, @@ -51,5 +53,15 @@ "remote_double_button_long_press": "M\u00f5lemad \"{subtype}\" nupud vabastatati p\u00e4rast pikka vajutust", "remote_double_button_short_press": "M\u00f5lemad \"{subtype}\" nupud vabastatati" } + }, + "options": { + "step": { + "init": { + "data": { + "allow_hue_groups": "Luba Hue r\u00fchmad", + "allow_unreachable": "Luba k\u00e4ttesaamatutel pirnidel oma olekust \u00f5igesti teatada" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/hue/translations/lb.json b/homeassistant/components/hue/translations/lb.json index 46960929404..9a713b1cb52 100644 --- a/homeassistant/components/hue/translations/lb.json +++ b/homeassistant/components/hue/translations/lb.json @@ -2,16 +2,16 @@ "config": { "abort": { "all_configured": "All Philips Hue Bridge si scho\u00a0konfigur\u00e9iert", - "already_configured": "Bridge ass scho konfigur\u00e9iert", - "already_in_progress": "Konfiguratioun fir d\u00ebsen Apparat ass schonn am gaang.", - "cannot_connect": "Keng Verbindung mat der bridge m\u00e9iglech", + "already_configured": "Apparat ass scho konfigur\u00e9iert", + "already_in_progress": "Konfiguratioun's Oflas ass schon am gaang", + "cannot_connect": "Feeler beim verbannen", "discover_timeout": "Keng Hue bridge fonnt", "no_bridges": "Keng Philips Hue Bridge fonnt", "not_hue_bridge": "Keng Hue Bridge", - "unknown": "Onbekannten Feeler opgetrueden" + "unknown": "Onerwaarte Feeler" }, "error": { - "linking": "Onbekannte Liaisoun's Feeler opgetrueden", + "linking": "Onerwaarte Feeler", "register_failed": "Feeler beim registr\u00e9ieren, prob\u00e9iert w.e.g. nach emol" }, "step": { @@ -58,7 +58,8 @@ "step": { "init": { "data": { - "allow_hue_groups": "Hue Gruppen erlaaben" + "allow_hue_groups": "Hue Gruppen erlaaben", + "allow_unreachable": "Erlaabt net erreechbar Bieren hir Zoust\u00e4nn richteg ze mellen" } } } diff --git a/homeassistant/components/hue/translations/nl.json b/homeassistant/components/hue/translations/nl.json index 73817f52488..f04d372bf6a 100644 --- a/homeassistant/components/hue/translations/nl.json +++ b/homeassistant/components/hue/translations/nl.json @@ -24,6 +24,11 @@ "link": { "description": "Druk op de knop van de bridge om Philips Hue te registreren met Home Assistant. \n\n![Locatie van de knop op bridge](/static/images/config_philips_hue.jpg)", "title": "Link Hub" + }, + "manual": { + "data": { + "host": "Host" + } } } }, diff --git a/homeassistant/components/hue/translations/pl.json b/homeassistant/components/hue/translations/pl.json index 4c101ae9386..873f60946d5 100644 --- a/homeassistant/components/hue/translations/pl.json +++ b/homeassistant/components/hue/translations/pl.json @@ -22,7 +22,7 @@ "title": "Wybierz mostek Hue" }, "link": { - "description": "Naci\u015bnij przycisk na mostku, aby zarejestrowa\u0107 Philips Hue w Home Assistant.\n\n![Location of button on bridge](/static/images/config_philips_hue.jpg)", + "description": "Naci\u015bnij przycisk na mostku, aby zarejestrowa\u0107 Philips Hue w Home Assistant.\n\n![Umiejscowienie przycisku na mostku](/static/images/config_philips_hue.jpg)", "title": "Hub Link" }, "manual": { diff --git a/homeassistant/components/hue/translations/ru.json b/homeassistant/components/hue/translations/ru.json index 12313583030..81cbe6a385f 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/humidifier/translations/et.json b/homeassistant/components/humidifier/translations/et.json index 8e401417a38..fe2b98d4f97 100644 --- a/homeassistant/components/humidifier/translations/et.json +++ b/homeassistant/components/humidifier/translations/et.json @@ -23,5 +23,6 @@ "off": "V\u00e4ljas", "on": "Sees" } - } + }, + "title": "\u00d5huniisutaja" } \ No newline at end of file diff --git a/homeassistant/components/humidifier/translations/pl.json b/homeassistant/components/humidifier/translations/pl.json index af049417782..450631e9678 100644 --- a/homeassistant/components/humidifier/translations/pl.json +++ b/homeassistant/components/humidifier/translations/pl.json @@ -8,9 +8,9 @@ "turn_on": "w\u0142\u0105cz {entity_name}" }, "condition_type": { - "is_mode": "{entity_name} ma ustawiony tryb", + "is_mode": "na {entity_name} jest ustawiony okre\u015blony tryb", "is_off": "nawil\u017cacz {entity_name} jest wy\u0142\u0105czony", - "is_on": "nawil\u017cacz{entity_name} jest w\u0142\u0105czony" + "is_on": "nawil\u017cacz {entity_name} jest w\u0142\u0105czony" }, "trigger_type": { "target_humidity_changed": "zmieni si\u0119 wilgotno\u015b\u0107 docelowa {entity_name}", diff --git a/homeassistant/components/hunterdouglas_powerview/strings.json b/homeassistant/components/hunterdouglas_powerview/strings.json index 5d0b042454d..a1c91cd2ed4 100644 --- a/homeassistant/components/hunterdouglas_powerview/strings.json +++ b/homeassistant/components/hunterdouglas_powerview/strings.json @@ -1,5 +1,4 @@ { - "title": "Hunter Douglas PowerView", "config": { "step": { "user": { diff --git a/homeassistant/components/hunterdouglas_powerview/translations/ca.json b/homeassistant/components/hunterdouglas_powerview/translations/ca.json index cba63e0d12f..9029b4bcff5 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/ca.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/ca.json @@ -19,6 +19,5 @@ "title": "Connexi\u00f3 amb el Hub PowerView" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/cs.json b/homeassistant/components/hunterdouglas_powerview/translations/cs.json index fb71c85166c..a238aca6c1c 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/cs.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/cs.json @@ -19,6 +19,5 @@ "title": "P\u0159ipojen\u00ed k rozbo\u010dova\u010di PowerView" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/de.json b/homeassistant/components/hunterdouglas_powerview/translations/de.json index 50dc39b3d98..4c843fb262f 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/de.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/de.json @@ -4,7 +4,7 @@ "already_configured": "Ger\u00e4t ist bereits konfiguriert" }, "error": { - "cannot_connect": "Verbindung fehlgeschlagen, versuchen Sie es erneut", + "cannot_connect": "Verbindung fehlgeschlagen", "unknown": "Unerwarteter Fehler" }, "step": { @@ -19,6 +19,5 @@ "title": "Stellen Sie eine Verbindung zum PowerView Hub her" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/en.json b/homeassistant/components/hunterdouglas_powerview/translations/en.json index 7188e296bce..b2d09aac12c 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/en.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/en.json @@ -19,6 +19,5 @@ "title": "Connect to the PowerView Hub" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/es-419.json b/homeassistant/components/hunterdouglas_powerview/translations/es-419.json index c4a26d7d35d..13ebf7348d8 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/es-419.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/es-419.json @@ -19,6 +19,5 @@ "title": "Conectar a Powerview Hub" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/es.json b/homeassistant/components/hunterdouglas_powerview/translations/es.json index 46e216976bd..1095ed06ed7 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/es.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/es.json @@ -19,6 +19,5 @@ "title": "Conectar con el PowerView Hub" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/et.json b/homeassistant/components/hunterdouglas_powerview/translations/et.json index 8294722585b..78b9fdba10b 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/et.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/et.json @@ -9,12 +9,14 @@ }, "step": { "link": { - "description": "Kas soovid seadistada {name}({host})?" + "description": "Kas soovid seadistada {name}({host})?", + "title": "Loo \u00fchendusPowerView Hub-iga" }, "user": { "data": { "host": "IP aadress" - } + }, + "title": "Loo \u00fchendusPowerView Hub-iga" } } } diff --git a/homeassistant/components/hunterdouglas_powerview/translations/fi.json b/homeassistant/components/hunterdouglas_powerview/translations/fi.json index 3dfa8931bff..2370960198c 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/fi.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/fi.json @@ -18,6 +18,5 @@ "title": "Yhdist\u00e4 PowerView-keskittimeen" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/fr.json b/homeassistant/components/hunterdouglas_powerview/translations/fr.json index e5208ebdd68..a1bd06078c6 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/fr.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/fr.json @@ -19,6 +19,5 @@ "title": "Connectez-vous au concentrateur PowerView" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/it.json b/homeassistant/components/hunterdouglas_powerview/translations/it.json index 2042fced9af..f8ff617f008 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/it.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/it.json @@ -19,6 +19,5 @@ "title": "Collegamento al PowerView Hub" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/ko.json b/homeassistant/components/hunterdouglas_powerview/translations/ko.json index 23a02dd2a5f..cba1b761682 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/ko.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/ko.json @@ -19,6 +19,5 @@ "title": "PowerView \ud5c8\ube0c\uc5d0 \uc5f0\uacb0\ud558\uae30" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/lb.json b/homeassistant/components/hunterdouglas_powerview/translations/lb.json index f9c13256409..33435d6a63c 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/lb.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/lb.json @@ -19,6 +19,5 @@ "title": "Mam PowerView Hub verbannen" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/nl.json b/homeassistant/components/hunterdouglas_powerview/translations/nl.json index 9c0ab4932de..e988b44a2de 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/nl.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/nl.json @@ -19,6 +19,5 @@ "title": "Maak verbinding met de PowerView Hub" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/no.json b/homeassistant/components/hunterdouglas_powerview/translations/no.json index 97b295dae32..14695bd815e 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/no.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/no.json @@ -19,6 +19,5 @@ "title": "Koble til PowerView-huben" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/pl.json b/homeassistant/components/hunterdouglas_powerview/translations/pl.json index fc48aa17d35..1bf55f64477 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/pl.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/pl.json @@ -19,6 +19,5 @@ "title": "Po\u0142\u0105czenie z hubem PowerView" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/ru.json b/homeassistant/components/hunterdouglas_powerview/translations/ru.json index 75b264b087f..ec20a2c71b1 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/ru.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/ru.json @@ -19,6 +19,5 @@ "title": "Hunter Douglas PowerView" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/sl.json b/homeassistant/components/hunterdouglas_powerview/translations/sl.json index 4edc104f3fc..3334ae7ec4a 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/sl.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/sl.json @@ -19,6 +19,5 @@ "title": "Pove\u017eite se s PowerView Hub" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hunterdouglas_powerview/translations/zh-Hant.json b/homeassistant/components/hunterdouglas_powerview/translations/zh-Hant.json index 1bb4093ad60..85d167fb040 100644 --- a/homeassistant/components/hunterdouglas_powerview/translations/zh-Hant.json +++ b/homeassistant/components/hunterdouglas_powerview/translations/zh-Hant.json @@ -19,6 +19,5 @@ "title": "\u9023\u7dda\u81f3 PowerView Hub" } } - }, - "title": "Hunter Douglas PowerView" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/strings.json b/homeassistant/components/hvv_departures/strings.json index c29ad6cc694..90b53bc0e64 100644 --- a/homeassistant/components/hvv_departures/strings.json +++ b/homeassistant/components/hvv_departures/strings.json @@ -1,5 +1,4 @@ { - "title": "HVV Departures", "config": { "step": { "user": { @@ -45,4 +44,4 @@ } } } -} \ No newline at end of file +} diff --git a/homeassistant/components/hvv_departures/translations/ca.json b/homeassistant/components/hvv_departures/translations/ca.json index 7a6025459c9..fad60206c1c 100644 --- a/homeassistant/components/hvv_departures/translations/ca.json +++ b/homeassistant/components/hvv_departures/translations/ca.json @@ -43,6 +43,5 @@ "title": "Opcions" } } - }, - "title": "HVV Departures" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/cs.json b/homeassistant/components/hvv_departures/translations/cs.json index dbe0007c2a1..6944dce8af2 100644 --- a/homeassistant/components/hvv_departures/translations/cs.json +++ b/homeassistant/components/hvv_departures/translations/cs.json @@ -5,9 +5,22 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" + "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", + "no_results": "\u017d\u00e1dn\u00e9 v\u00fdsledky. Zkuste pou\u017e\u00edt jinou stanici/adresu" }, "step": { + "station": { + "data": { + "station": "Stanice/adresa" + }, + "title": "Zadejte stanici/adresu" + }, + "station_select": { + "data": { + "station": "Stanice/adresa" + }, + "title": "Vyberte stanici/adresu" + }, "user": { "data": { "host": "Hostitel", @@ -22,7 +35,9 @@ "step": { "init": { "data": { - "offset": "Posun (v minut\u00e1ch)" + "filter": "Vyberte linky", + "offset": "Posun (v minut\u00e1ch)", + "real_time": "Pou\u017e\u00edt data v re\u00e1ln\u00e9m \u010dase" }, "title": "Mo\u017enosti" } diff --git a/homeassistant/components/hvv_departures/translations/de.json b/homeassistant/components/hvv_departures/translations/de.json index b383e57bd93..78d830c48db 100644 --- a/homeassistant/components/hvv_departures/translations/de.json +++ b/homeassistant/components/hvv_departures/translations/de.json @@ -4,7 +4,7 @@ "already_configured": "Ger\u00e4t ist bereits konfiguriert" }, "error": { - "cannot_connect": "Verbindung fehlgeschlagen, bitte erneut versuchen", + "cannot_connect": "Verbindung fehlgeschlagen", "invalid_auth": "Ung\u00fcltige Authentifizierung", "no_results": "Keine Ergebnisse. Versuch es mit einer anderen Station/Adresse" }, @@ -43,6 +43,5 @@ "title": "Optionen" } } - }, - "title": "HVV Abfahrten" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/en.json b/homeassistant/components/hvv_departures/translations/en.json index 846457196e5..3f02f88a4d0 100644 --- a/homeassistant/components/hvv_departures/translations/en.json +++ b/homeassistant/components/hvv_departures/translations/en.json @@ -43,6 +43,5 @@ "title": "Options" } } - }, - "title": "HVV Departures" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/es.json b/homeassistant/components/hvv_departures/translations/es.json index fbfe63e4042..d73002c5a4b 100644 --- a/homeassistant/components/hvv_departures/translations/es.json +++ b/homeassistant/components/hvv_departures/translations/es.json @@ -43,6 +43,5 @@ "title": "Opciones" } } - }, - "title": "Salidas de HVV" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/et.json b/homeassistant/components/hvv_departures/translations/et.json index 0c0dcc2adc6..79e6d8b8be8 100644 --- a/homeassistant/components/hvv_departures/translations/et.json +++ b/homeassistant/components/hvv_departures/translations/et.json @@ -5,15 +5,42 @@ }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "invalid_auth": "Tuvastamine nurjus" + "invalid_auth": "Tuvastamine nurjus", + "no_results": "Vasted puuduvad. Proovi m\u00f5ne muu jaama / aadressiga" }, "step": { + "station": { + "data": { + "station": "Jaam/aadress" + }, + "title": "Sisesta jaam/aadress" + }, + "station_select": { + "data": { + "station": "Jaam/aadress" + }, + "title": "Jaama/aadressi valimine" + }, "user": { "data": { "host": "Host", "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "Loo \u00fchendus HVV API'ga" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "filter": "Vali liinid", + "offset": "Nihe (minutites)", + "real_time": "Kasuta reaalaja andmeid" + }, + "description": "Muuda selle v\u00e4ljumisanduri suvandeid", + "title": "Valikud" } } } diff --git a/homeassistant/components/hvv_departures/translations/fr.json b/homeassistant/components/hvv_departures/translations/fr.json index e6560da4047..1ade2ebd742 100644 --- a/homeassistant/components/hvv_departures/translations/fr.json +++ b/homeassistant/components/hvv_departures/translations/fr.json @@ -43,6 +43,5 @@ "title": "Options" } } - }, - "title": "D\u00e9parts HVV" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/it.json b/homeassistant/components/hvv_departures/translations/it.json index 2b9419f70cc..1fafecba7c7 100644 --- a/homeassistant/components/hvv_departures/translations/it.json +++ b/homeassistant/components/hvv_departures/translations/it.json @@ -43,6 +43,5 @@ "title": "Opzioni" } } - }, - "title": "Partenze HVV" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/ko.json b/homeassistant/components/hvv_departures/translations/ko.json index 61b6f5cd49e..41c7f44be7f 100644 --- a/homeassistant/components/hvv_departures/translations/ko.json +++ b/homeassistant/components/hvv_departures/translations/ko.json @@ -43,6 +43,5 @@ "title": "\uc635\uc158" } } - }, - "title": "HVV \ucd9c\ubc1c\ud3b8" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/lb.json b/homeassistant/components/hvv_departures/translations/lb.json index fd624db30ce..2a4555a1a5c 100644 --- a/homeassistant/components/hvv_departures/translations/lb.json +++ b/homeassistant/components/hvv_departures/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "no_results": "Keng Resultater. Prob\u00e9ier mat enger aanerer Statioun/Adress" }, @@ -43,6 +43,5 @@ "title": "Optiounen" } } - }, - "title": "HVV Departe" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/nl.json b/homeassistant/components/hvv_departures/translations/nl.json index 46399483e18..8c80ae5b942 100644 --- a/homeassistant/components/hvv_departures/translations/nl.json +++ b/homeassistant/components/hvv_departures/translations/nl.json @@ -3,12 +3,18 @@ "abort": { "already_configured": "Apparaat is al geconfigureerd" }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie" + }, "step": { "user": { "data": { + "host": "Host", "password": "Wachtwoord", "username": "Gebruikersnaam" - } + }, + "title": "Maak verbinding met de HVV API" } } } diff --git a/homeassistant/components/hvv_departures/translations/no.json b/homeassistant/components/hvv_departures/translations/no.json index 2c7743d61e7..9706a508ac8 100644 --- a/homeassistant/components/hvv_departures/translations/no.json +++ b/homeassistant/components/hvv_departures/translations/no.json @@ -43,6 +43,5 @@ "title": "Alternativer" } } - }, - "title": "HVV Avganger" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/pl.json b/homeassistant/components/hvv_departures/translations/pl.json index 99bc564319a..61765bbdea4 100644 --- a/homeassistant/components/hvv_departures/translations/pl.json +++ b/homeassistant/components/hvv_departures/translations/pl.json @@ -43,6 +43,5 @@ "title": "Opcje" } } - }, - "title": "Odjazdy HVV" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/ru.json b/homeassistant/components/hvv_departures/translations/ru.json index 354faf167a7..ff5819a562d 100644 --- a/homeassistant/components/hvv_departures/translations/ru.json +++ b/homeassistant/components/hvv_departures/translations/ru.json @@ -43,6 +43,5 @@ "title": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b" } } - }, - "title": "HVV Departures" + } } \ No newline at end of file diff --git a/homeassistant/components/hvv_departures/translations/zh-Hant.json b/homeassistant/components/hvv_departures/translations/zh-Hant.json index 5859493eeab..a965fa38816 100644 --- a/homeassistant/components/hvv_departures/translations/zh-Hant.json +++ b/homeassistant/components/hvv_departures/translations/zh-Hant.json @@ -43,6 +43,5 @@ "title": "\u9078\u9805" } } - }, - "title": "HVV \u5217\u8eca\u6642\u523b" + } } \ No newline at end of file diff --git a/homeassistant/components/ialarm/__init__.py b/homeassistant/components/ialarm/__init__.py deleted file mode 100644 index d03609bc1d0..00000000000 --- a/homeassistant/components/ialarm/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The ialarm component.""" diff --git a/homeassistant/components/ialarm/alarm_control_panel.py b/homeassistant/components/ialarm/alarm_control_panel.py deleted file mode 100644 index 67c9ec891a6..00000000000 --- a/homeassistant/components/ialarm/alarm_control_panel.py +++ /dev/null @@ -1,143 +0,0 @@ -"""Interfaces with iAlarm control panels.""" -import logging -import re - -from pyialarm import IAlarm -import voluptuous as vol - -import homeassistant.components.alarm_control_panel as alarm -from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA -from homeassistant.components.alarm_control_panel.const import ( - SUPPORT_ALARM_ARM_AWAY, - SUPPORT_ALARM_ARM_HOME, -) -from homeassistant.const import ( - CONF_CODE, - CONF_HOST, - CONF_NAME, - CONF_PASSWORD, - CONF_USERNAME, - STATE_ALARM_ARMED_AWAY, - STATE_ALARM_ARMED_HOME, - STATE_ALARM_DISARMED, - STATE_ALARM_TRIGGERED, -) -import homeassistant.helpers.config_validation as cv - -_LOGGER = logging.getLogger(__name__) - -DEFAULT_NAME = "iAlarm" - - -def no_application_protocol(value): - """Validate that value is without the application protocol.""" - protocol_separator = "://" - if not value or protocol_separator in value: - raise vol.Invalid(f"Invalid host, {protocol_separator} is not allowed") - - return value - - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( - { - vol.Required(CONF_HOST): vol.All(cv.string, no_application_protocol), - vol.Required(CONF_PASSWORD): cv.string, - vol.Required(CONF_USERNAME): cv.string, - vol.Optional(CONF_CODE): cv.positive_int, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - } -) - - -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up an iAlarm control panel.""" - name = config.get(CONF_NAME) - code = config.get(CONF_CODE) - username = config.get(CONF_USERNAME) - password = config.get(CONF_PASSWORD) - host = config.get(CONF_HOST) - - url = f"http://{host}" - ialarm = IAlarmPanel(name, code, username, password, url) - add_entities([ialarm], True) - - -class IAlarmPanel(alarm.AlarmControlPanelEntity): - """Representation of an iAlarm status.""" - - def __init__(self, name, code, username, password, url): - """Initialize the iAlarm status.""" - - self._name = name - self._code = str(code) if code else None - self._username = username - self._password = password - self._url = url - self._state = None - self._client = IAlarm(username, password, url) - - @property - def name(self): - """Return the name of the device.""" - return self._name - - @property - def code_format(self): - """Return one or more digits/characters.""" - if self._code is None: - return None - if isinstance(self._code, str) and re.search("^\\d+$", self._code): - return alarm.FORMAT_NUMBER - return alarm.FORMAT_TEXT - - @property - def state(self): - """Return the state of the device.""" - return self._state - - @property - def supported_features(self) -> int: - """Return the list of supported features.""" - return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY - - def update(self): - """Return the state of the device.""" - status = self._client.get_status() - _LOGGER.debug("iAlarm status: %s", status) - if status: - status = int(status) - - if status == self._client.DISARMED: - state = STATE_ALARM_DISARMED - elif status == self._client.ARMED_AWAY: - state = STATE_ALARM_ARMED_AWAY - elif status == self._client.ARMED_STAY: - state = STATE_ALARM_ARMED_HOME - elif status == self._client.TRIGGERED: - state = STATE_ALARM_TRIGGERED - else: - state = None - - self._state = state - - def alarm_disarm(self, code=None): - """Send disarm command.""" - if self._validate_code(code): - self._client.disarm() - - def alarm_arm_away(self, code=None): - """Send arm away command.""" - if self._validate_code(code): - self._client.arm_away() - - def alarm_arm_home(self, code=None): - """Send arm home command.""" - if self._validate_code(code): - self._client.arm_stay() - - def _validate_code(self, code): - """Validate given code.""" - check = self._code is None or code == self._code - if not check: - _LOGGER.warning("Wrong code entered") - return check diff --git a/homeassistant/components/ialarm/manifest.json b/homeassistant/components/ialarm/manifest.json deleted file mode 100644 index d5d32e28c59..00000000000 --- a/homeassistant/components/ialarm/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "domain": "ialarm", - "name": "Antifurto365 iAlarm", - "documentation": "https://www.home-assistant.io/integrations/ialarm", - "requirements": ["pyialarm==0.3"], - "codeowners": [] -} diff --git a/homeassistant/components/iaqualink/translations/bg.json b/homeassistant/components/iaqualink/translations/bg.json index 4da913f8e24..01e110fdf2d 100644 --- a/homeassistant/components/iaqualink/translations/bg.json +++ b/homeassistant/components/iaqualink/translations/bg.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "\u041c\u043e\u0436\u0435 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0430 \u0441 iAqualink." - }, - "error": { - "connection_failure": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 iAqualink. \u041f\u0440\u043e\u0432\u0435\u0440\u0435\u0442\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e\u0442\u043e \u0438\u043c\u0435 \u0438 \u043f\u0430\u0440\u043e\u043b\u0430\u0442\u0430." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/iaqualink/translations/ca.json b/homeassistant/components/iaqualink/translations/ca.json index f0ca2ef59e0..8faf28aab27 100644 --- a/homeassistant/components/iaqualink/translations/ca.json +++ b/homeassistant/components/iaqualink/translations/ca.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Nom\u00e9s pots configurar una \u00fanica connexi\u00f3 d'iAqualink.", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_failure": "No s'ha pogut connectar amb iAqualink. Comprova el nom d'usuari i la contrasenya." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/cs.json b/homeassistant/components/iaqualink/translations/cs.json index 6bedd60afd8..990562bbc0a 100644 --- a/homeassistant/components/iaqualink/translations/cs.json +++ b/homeassistant/components/iaqualink/translations/cs.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "M\u016f\u017eete nastavit pouze jedno p\u0159ipojen\u00ed iAqualink.", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_failure": "Nelze se p\u0159ipojit k iAqualink. Zkontrolujte sv\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no a heslo." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/da.json b/homeassistant/components/iaqualink/translations/da.json index 1988db1767f..dc2d9761c57 100644 --- a/homeassistant/components/iaqualink/translations/da.json +++ b/homeassistant/components/iaqualink/translations/da.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Du kan kun konfigurere en enkelt iAqualink-forbindelse." - }, - "error": { - "connection_failure": "Kan ikke oprette forbindelse til iAqualink. Kontroller dit brugernavn og din adgangskode." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/iaqualink/translations/de.json b/homeassistant/components/iaqualink/translations/de.json index 619609c3ac7..e7e1002015c 100644 --- a/homeassistant/components/iaqualink/translations/de.json +++ b/homeassistant/components/iaqualink/translations/de.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Es kann nur eine einzige iAqualink-Verbindung konfiguriert werden." - }, - "error": { - "connection_failure": "Die Verbindung zu iAqualink ist nicht m\u00f6glich. Bitte \u00fcberpr\u00fcfe den Benutzernamen und das Passwort." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/iaqualink/translations/en.json b/homeassistant/components/iaqualink/translations/en.json index 3ddc3a13924..a2a8719f9b7 100644 --- a/homeassistant/components/iaqualink/translations/en.json +++ b/homeassistant/components/iaqualink/translations/en.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "You can only configure a single iAqualink connection.", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "error": { - "cannot_connect": "Failed to connect", - "connection_failure": "Unable to connect to iAqualink. Check your username and password." + "cannot_connect": "Failed to connect" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/es-419.json b/homeassistant/components/iaqualink/translations/es-419.json index 9d43bfa7e57..1b65f9e2c8c 100644 --- a/homeassistant/components/iaqualink/translations/es-419.json +++ b/homeassistant/components/iaqualink/translations/es-419.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Solo puede configurar una \u00fanica conexi\u00f3n iAqualink." - }, - "error": { - "connection_failure": "No se puede conectar a iAqualink. Verifice su nombre de usuario y contrase\u00f1a." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/iaqualink/translations/es.json b/homeassistant/components/iaqualink/translations/es.json index b91ad03b297..7d9c2445fd4 100644 --- a/homeassistant/components/iaqualink/translations/es.json +++ b/homeassistant/components/iaqualink/translations/es.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Solo puede configurar una \u00fanica conexi\u00f3n iAqualink.", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "error": { - "cannot_connect": "No se pudo conectar", - "connection_failure": "No se puede conectar a iAqualink. Verifica tu nombre de usuario y contrase\u00f1a." + "cannot_connect": "No se pudo conectar" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/et.json b/homeassistant/components/iaqualink/translations/et.json index 7a2b5e92aae..d8d681612c3 100644 --- a/homeassistant/components/iaqualink/translations/et.json +++ b/homeassistant/components/iaqualink/translations/et.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Saad h\u00e4\u00e4lestada ainult \u00fche iAqualink konto.", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "error": { - "cannot_connect": "\u00dchendamine nurjus", - "connection_failure": "IAqualink'iga ei saa \u00fchendust luua. Kontrolli oma kasutajanime ja salas\u00f5na." + "cannot_connect": "\u00dchendamine nurjus" }, "step": { "user": { @@ -14,7 +12,8 @@ "password": "Salas\u00f5na", "username": "Kasutajanimi" }, - "description": "Sisesta oma iAqualinki konto kasutajanimi ja salas\u00f5na." + "description": "Sisesta oma iAqualinki konto kasutajanimi ja salas\u00f5na.", + "title": "Loo \u00fchendus iAqualink-iga" } } } diff --git a/homeassistant/components/iaqualink/translations/fr.json b/homeassistant/components/iaqualink/translations/fr.json index 47ed27fb339..b6449ebed74 100644 --- a/homeassistant/components/iaqualink/translations/fr.json +++ b/homeassistant/components/iaqualink/translations/fr.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_setup": "Vous ne pouvez configurer qu'une seule connexion iAqualink." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { - "connection_failure": "Impossible de se connecter \u00e0 iAqualink. V\u00e9rifiez votre nom d'utilisateur et votre mot de passe." + "cannot_connect": "\u00c9chec de connexion" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/it.json b/homeassistant/components/iaqualink/translations/it.json index f1abb66006f..0364c1ebca2 100644 --- a/homeassistant/components/iaqualink/translations/it.json +++ b/homeassistant/components/iaqualink/translations/it.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u00c8 possibile configurare una sola connessione iAqualink.", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "error": { - "cannot_connect": "Impossibile connettersi", - "connection_failure": "Impossibile connettersi a iAqualink. Controllare il nome utente e la password." + "cannot_connect": "Impossibile connettersi" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/ko.json b/homeassistant/components/iaqualink/translations/ko.json index 179a862e67d..6396d5d250e 100644 --- a/homeassistant/components/iaqualink/translations/ko.json +++ b/homeassistant/components/iaqualink/translations/ko.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "\ud558\ub098\uc758 iAqualink \uc5f0\uacb0\ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4." - }, - "error": { - "connection_failure": "iAqualink \uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. \uc0ac\uc6a9\uc790 \uc774\ub984\uacfc \ube44\ubc00\ubc88\ud638\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/iaqualink/translations/lb.json b/homeassistant/components/iaqualink/translations/lb.json index 9a9082841ad..2a5f4dadde7 100644 --- a/homeassistant/components/iaqualink/translations/lb.json +++ b/homeassistant/components/iaqualink/translations/lb.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "Dir k\u00ebnnt n\u00ebmmen eng eenzeg iAqualink Verbindung konfigur\u00e9ieren." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { - "cannot_connect": "Feeler beim verbannen", - "connection_failure": "Kann sech net mat iAqualink verbannen. Iwwerpr\u00e9ift \u00e4ren Benotzernumm an Passwuert" + "cannot_connect": "Feeler beim verbannen" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/nl.json b/homeassistant/components/iaqualink/translations/nl.json index e2034d74fcd..fae8693ce4c 100644 --- a/homeassistant/components/iaqualink/translations/nl.json +++ b/homeassistant/components/iaqualink/translations/nl.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "U kunt slechts \u00e9\u00e9n iAqualink-verbinding configureren.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "error": { - "cannot_connect": "Kan geen verbinding maken", - "connection_failure": "Kan geen verbinding maken met iAqualink. Controleer je gebruikersnaam en wachtwoord." + "cannot_connect": "Kan geen verbinding maken" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/no.json b/homeassistant/components/iaqualink/translations/no.json index 1a8cc479de8..8e9f2ad45ca 100644 --- a/homeassistant/components/iaqualink/translations/no.json +++ b/homeassistant/components/iaqualink/translations/no.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Du kan bare konfigurere en enkel iAqualink-tilkobling.", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "connection_failure": "Kan ikke koble til iAqualink. Sjekk brukernavnet og passordet ditt." + "cannot_connect": "Tilkobling mislyktes" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/pl.json b/homeassistant/components/iaqualink/translations/pl.json index 558a9f82006..ee5cc663543 100644 --- a/homeassistant/components/iaqualink/translations/pl.json +++ b/homeassistant/components/iaqualink/translations/pl.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno po\u0142\u0105czenie iAqualink", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_failure": "Nie mo\u017cna po\u0142\u0105czy\u0107 z iAqualink. Sprawd\u017a nazw\u0119 u\u017cytkownika i has\u0142o." + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/ru.json b/homeassistant/components/iaqualink/translations/ru.json index ac065354124..27531c65d9e 100644 --- a/homeassistant/components/iaqualink/translations/ru.json +++ b/homeassistant/components/iaqualink/translations/ru.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_failure": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a iAqualink. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0412\u0430\u0448 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "user": { diff --git a/homeassistant/components/iaqualink/translations/sl.json b/homeassistant/components/iaqualink/translations/sl.json index 73e988139f9..3b92f653e7f 100644 --- a/homeassistant/components/iaqualink/translations/sl.json +++ b/homeassistant/components/iaqualink/translations/sl.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Konfigurirate lahko samo eno povezavo iAqualink." - }, - "error": { - "connection_failure": "Ne morete vzpostaviti povezave z iAqualink. Preverite va\u0161e uporabni\u0161ko ime in geslo." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/iaqualink/translations/sv.json b/homeassistant/components/iaqualink/translations/sv.json index 4bab2dda632..0e086c9c413 100644 --- a/homeassistant/components/iaqualink/translations/sv.json +++ b/homeassistant/components/iaqualink/translations/sv.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Du kan bara konfigurera en enda iAqualink-anslutning." - }, - "error": { - "connection_failure": "Det g\u00e5r inte att ansluta till iAqualink. Kontrollera ditt anv\u00e4ndarnamn och l\u00f6senord." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/iaqualink/translations/zh-Hans.json b/homeassistant/components/iaqualink/translations/zh-Hans.json index d13c8a6b46a..e5f2968d85b 100644 --- a/homeassistant/components/iaqualink/translations/zh-Hans.json +++ b/homeassistant/components/iaqualink/translations/zh-Hans.json @@ -1,10 +1,13 @@ { "config": { "error": { - "connection_failure": "\u65e0\u6cd5\u8fde\u63a5\u5230iAqualink\u3002\u68c0\u67e5\u60a8\u7684\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002" + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" }, "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/iaqualink/translations/zh-Hant.json b/homeassistant/components/iaqualink/translations/zh-Hant.json index 7a8eddeb129..3923f95f71b 100644 --- a/homeassistant/components/iaqualink/translations/zh-Hant.json +++ b/homeassistant/components/iaqualink/translations/zh-Hant.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44 iAqualink \u9023\u7dda\u3002", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_failure": "\u7121\u6cd5\u9023\u7dda\u81f3 iAqualink\uff0c\u8acb\u78ba\u8a8d\u60a8\u7684\u4f7f\u7528\u8005\u540d\u7a31\u8207\u5bc6\u78bc\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "user": { diff --git a/homeassistant/components/icloud/translations/ca.json b/homeassistant/components/icloud/translations/ca.json index c6f634c7e6f..a0d74aba98c 100644 --- a/homeassistant/components/icloud/translations/ca.json +++ b/homeassistant/components/icloud/translations/ca.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "login": "Error d'inici de sessi\u00f3: comprova el correu electr\u00f2nic i la contrasenya", "send_verification_code": "No s'ha pogut enviar el codi de verificaci\u00f3", "validate_verification_code": "No s'ha pogut verificar el codi de verificaci\u00f3, tria un dispositiu de confian\u00e7a i torna a iniciar el proc\u00e9s" }, diff --git a/homeassistant/components/icloud/translations/cs.json b/homeassistant/components/icloud/translations/cs.json index d3c012e2359..f06cae4019d 100644 --- a/homeassistant/components/icloud/translations/cs.json +++ b/homeassistant/components/icloud/translations/cs.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "login": "Chyba p\u0159ihl\u00e1\u0161en\u00ed: zkontrolujte pros\u00edm sv\u016fj e-mail a heslo", "send_verification_code": "Odesl\u00e1n\u00ed ov\u011b\u0159ovac\u00edho k\u00f3du se nezda\u0159ilo", "validate_verification_code": "Nepoda\u0159ilo se ov\u011b\u0159it v\u00e1\u0161 ov\u011b\u0159ovac\u00ed k\u00f3d, vyberte d\u016fv\u011bryhodn\u00e9 za\u0159\u00edzen\u00ed a spus\u0165te ov\u011b\u0159en\u00ed znovu" }, diff --git a/homeassistant/components/icloud/translations/da.json b/homeassistant/components/icloud/translations/da.json index a06950ca30d..57129a72984 100644 --- a/homeassistant/components/icloud/translations/da.json +++ b/homeassistant/components/icloud/translations/da.json @@ -5,7 +5,6 @@ "no_device": "Ingen af dine enheder har aktiveret \"Find min iPhone\"" }, "error": { - "login": "Loginfejl: Kontroller din email og adgangskode", "send_verification_code": "Bekr\u00e6ftelseskoden kunne ikke sendes", "validate_verification_code": "Bekr\u00e6ftelseskoden kunne ikke bekr\u00e6ftes, V\u00e6lg en betroet enhed, og start bekr\u00e6ftelsen igen" }, diff --git a/homeassistant/components/icloud/translations/de.json b/homeassistant/components/icloud/translations/de.json index ea2096c3c00..e7441792d91 100644 --- a/homeassistant/components/icloud/translations/de.json +++ b/homeassistant/components/icloud/translations/de.json @@ -5,7 +5,6 @@ "no_device": "Auf keinem Ihrer Ger\u00e4te ist \"Find my iPhone\" aktiviert" }, "error": { - "login": "Login-Fehler: Bitte \u00fcberpr\u00fcfe deine E-Mail & Passwort", "send_verification_code": "Fehler beim Senden des Best\u00e4tigungscodes", "validate_verification_code": "Verifizierung des Verifizierungscodes fehlgeschlagen. W\u00e4hle ein vertrauensw\u00fcrdiges Ger\u00e4t aus und starte die Verifizierung erneut" }, diff --git a/homeassistant/components/icloud/translations/en.json b/homeassistant/components/icloud/translations/en.json index 0421cfe3902..3097302ded2 100644 --- a/homeassistant/components/icloud/translations/en.json +++ b/homeassistant/components/icloud/translations/en.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "Invalid authentication", - "login": "Login error: please check your email & password", "send_verification_code": "Failed to send verification code", "validate_verification_code": "Failed to verify your verification code, choose a trust device and start the verification again" }, diff --git a/homeassistant/components/icloud/translations/es-419.json b/homeassistant/components/icloud/translations/es-419.json index 250235eea62..d422135c7b4 100644 --- a/homeassistant/components/icloud/translations/es-419.json +++ b/homeassistant/components/icloud/translations/es-419.json @@ -5,7 +5,6 @@ "no_device": "Ninguno de sus dispositivos tiene activado \"Buscar mi iPhone\"" }, "error": { - "login": "Error de inicio de sesi\u00f3n: compruebe su correo electr\u00f3nico y contrase\u00f1a", "send_verification_code": "Error al enviar el c\u00f3digo de verificaci\u00f3n", "validate_verification_code": "No se pudo verificar su c\u00f3digo de verificaci\u00f3n, elija un dispositivo de confianza y comience la verificaci\u00f3n nuevamente" }, diff --git a/homeassistant/components/icloud/translations/es.json b/homeassistant/components/icloud/translations/es.json index dbbdaae376e..593f2753d99 100644 --- a/homeassistant/components/icloud/translations/es.json +++ b/homeassistant/components/icloud/translations/es.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "login": "Error de inicio de sesi\u00f3n: comprueba tu direcci\u00f3n de correo electr\u00f3nico y contrase\u00f1a", "send_verification_code": "Error al enviar el c\u00f3digo de verificaci\u00f3n", "validate_verification_code": "No se pudo verificar el c\u00f3digo de verificaci\u00f3n, elegir un dispositivo de confianza e iniciar la verificaci\u00f3n de nuevo" }, diff --git a/homeassistant/components/icloud/translations/et.json b/homeassistant/components/icloud/translations/et.json index 41bc069f6a4..29b24aabf5a 100644 --- a/homeassistant/components/icloud/translations/et.json +++ b/homeassistant/components/icloud/translations/et.json @@ -2,10 +2,13 @@ "config": { "abort": { "already_configured": "Konto on juba seadistatud", + "no_device": "\u00dchelgi seadmetest ei ole \"Leia minu iPhone\" aktiveeritud", "reauth_successful": "Taastuvastamine \u00f5nnestus" }, "error": { - "invalid_auth": "Tuvastamise viga" + "invalid_auth": "Tuvastamise viga", + "send_verification_code": "Kinnituskoodi saatmine nurjus", + "validate_verification_code": "Tuvastuskoodi kinnitamine nurjus. Vali usaldusseade ja proovi uuesti" }, "step": { "reauth": { @@ -15,11 +18,28 @@ "description": "Varem sisestatud salas\u00f5na kasutajale {username} ei t\u00f6\u00f6ta enam. Selle sidumise kasutamise j\u00e4tkamiseks v\u00e4rskendage oma salas\u00f5na.", "title": "iCloudi tuvastusandmed" }, + "trusted_device": { + "data": { + "trusted_device": "Usaldusv\u00e4\u00e4rne seade" + }, + "description": "Vali oma usaldatav seade", + "title": "iCloudi usaldatav seade" + }, "user": { "data": { "password": "Salas\u00f5na", - "username": "E-post" - } + "username": "E-post", + "with_family": "Perega" + }, + "description": "Sisesta oma mandaat.", + "title": "iCloudi tuvastusandmed" + }, + "verification_code": { + "data": { + "verification_code": "Kinnituskood" + }, + "description": "Sisesta \u00e4sja iCloudilt saadud kinnituskood", + "title": "iCloudi kinnituskood" } } } diff --git a/homeassistant/components/icloud/translations/fr.json b/homeassistant/components/icloud/translations/fr.json index 000696d5b7d..77fc925851e 100644 --- a/homeassistant/components/icloud/translations/fr.json +++ b/homeassistant/components/icloud/translations/fr.json @@ -2,15 +2,22 @@ "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", - "login": "Erreur de connexion: veuillez v\u00e9rifier votre e-mail et votre mot de passe", "send_verification_code": "\u00c9chec de l'envoi du code de v\u00e9rification", "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/icloud/translations/hu.json b/homeassistant/components/icloud/translations/hu.json index 4dcf547619c..e2664659d05 100644 --- a/homeassistant/components/icloud/translations/hu.json +++ b/homeassistant/components/icloud/translations/hu.json @@ -1,7 +1,6 @@ { "config": { "error": { - "login": "Bejelentkez\u00e9si hiba: k\u00e9rj\u00fck, ellen\u0151rizze e-mail c\u00edm\u00e9t \u00e9s jelszav\u00e1t", "send_verification_code": "Nem siker\u00fclt elk\u00fcldeni az ellen\u0151rz\u0151 k\u00f3dot", "validate_verification_code": "Nem siker\u00fclt ellen\u0151rizni az ellen\u0151rz\u0151 k\u00f3dot, ki kell v\u00e1lasztania egy megb\u00edzhat\u00f3s\u00e1gi eszk\u00f6zt, \u00e9s \u00fajra kell ind\u00edtania az ellen\u0151rz\u00e9st" }, diff --git a/homeassistant/components/icloud/translations/it.json b/homeassistant/components/icloud/translations/it.json index 98d3ca2f780..4fde8b33526 100644 --- a/homeassistant/components/icloud/translations/it.json +++ b/homeassistant/components/icloud/translations/it.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "Autenticazione non valida", - "login": "Errore di accesso: si prega di controllare la tua e-mail e la password", "send_verification_code": "Impossibile inviare il codice di verifica", "validate_verification_code": "Impossibile verificare il codice di verifica, scegliere un dispositivo attendibile e riavviare la verifica" }, @@ -17,7 +16,7 @@ "password": "Password" }, "description": "La password inserita in precedenza per {username} non funziona pi\u00f9. Aggiorna la tua password per continuare a utilizzare questa integrazione.", - "title": "Credenziali iCloud" + "title": "Reautenticare l'integrazione" }, "trusted_device": { "data": { diff --git a/homeassistant/components/icloud/translations/ko.json b/homeassistant/components/icloud/translations/ko.json index a39940d42ed..045042362b7 100644 --- a/homeassistant/components/icloud/translations/ko.json +++ b/homeassistant/components/icloud/translations/ko.json @@ -5,7 +5,6 @@ "no_device": "\"\ub098\uc758 iPhone \ucc3e\uae30\"\uac00 \ud65c\uc131\ud654\ub41c \uae30\uae30\uac00 \uc5c6\uc2b5\ub2c8\ub2e4" }, "error": { - "login": "\ub85c\uadf8\uc778 \uc624\ub958: \uc774\uba54\uc77c \ubc0f \ube44\ubc00\ubc88\ud638\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694", "send_verification_code": "\uc778\uc99d \ucf54\ub4dc\ub97c \ubcf4\ub0b4\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4", "validate_verification_code": "\uc778\uc99d \ucf54\ub4dc\ub97c \ud655\uc778\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \uc2e0\ub8b0\ud560 \uc218 \uc788\ub294 \uae30\uae30\ub97c \uc120\ud0dd\ud558\uace0 \uc778\uc99d\uc744 \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694" }, diff --git a/homeassistant/components/icloud/translations/lb.json b/homeassistant/components/icloud/translations/lb.json index f47ffdbb64b..6f0caa00528 100644 --- a/homeassistant/components/icloud/translations/lb.json +++ b/homeassistant/components/icloud/translations/lb.json @@ -2,15 +2,22 @@ "config": { "abort": { "already_configured": "Kont ass scho konfigur\u00e9iert", - "no_device": "Kee vun dengen Apparater huet \"Find my iPhone\" aktiv\u00e9iert" + "no_device": "Kee vun dengen Apparater huet \"Find my iPhone\" aktiv\u00e9iert", + "reauth_successful": "Re-authentifikatioun war erfollegr\u00e4ich" }, "error": { "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "login": "Feeler beim Login: iwwerpr\u00e9ift \u00e4r E-Mail & Passwuert", "send_verification_code": "Feeler beim sch\u00e9cken vum Verifikatiouns Code", "validate_verification_code": "Feeler beim iwwerpr\u00e9iwe vum Verifikatiouns Code, wielt ee vertrauten Apparat aus a start d'Iwwerpr\u00e9iwung nei" }, "step": { + "reauth": { + "data": { + "password": "Passwuert" + }, + "description": "D\u00e4in Passwuert fir {username} funktionn\u00e9iert net m\u00e9i. Aktualis\u00e9ier d\u00e4in Passwuert fir d\u00ebs Integratioun weider ze benotzen.", + "title": "Integratioun re-authentifiz\u00e9ieren" + }, "trusted_device": { "data": { "trusted_device": "Vertrauten Apparat" diff --git a/homeassistant/components/icloud/translations/nl.json b/homeassistant/components/icloud/translations/nl.json index 1088b7bb16e..537d310b0a7 100644 --- a/homeassistant/components/icloud/translations/nl.json +++ b/homeassistant/components/icloud/translations/nl.json @@ -5,11 +5,16 @@ "no_device": "Op geen van uw apparaten is \"Find my iPhone\" geactiveerd" }, "error": { - "login": "Aanmeldingsfout: controleer uw e-mailadres en wachtwoord", "send_verification_code": "Kan verificatiecode niet verzenden", "validate_verification_code": "Kan uw verificatiecode niet verifi\u00ebren, kies een vertrouwensapparaat en start de verificatie opnieuw" }, "step": { + "reauth": { + "data": { + "password": "Wachtwoord" + }, + "description": "Uw eerder ingevoerde wachtwoord voor {username} werkt niet meer. Update uw wachtwoord om deze integratie te blijven gebruiken." + }, "trusted_device": { "data": { "trusted_device": "Vertrouwd apparaat" diff --git a/homeassistant/components/icloud/translations/no.json b/homeassistant/components/icloud/translations/no.json index b1024920d65..2f9571b68fa 100644 --- a/homeassistant/components/icloud/translations/no.json +++ b/homeassistant/components/icloud/translations/no.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "Ugyldig godkjenning", - "login": "Innloggingsfeil: vennligst sjekk e-postadressen og passordet ditt", "send_verification_code": "Kunne ikke sende bekreftelseskode", "validate_verification_code": "Kunne ikke bekrefte bekreftelseskoden din, velg en tillitsenhet og start bekreftelsen p\u00e5 nytt" }, diff --git a/homeassistant/components/icloud/translations/pl.json b/homeassistant/components/icloud/translations/pl.json index 5ac18305140..4ac02d1f3f0 100644 --- a/homeassistant/components/icloud/translations/pl.json +++ b/homeassistant/components/icloud/translations/pl.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "Niepoprawne uwierzytelnienie", - "login": "B\u0142\u0105d logowania: sprawd\u017a adres e-mail i has\u0142o", "send_verification_code": "Nie uda\u0142o si\u0119 wys\u0142a\u0107 kodu weryfikacyjnego", "validate_verification_code": "Nie uda\u0142o si\u0119 zweryfikowa\u0107 kodu weryfikacyjnego, wybierz urz\u0105dzenie zaufane i ponownie rozpocznij weryfikacj\u0119" }, diff --git a/homeassistant/components/icloud/translations/pt-BR.json b/homeassistant/components/icloud/translations/pt-BR.json index 219930a94fd..7005c83bf69 100644 --- a/homeassistant/components/icloud/translations/pt-BR.json +++ b/homeassistant/components/icloud/translations/pt-BR.json @@ -4,7 +4,6 @@ "already_configured": "Conta j\u00e1 configurada" }, "error": { - "login": "Erro de login: verifique seu e-mail e senha", "send_verification_code": "Falha ao enviar c\u00f3digo de verifica\u00e7\u00e3o", "validate_verification_code": "Falha ao verificar seu c\u00f3digo de verifica\u00e7\u00e3o, escolha um dispositivo confi\u00e1vel e inicie a verifica\u00e7\u00e3o novamente" }, diff --git a/homeassistant/components/icloud/translations/ru.json b/homeassistant/components/icloud/translations/ru.json index 5270ffe531b..d977899d902 100644 --- a/homeassistant/components/icloud/translations/ru.json +++ b/homeassistant/components/icloud/translations/ru.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", - "login": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u0445\u043e\u0434\u0430: \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b \u0438 \u043f\u0430\u0440\u043e\u043b\u044c.", "send_verification_code": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u0434 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f.", "validate_verification_code": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c \u043a\u043e\u0434 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u043e\u0432\u0435\u0440\u0435\u043d\u043d\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0438 \u043d\u0430\u0447\u043d\u0438\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0441\u043d\u043e\u0432\u0430." }, diff --git a/homeassistant/components/icloud/translations/sl.json b/homeassistant/components/icloud/translations/sl.json index 9e259bb0516..19257274e05 100644 --- a/homeassistant/components/icloud/translations/sl.json +++ b/homeassistant/components/icloud/translations/sl.json @@ -5,7 +5,6 @@ "no_device": "V nobeni od va\u0161ih naprav ni aktiviran \u00bbFind my iPhone\u00ab" }, "error": { - "login": "Napaka pri prijavi: preverite svoj e-po\u0161tni naslov in geslo", "send_verification_code": "Kode za preverjanje ni bilo mogo\u010de poslati", "validate_verification_code": "Kode za preverjanje ni bilo mogo\u010de preveriti, izberi napravo za zaupanje in znova za\u017eeni preverjanje" }, diff --git a/homeassistant/components/icloud/translations/sv.json b/homeassistant/components/icloud/translations/sv.json index 31dbf29c89d..6caf02f56c5 100644 --- a/homeassistant/components/icloud/translations/sv.json +++ b/homeassistant/components/icloud/translations/sv.json @@ -4,7 +4,6 @@ "already_configured": "Kontot har redan konfigurerats" }, "error": { - "login": "Inloggningsfel: var god att kontrollera din e-postadress och l\u00f6senord", "send_verification_code": "Det gick inte att skicka verifieringskod", "validate_verification_code": "Det gick inte att verifiera verifieringskoden, v\u00e4lj en betrodd enhet och starta verifieringen igen" }, diff --git a/homeassistant/components/icloud/translations/zh-Hans.json b/homeassistant/components/icloud/translations/zh-Hans.json index 82927dc54b5..96b16faec97 100644 --- a/homeassistant/components/icloud/translations/zh-Hans.json +++ b/homeassistant/components/icloud/translations/zh-Hans.json @@ -4,7 +4,6 @@ "already_configured": "\u8d26\u6237\u5df2\u914d\u7f6e\u5b8c\u6210" }, "error": { - "login": "\u767b\u5f55\u51fa\u9519\uff1a\u8bf7\u68c0\u67e5\u60a8\u7684\u7535\u5b50\u90ae\u7bb1\u548c\u5bc6\u7801", "send_verification_code": "\u65e0\u6cd5\u53d1\u9001\u9a8c\u8bc1\u7801", "validate_verification_code": "\u65e0\u6cd5\u9a8c\u8bc1\u9a8c\u8bc1\u7801\uff0c\u8bf7\u9009\u62e9\u53d7\u4fe1\u4efb\u7684\u8bbe\u5907\u5e76\u91cd\u65b0\u5f00\u59cb\u9a8c\u8bc1" }, diff --git a/homeassistant/components/icloud/translations/zh-Hant.json b/homeassistant/components/icloud/translations/zh-Hant.json index a48f0a74e85..3a6f1b64fa9 100644 --- a/homeassistant/components/icloud/translations/zh-Hant.json +++ b/homeassistant/components/icloud/translations/zh-Hant.json @@ -7,7 +7,6 @@ }, "error": { "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "login": "\u767b\u5165\u932f\u8aa4\uff1a\u8acb\u78ba\u8a8d\u96fb\u5b50\u90f5\u4ef6\u8207\u5bc6\u78bc", "send_verification_code": "\u50b3\u9001\u9a57\u8b49\u78bc\u5931\u6557", "validate_verification_code": "\u7121\u6cd5\u9a57\u8b49\u8f38\u5165\u9a57\u8b49\u78bc\uff0c\u9078\u64c7\u4e00\u90e8\u4fe1\u4efb\u8a2d\u5099\u3001\u7136\u5f8c\u91cd\u65b0\u57f7\u884c\u9a57\u8b49\u3002" }, diff --git a/homeassistant/components/ifttt/strings.json b/homeassistant/components/ifttt/strings.json index 9002cf30756..d93879f6327 100644 --- a/homeassistant/components/ifttt/strings.json +++ b/homeassistant/components/ifttt/strings.json @@ -8,7 +8,7 @@ }, "abort": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive IFTTT messages." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send events to Home Assistant, you will need to use the \"Make a web request\" action from the [IFTTT Webhook applet]({applet_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data." diff --git a/homeassistant/components/ifttt/translations/bg.json b/homeassistant/components/ifttt/translations/bg.json index 674757b92b9..98f24af2997 100644 --- a/homeassistant/components/ifttt/translations/bg.json +++ b/homeassistant/components/ifttt/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 IFTTT.", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u0441\u044a\u0431\u0438\u0442\u0438\u044f \u0434\u043e Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \"Make a web request\" \u043e\u0442 [IFTTT Webhook \u0430\u043f\u043b\u0435\u0442]({applet_url}). \n\n\u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: \n\n - URL: `{webhook_url}` \n - Method: POST \n - Content Type: application/json\n\n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u0442\u043e\u0432\u0430 \u043a\u0430\u043a \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438\u0442\u0435 \u0437\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0430 \u0432\u0445\u043e\u0434\u044f\u0449\u0438 \u0434\u0430\u043d\u043d\u0438." }, diff --git a/homeassistant/components/ifttt/translations/ca.json b/homeassistant/components/ifttt/translations/ca.json index 8706b5655dc..0c8bb89ba02 100644 --- a/homeassistant/components/ifttt/translations/ca.json +++ b/homeassistant/components/ifttt/translations/ca.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de IFTTT.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar esdeveniments a Home Assistant, necessitar\u00e0s utilitzar l'acci\u00f3 \"Make a web resquest\" de [IFTTT Webhook applet]({applet_url}). \n\nCompleta la seg\u00fcent informaci\u00f3: \n\n- URL: `{webhook_url}` \n- Method: POST \n- Content Type: application/json \n\nConsulta la [documentaci\u00f3]({docs_url}) sobre com configurar les automatitzacions per gestionar dades entrants." diff --git a/homeassistant/components/ifttt/translations/cs.json b/homeassistant/components/ifttt/translations/cs.json index 7ce666724e8..04a35012175 100644 --- a/homeassistant/components/ifttt/translations/cs.json +++ b/homeassistant/components/ifttt/translations/cs.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "not_internet_accessible": "V\u00e1\u0161 Home Asistent mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy od IFTTT.", - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "create_entry": { - "default": "Chcete-li odeslat ud\u00e1losti do aplikace Home Assistant, budete muset pou\u017e\u00edt akci \"Vytvo\u0159it webovou \u017e\u00e1dost\" z [IFTTT Webhook appletu]({applet_url}). \n\n Vypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: ` {webhook_url} ' \n - Metoda: POST \n - Typ obsahu: aplikace/json \n\n Viz [dokumentace]({docs_url}), jak konfigurovat automatizace pro zpracov\u00e1n\u00ed p\u0159\u00edchoz\u00edch dat." + "default": "Chcete-li odeslat ud\u00e1losti do Home Assistant, budete muset pou\u017e\u00edt akci \"Vytvo\u0159it webovou \u017e\u00e1dost\" z [IFTTT Webhook appletu]({applet_url}). \n\nVypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: ` {webhook_url} ' \n - Metoda: POST \n - Typ obsahu: aplikace/json \n\nViz [dokumentace]({docs_url}), jak konfigurovat automatizace pro zpracov\u00e1n\u00ed p\u0159\u00edchoz\u00edch dat." }, "step": { "user": { diff --git a/homeassistant/components/ifttt/translations/da.json b/homeassistant/components/ifttt/translations/da.json index 109be40acca..658498bf156 100644 --- a/homeassistant/components/ifttt/translations/da.json +++ b/homeassistant/components/ifttt/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage IFTTT-meddelelser", - "one_instance_allowed": "Kun en enkelt instans er n\u00f8dvendig." - }, "create_entry": { "default": "For at sende h\u00e6ndelser til Home Assistant skal du bruge handlingen \"Foretag en web-foresp\u00f8rgsel\" fra [IFTTT Webhook-applet] ({applet_url}).\n\n Udfyld f\u00f8lgende oplysninger: \n\n - Webadresse: `{webhook_url}`\n - Metode: POST\n - Indholdstype: application/json\n\nSe [dokumentationen] ({docs_url}) om hvordan du konfigurerer automatiseringer til at h\u00e5ndtere indg\u00e5ende data." }, diff --git a/homeassistant/components/ifttt/translations/de.json b/homeassistant/components/ifttt/translations/de.json index 1633f091a6e..c96928afa18 100644 --- a/homeassistant/components/ifttt/translations/de.json +++ b/homeassistant/components/ifttt/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Auf Ihre Home Assistant-Instanz muss vom Internet aus zugegriffen werden k\u00f6nnen, um IFTTT-Nachrichten zu empfangen.", - "one_instance_allowed": "Nur eine einzige Instanz ist notwendig." - }, "create_entry": { "default": "Um Ereignisse an Home Assistant zu senden, musst du die Aktion \"Eine Webanforderung erstellen\" aus dem [IFTTT Webhook Applet]({applet_url}) ausw\u00e4hlen.\n\nF\u00fclle folgende Informationen aus: \n- URL: `{webhook_url}`\n- Methode: POST\n- Inhaltstyp: application/json\n\nIn der Dokumentation ({docs_url}) findest du Informationen zur Konfiguration der Automation eingehender Daten." }, diff --git a/homeassistant/components/ifttt/translations/en.json b/homeassistant/components/ifttt/translations/en.json index 006680f9402..68999eba2b7 100644 --- a/homeassistant/components/ifttt/translations/en.json +++ b/homeassistant/components/ifttt/translations/en.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive IFTTT messages.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send events to Home Assistant, you will need to use the \"Make a web request\" action from the [IFTTT Webhook applet]({applet_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data." diff --git a/homeassistant/components/ifttt/translations/es-419.json b/homeassistant/components/ifttt/translations/es-419.json index 4b648d64279..835bcc183ab 100644 --- a/homeassistant/components/ifttt/translations/es-419.json +++ b/homeassistant/components/ifttt/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes IFTTT.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar eventos a Home Assistant, deber\u00e1 usar la acci\u00f3n \"Realizar una solicitud web\" del [applet de IFTTT Webhook] ( {applet_url} ). \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n - Tipo de contenido: aplicaci\u00f3n / json \n\n Consulte [la documentaci\u00f3n] ( {docs_url} ) sobre c\u00f3mo configurar las automatizaciones para manejar los datos entrantes." }, diff --git a/homeassistant/components/ifttt/translations/es.json b/homeassistant/components/ifttt/translations/es.json index acc74410df5..b29862c38e2 100644 --- a/homeassistant/components/ifttt/translations/es.json +++ b/homeassistant/components/ifttt/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Tu instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes IFTTT.", - "one_instance_allowed": "S\u00f3lo se necesita una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar eventos a Home Assistant debes usar la acci\u00f3n \"Make a web request\" del [applet IFTTT Webhook]({applet_url}).\n\nCompleta la siguiente informaci\u00f3n: \n\n- URL: `{webhook_url}`\n- M\u00e9todo: POST\n- Tipo de contenido: application/json\n\nConsulta [la documentaci\u00f3n]({docs_url}) sobre c\u00f3mo configurar las automatizaciones para manejar los datos entrantes." diff --git a/homeassistant/components/ifttt/translations/et.json b/homeassistant/components/ifttt/translations/et.json index 1ab718c48f1..cecd2aea7e7 100644 --- a/homeassistant/components/ifttt/translations/et.json +++ b/homeassistant/components/ifttt/translations/et.json @@ -1,14 +1,16 @@ { "config": { "abort": { - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." }, "create_entry": { "default": "S\u00fcndmuste saatmiseks Home Assistantile peate kasutama toimingut \"Make a web request\" [IFTTT Webhooki apletilt] ({applet_url}).\n\nSisestage j\u00e4rgmine teave:\n\n- URL: {webhook_url}.\n- Method: POST\n- Content Type: application/json\n\nVaadake [dokumentatsiooni]({docs_url}) kuidas seadistada sissetulevate andmete t\u00f6\u00f6tlemiseks automatiseerimisi." }, "step": { "user": { - "description": "Kas soovid kindlasti IFTTT seadistada?" + "description": "Kas soovid kindlasti IFTTT seadistada?", + "title": "Seadista IFTTT Webhook Applet" } } } diff --git a/homeassistant/components/ifttt/translations/fi.json b/homeassistant/components/ifttt/translations/fi.json index b01accbb371..e9f6e13cc75 100644 --- a/homeassistant/components/ifttt/translations/fi.json +++ b/homeassistant/components/ifttt/translations/fi.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Vain yksi instanssi on tarpeen." - }, "step": { "user": { "description": "Haluatko varmasti m\u00e4\u00e4ritt\u00e4\u00e4 IFTTT:n?" diff --git a/homeassistant/components/ifttt/translations/fr.json b/homeassistant/components/ifttt/translations/fr.json index b8782f1452e..fe72a0df172 100644 --- a/homeassistant/components/ifttt/translations/fr.json +++ b/homeassistant/components/ifttt/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance Home Assistant doit \u00eatre accessible \u00e0 partir d'Internet pour recevoir les messages IFTTT.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez utiliser l'action \"Effectuer une demande Web\" \u00e0 partir de [l'applet IFTTT Webhook]({applet_url}). \n\n Remplissez les informations suivantes: \n\n - URL: ` {webhook_url} ` \n - M\u00e9thode: POST \n - Type de contenu: application / json \n\n Voir [la documentation]({docs_url}) pour savoir comment configurer les automatisations pour g\u00e9rer les donn\u00e9es entrantes." diff --git a/homeassistant/components/ifttt/translations/hu.json b/homeassistant/components/ifttt/translations/hu.json index 560c2c84064..a64800ab7db 100644 --- a/homeassistant/components/ifttt/translations/hu.json +++ b/homeassistant/components/ifttt/translations/hu.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A Home Assistant-nek el\u00e9rhet\u0151nek kell lennie az internetr\u0151l az IFTTT \u00fczenetek fogad\u00e1s\u00e1hoz.", - "one_instance_allowed": "Csak egyetlen konfigur\u00e1ci\u00f3 sz\u00fcks\u00e9ges." - }, "step": { "user": { "description": "Biztosan be szeretn\u00e9d \u00e1ll\u00edtani az IFTTT-t?", diff --git a/homeassistant/components/ifttt/translations/it.json b/homeassistant/components/ifttt/translations/it.json index 101e91e7f98..6b1d1dd4c53 100644 --- a/homeassistant/components/ifttt/translations/it.json +++ b/homeassistant/components/ifttt/translations/it.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi IFTTT.", - "one_instance_allowed": "\u00c8 necessaria una sola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare eventi a Home Assistant, \u00e8 necessario utilizzare l'azione \"Crea una richiesta web\" dall'[applet IFTTT Webhook]({applet_url}). \n\n Compilare le seguenti informazioni: \n\n - URL: `{webhook_url}` \n - Metodo: POST \n - Tipo di contenuto: application/json \n\nVedere [la documentazione]({docs_url}) su come configurare le automazioni per gestire i dati in arrivo." diff --git a/homeassistant/components/ifttt/translations/ko.json b/homeassistant/components/ifttt/translations/ko.json index f3c0cb1062c..93daad9e182 100644 --- a/homeassistant/components/ifttt/translations/ko.json +++ b/homeassistant/components/ifttt/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "IFTTT \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\uae30 \uc704\ud574\uc11c\ub294 [IFTTT \uc6f9 \ud6c5 \uc560\ud50c\ub9bf]({applet_url}) \uc5d0\uc11c \"Make a web request\" \ub97c \uc0ac\uc6a9\ud574\uc57c \ud569\ub2c8\ub2e4. \n\n\ub2e4\uc74c\uc758 \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694.\n\n - URL: `{webhook_url}` \n - Method: POST \n - Content Type: application/json \n\nHome Assistant \ub85c \ub4e4\uc5b4\uc624\ub294 \ub370\uc774\ud130\ub97c \ucc98\ub9ac\ud558\uae30 \uc704\ud55c \uc790\ub3d9\ud654\ub97c \uad6c\uc131\ud558\ub294 \ubc29\ubc95\uc740 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/ifttt/translations/lb.json b/homeassistant/components/ifttt/translations/lb.json index 7ff324b45a2..56b3ba9ad81 100644 --- a/homeassistant/components/ifttt/translations/lb.json +++ b/homeassistant/components/ifttt/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir IFTTT Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { diff --git a/homeassistant/components/ifttt/translations/nl.json b/homeassistant/components/ifttt/translations/nl.json index 8415509b941..e7da47dd658 100644 --- a/homeassistant/components/ifttt/translations/nl.json +++ b/homeassistant/components/ifttt/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Uw Home Assistant-instantie moet via internet toegankelijk zijn om IFTTT-berichten te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/ifttt/translations/no.json b/homeassistant/components/ifttt/translations/no.json index af3f14ac087..98fec09e773 100644 --- a/homeassistant/components/ifttt/translations/no.json +++ b/homeassistant/components/ifttt/translations/no.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "not_internet_accessible": "Din Home Assistant enhet m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta IFTTT-meldinger.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { - "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du bruke \"Make a web request\" handlingen fra [IFTTT Webhook applet]({applet_url}).\n\nFyll ut f\u00f8lgende informasjon:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSe [dokumentasjonen]({docs_url}) om hvordan du konfigurerer automatiseringer for \u00e5 h\u00e5ndtere innkommende data." + "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du bruke \"Make a web request\" handlingen fra [IFTTT Webhook applet]({applet_url}).\n\nFyll ut f\u00f8lgende informasjon:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSe [dokumentasjonen]({docs_url}) om hvordan du konfigurerer automasjoner for \u00e5 h\u00e5ndtere innkommende data." }, "step": { "user": { diff --git a/homeassistant/components/ifttt/translations/pl.json b/homeassistant/components/ifttt/translations/pl.json index 321c31142ca..7c0dfbfab66 100644 --- a/homeassistant/components/ifttt/translations/pl.json +++ b/homeassistant/components/ifttt/translations/pl.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty IFTTT", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant, musisz u\u017cy\u0107 akcji \"Make a web request\" z [apletu IFTTT Webhook]({applet_url}). \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}`\n - Metoda: POST\n - Typ zawarto\u015bci: application/json\n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}) na temat konfiguracji automatyzacji, by obs\u0142u\u017cy\u0107 przychodz\u0105ce dane." }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 IFTTT?", + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", "title": "Konfiguracja apletu Webhook IFTTT" } } diff --git a/homeassistant/components/ifttt/translations/pt-BR.json b/homeassistant/components/ifttt/translations/pt-BR.json index 18e0791b187..c78da4db0c0 100644 --- a/homeassistant/components/ifttt/translations/pt-BR.json +++ b/homeassistant/components/ifttt/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia do Home Assistant precisa estar acess\u00edvel na Internet para receber mensagens IFTTT.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, voc\u00ea precisar\u00e1 usar a a\u00e7\u00e3o \"Fazer uma solicita\u00e7\u00e3o Web\" no [applet IFTTT Webhook] ( {applet_url} ). \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n - Tipo de Conte\u00fado: application / json \n\n Veja [a documenta\u00e7\u00e3o] ( {docs_url} ) sobre como configurar automa\u00e7\u00f5es para manipular dados de entrada." }, diff --git a/homeassistant/components/ifttt/translations/pt.json b/homeassistant/components/ifttt/translations/pt.json index f32ced997d3..eaed455b71a 100644 --- a/homeassistant/components/ifttt/translations/pt.json +++ b/homeassistant/components/ifttt/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A sua inst\u00e2ncia Home Assistant precisa de ser acess\u00edvel a partir da internet para receber mensagens IFTTT.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, precisa de utilizar a a\u00e7\u00e3o \"Make a web request\" no [IFTTT Webhook applet]({applet_url}).\n\nPreencha com a seguinte informa\u00e7\u00e3o:\n\n- URL: `{webhook_url}`\n- Method: POST \n- Content Type: application/json \n\nConsulte [a documenta\u00e7\u00e3o]({docs_url}) sobre como configurar automa\u00e7\u00f5es para lidar com dados de entrada." }, diff --git a/homeassistant/components/ifttt/translations/ro.json b/homeassistant/components/ifttt/translations/ro.json index 36e75204e92..8a138488894 100644 --- a/homeassistant/components/ifttt/translations/ro.json +++ b/homeassistant/components/ifttt/translations/ro.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Instan\u021ba Home Assistant trebuie s\u0103 fie accesibil\u0103 de pe internet pentru a primi mesaje IFTTT.", - "one_instance_allowed": "Este necesar\u0103 o singur\u0103 instan\u021b\u0103." - }, "step": { "user": { "description": "Sigur dori\u021bi s\u0103 configura\u021bi IFTTT?" diff --git a/homeassistant/components/ifttt/translations/ru.json b/homeassistant/components/ifttt/translations/ru.json index 4f3efe9e267..2e7f83c6f61 100644 --- a/homeassistant/components/ifttt/translations/ru.json +++ b/homeassistant/components/ifttt/translations/ru.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 IFTTT.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \"Make a web request\" \u0438\u0437 [IFTTT Webhook applet]({applet_url}).\n\n\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\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 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0439 \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445." diff --git a/homeassistant/components/ifttt/translations/sl.json b/homeassistant/components/ifttt/translations/sl.json index 83a5a4567de..212c8f384e5 100644 --- a/homeassistant/components/ifttt/translations/sl.json +++ b/homeassistant/components/ifttt/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Va\u0161 Home Assistant mora biti dostopek prek interneta, da boste lahko prejemali IFTTT sporo\u010dila.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "\u010ce \u017eelite poslati dogodke Home Assistant-u, boste morali uporabiti akcijo \u00bbNaredi spletno zahtevo\u00ab iz orodja [IFTTT Webhook applet] ( {applet_url} ). \n\n Izpolnite naslednje podatke: \n\n - URL: ` {webhook_url} ` \n - Metoda: POST \n - Vrsta vsebine: application/json \n\n Poglejte si [dokumentacijo] ( {docs_url} ) o tem, kako konfigurirati avtomatizacijo za obdelavo dohodnih podatkov." }, diff --git a/homeassistant/components/ifttt/translations/sv.json b/homeassistant/components/ifttt/translations/sv.json index 6de7b1f4f27..57837a63b15 100644 --- a/homeassistant/components/ifttt/translations/sv.json +++ b/homeassistant/components/ifttt/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant instans m\u00e5ste vara tillg\u00e4nglig fr\u00e5n internet f\u00f6r att ta emot IFTTT meddelanden.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du anv\u00e4nda \u00e5tg\u00e4rden \"G\u00f6r en webbf\u00f6rfr\u00e5gan\" fr\u00e5n [IFTTT Webhook applet] ( {applet_url} ).\n\n Fyll i f\u00f6ljande information:\n \n - URL: ` {webhook_url} `\n - Metod: POST\n - Inneh\u00e5llstyp: application / json\n\n Se [dokumentationen] ( {docs_url} ) om hur du konfigurerar automatiseringar f\u00f6r att hantera inkommande data." }, diff --git a/homeassistant/components/ifttt/translations/zh-Hans.json b/homeassistant/components/ifttt/translations/zh-Hans.json index e58bd80af7c..c9e8bfd6044 100644 --- a/homeassistant/components/ifttt/translations/zh-Hans.json +++ b/homeassistant/components/ifttt/translations/zh-Hans.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u53ef\u4ece\u4e92\u8054\u7f51\u8bbf\u95ee\u4ee5\u63a5\u6536 IFTTT \u6d88\u606f\u3002", - "one_instance_allowed": "\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u662f\u5fc5\u9700\u7684\u3002" - }, "create_entry": { "default": "\u8981\u5411 Home Assistant \u53d1\u9001\u4e8b\u4ef6\uff0c\u60a8\u9700\u8981\u4f7f\u7528 [IFTTT Webhook applet]({applet_url}) \u4e2d\u7684 \"Make a web request\" \u52a8\u4f5c\u3002\n\n\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\u6709\u5173\u5982\u4f55\u914d\u7f6e\u81ea\u52a8\u5316\u4ee5\u5904\u7406\u4f20\u5165\u7684\u6570\u636e\uff0c\u8bf7\u53c2\u9605[\u6587\u6863]({docs_url})\u3002" }, diff --git a/homeassistant/components/ifttt/translations/zh-Hant.json b/homeassistant/components/ifttt/translations/zh-Hant.json index cb57097e4f2..beef1c7070e 100644 --- a/homeassistant/components/ifttt/translations/zh-Hant.json +++ b/homeassistant/components/ifttt/translations/zh-Hant.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u7269\u4ef6\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 IFTTT \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u7269\u4ef6\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u8981\u7531 [IFTTT Webhook applet]({applet_url}) \u547c\u53eb\u300c\u9032\u884c Web \u8acb\u6c42\u300d\u52d5\u4f5c\u3002\n\n\u8acb\u586b\u5beb\u4e0b\u5217\u8cc7\u8a0a\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\u95dc\u65bc\u5982\u4f55\u50b3\u5165\u8cc7\u6599\u81ea\u52d5\u5316\u8a2d\u5b9a\uff0c\u8acb\u53c3\u95b1[\u6587\u4ef6]({docs_url})\u4ee5\u9032\u884c\u4e86\u89e3\u3002" diff --git a/homeassistant/components/insteon/climate.py b/homeassistant/components/insteon/climate.py index f05cf9d2940..7d4d9543c3f 100644 --- a/homeassistant/components/insteon/climate.py +++ b/homeassistant/components/insteon/climate.py @@ -202,12 +202,12 @@ class InsteonClimateEntity(InsteonEntity, ClimateEntity): 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/insteon/translations/ca.json b/homeassistant/components/insteon/translations/ca.json index ea5300200c2..63601dd8071 100644 --- a/homeassistant/components/insteon/translations/ca.json +++ b/homeassistant/components/insteon/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Ja hi ha una connexi\u00f3 amb un m\u00f2dem Insteon configurada", "cannot_connect": "Ha fallat la connexi\u00f3", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, @@ -10,24 +9,6 @@ "select_single": "Selecciona una opci\u00f3." }, "step": { - "hub1": { - "data": { - "host": "Adre\u00e7a IP del Hub", - "port": "Port IP" - }, - "description": "Configura l'Insteon Hub versi\u00f3 1 (anterior a 2014).", - "title": "Insteon Hub versi\u00f3 1" - }, - "hub2": { - "data": { - "host": "Adre\u00e7a IP del Hub", - "password": "Contrasenya", - "port": "Port IP", - "username": "Nom d'usuari" - }, - "description": "Configura l'Insteon Hub versi\u00f3 2.", - "title": "Insteon Hub versi\u00f3 2" - }, "hubv1": { "data": { "host": "Adre\u00e7a IP", @@ -46,15 +27,6 @@ "description": "Configura l'Insteon Hub versi\u00f3 2.", "title": "Insteon Hub versi\u00f3 2" }, - "init": { - "data": { - "hubv1": "Hub versi\u00f3 1 (anterior a 2014)", - "hubv2": "Hub versi\u00f3 2", - "plm": "M\u00f2dem PowerLink (PLM)" - }, - "description": "Selecciona el tipus de m\u00f2dem Insteon.", - "title": "Insteon" - }, "plm": { "data": { "device": "Ruta del port USB del dispositiu" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "Ja hi ha una connexi\u00f3 amb un m\u00f2dem Insteon configurada", - "cannot_connect": "No es pot connectar amb el m\u00f2dem Insteon" - }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", "input_error": "Entrades inv\u00e0lides, revisa els valors.", diff --git a/homeassistant/components/insteon/translations/cs.json b/homeassistant/components/insteon/translations/cs.json index 1bd9fd60f72..18d7ff1c999 100644 --- a/homeassistant/components/insteon/translations/cs.json +++ b/homeassistant/components/insteon/translations/cs.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "P\u0159ipojen\u00ed modemu Insteon je ji\u017e nastaveno", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, @@ -10,22 +9,6 @@ "select_single": "Vyberte jednu mo\u017enost." }, "step": { - "hub1": { - "data": { - "host": "IP adresa rozbo\u010dova\u010de" - }, - "description": "Nastavte Insteon Hub verze 1 (p\u0159ed rokem 2014).", - "title": "Insteon Hub verze 1" - }, - "hub2": { - "data": { - "host": "IP adresa rozbo\u010dova\u010de", - "password": "Heslo", - "username": "U\u017eivatelsk\u00e9 jm\u00e9no" - }, - "description": "Nastavte Insteon Hub verze 2.", - "title": "Insteon Hub verze 2" - }, "hubv1": { "data": { "host": "IP adresa", @@ -44,18 +27,11 @@ "description": "Nastavte Insteon Hub verze 2.", "title": "Insteon Hub verze 2" }, - "init": { - "data": { - "hubv1": "Hub verze 1 (p\u0159ed rokem 2014)", - "hubv2": "Hub verze 2" - }, - "description": "Vyberte typ modemu Insteon.", - "title": "Insteon" - }, "plm": { "data": { "device": "Cesta k USB za\u0159\u00edzen\u00ed" - } + }, + "description": "Nastavte modem Insteon PowerLink (PLM)." }, "user": { "data": { @@ -67,11 +43,9 @@ } }, "options": { - "abort": { - "cannot_connect": "Nelze se p\u0159ipojit k modemu Insteon" - }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", + "input_error": "Neplatn\u00e9 polo\u017eky, zkontrolujte pros\u00edm sv\u00e9 hodnoty.", "select_single": "Vyberte jednu mo\u017enost." }, "step": { @@ -84,7 +58,10 @@ }, "add_x10": { "data": { - "platform": "Platforma" + "housecode": "K\u00f3d domu (a-p)", + "platform": "Platforma", + "steps": "Kroky stm\u00edva\u010de (pouze pro sv\u011btla, v\u00fdchoz\u00ed 22)", + "unitcode": "K\u00f3d jednotky (1-16)" }, "title": "Insteon" }, @@ -95,6 +72,7 @@ "port": "Port", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" }, + "description": "Zm\u011b\u0148te informace o p\u0159ipojen\u00ed rozbo\u010dova\u010de Insteon. Po proveden\u00ed t\u00e9to zm\u011bny mus\u00edte Home Assistant restartovat. T\u00edm se nezm\u011bn\u00ed nastaven\u00ed samotn\u00e9ho rozbo\u010dova\u010de. Chcete-li zm\u011bnit nastaven\u00ed rozbo\u010dova\u010de, pou\u017eijte jeho aplikaci.", "title": "Insteon" }, "init": { @@ -102,9 +80,13 @@ "add_x10": "P\u0159idejte za\u0159\u00edzen\u00ed X10.", "remove_x10": "Odeberte za\u0159\u00edzen\u00ed X10." }, + "description": "Vyberte mo\u017enost k nastaven\u00ed.", "title": "Insteon" }, "remove_override": { + "data": { + "address": "Vyberte adresu za\u0159\u00edzen\u00ed, kter\u00e9 chcete odebrat" + }, "title": "Insteon" }, "remove_x10": { diff --git a/homeassistant/components/insteon/translations/de.json b/homeassistant/components/insteon/translations/de.json index c7f2ad94313..dfa4f3f7567 100644 --- a/homeassistant/components/insteon/translations/de.json +++ b/homeassistant/components/insteon/translations/de.json @@ -1,12 +1,12 @@ { "config": { + "abort": { + "cannot_connect": "Verbindung fehlgeschlagen" + }, + "error": { + "cannot_connect": "Verbindung fehlgeschlagen" + }, "step": { - "hub2": { - "data": { - "password": "Passwort", - "username": "Benutzername" - } - }, "hubv1": { "data": { "host": "IP-Adresse", @@ -21,9 +21,6 @@ "username": "Benutzername" } }, - "init": { - "title": "Insteon" - }, "plm": { "title": "Insteon PLM" }, @@ -34,6 +31,7 @@ }, "options": { "error": { + "cannot_connect": "Verbindung fehlgeschlagen", "select_single": "W\u00e4hle eine Option aus." }, "step": { diff --git a/homeassistant/components/insteon/translations/en.json b/homeassistant/components/insteon/translations/en.json index 5b5ba8a8366..18217bb2842 100644 --- a/homeassistant/components/insteon/translations/en.json +++ b/homeassistant/components/insteon/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "An Insteon modem connection is already configured", "cannot_connect": "Failed to connect", "single_instance_allowed": "Already configured. Only a single configuration possible." }, @@ -10,24 +9,6 @@ "select_single": "Select one option." }, "step": { - "hub1": { - "data": { - "host": "Hub IP address", - "port": "IP port" - }, - "description": "Configure the Insteon Hub Version 1 (pre-2014).", - "title": "Insteon Hub Version 1" - }, - "hub2": { - "data": { - "host": "Hub IP address", - "password": "Password", - "port": "IP port", - "username": "Username" - }, - "description": "Configure the Insteon Hub Version 2.", - "title": "Insteon Hub Version 2" - }, "hubv1": { "data": { "host": "IP Address", @@ -46,15 +27,6 @@ "description": "Configure the Insteon Hub Version 2.", "title": "Insteon Hub Version 2" }, - "init": { - "data": { - "hubv1": "Hub Version 1 (Pre-2014)", - "hubv2": "Hub Version 2", - "plm": "PowerLink Modem (PLM)" - }, - "description": "Select the Insteon modem type.", - "title": "Insteon" - }, "plm": { "data": { "device": "USB Device Path" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "An Insteon modem connection is already configured", - "cannot_connect": "Unable to connect to the Insteon modem" - }, "error": { "cannot_connect": "Failed to connect", "input_error": "Invalid entries, please check your values.", diff --git a/homeassistant/components/insteon/translations/es.json b/homeassistant/components/insteon/translations/es.json index 093311b7b82..31088b3bf60 100644 --- a/homeassistant/components/insteon/translations/es.json +++ b/homeassistant/components/insteon/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Una conexi\u00f3n de m\u00f3dem Insteon ya est\u00e1 configurada", "cannot_connect": "No se puede conectar al m\u00f3dem Insteon", "single_instance_allowed": "Ya esta configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, @@ -10,24 +9,6 @@ "select_single": "Seleccione una opci\u00f3n." }, "step": { - "hub1": { - "data": { - "host": "Direcci\u00f3n IP del Hub", - "port": "Puerto IP" - }, - "description": "Configure el Insteon Hub Versi\u00f3n 1 (anterior a 2014).", - "title": "Insteon Hub Versi\u00f3n 1" - }, - "hub2": { - "data": { - "host": "Direcci\u00f3n IP del Hub", - "password": "Contrase\u00f1a", - "port": "Puerto IP", - "username": "Nombre de usuario" - }, - "description": "Configure el Insteon Hub versi\u00f3n 2.", - "title": "Insteon Hub Versi\u00f3n 2" - }, "hubv1": { "data": { "host": "Direcci\u00f3n IP", @@ -46,15 +27,6 @@ "description": "Configure el Insteon Hub versi\u00f3n 2.", "title": "Insteon Hub Versi\u00f3n 2" }, - "init": { - "data": { - "hubv1": "Hub versi\u00f3n 1 (anterior a 2014)", - "hubv2": "Hub Versi\u00f3n 2", - "plm": "M\u00f3dem PowerLink (PLM)" - }, - "description": "Seleccione el tipo de m\u00f3dem Insteon.", - "title": "Insteon" - }, "plm": { "data": { "device": "Ruta del dispositivo USB" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "Ya est\u00e1 configurada una conexi\u00f3n del m\u00f3dem Insteon", - "cannot_connect": "No se puede conectar al m\u00f3dem Insteon" - }, "error": { "cannot_connect": "No se pudo conectar", "input_error": "Entradas no v\u00e1lidas, compruebe sus valores.", diff --git a/homeassistant/components/insteon/translations/et.json b/homeassistant/components/insteon/translations/et.json index 33a6848f7e3..5fee63e1219 100644 --- a/homeassistant/components/insteon/translations/et.json +++ b/homeassistant/components/insteon/translations/et.json @@ -1,24 +1,14 @@ { "config": { "abort": { - "already_configured": "Insteoni modemi \u00fchendus on juba seadistatud", "cannot_connect": "\u00dchendamine nurjus", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "error": { - "cannot_connect": "\u00dchendamine nurjus" + "cannot_connect": "\u00dchendamine nurjus", + "select_single": "Vali \u00fcks suvand." }, "step": { - "hub1": { - "title": "" - }, - "hub2": { - "data": { - "password": "Salas\u00f5na", - "username": "Kasutajanimi" - }, - "title": "" - }, "hubv1": { "data": { "host": "IP aagress", @@ -37,13 +27,11 @@ "description": "Insteon Hub ver 2 seadistamine.", "title": "" }, - "init": { - "title": "" - }, "plm": { "data": { "device": "USB seadme rada" }, + "description": "Insteon PowerLink Modemi (PLM) seadistamine.", "title": "" }, "user": { @@ -56,15 +44,29 @@ } }, "options": { - "abort": { - "already_configured": "Insteoni modemi \u00fchendus on juba seadistatud" - }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "input_error": "Vigane sisestus, kontrolli andmeid" + "input_error": "Vigane sisestus, kontrolli andmeid", + "select_single": "Vali \u00fcks suvand." }, "step": { "add_override": { + "data": { + "address": "Seadme aadress (n\u00e4iteks 1a2b3c)", + "cat": "Seadme kategooria (n\u00e4iteks 0x10)", + "subcat": "Seadme alamkategooria (n\u00e4iteks 0x0a)" + }, + "description": "Lisa seadme alistamine.", + "title": "" + }, + "add_x10": { + "data": { + "housecode": "", + "platform": "Platvorm", + "steps": "H\u00e4mardamise samm (ainult valgustite jaoks, vaikimisi 22)", + "unitcode": "" + }, + "description": "Muuda Insteon Hubi parooli.", "title": "" }, "change_hub_config": { @@ -73,9 +75,33 @@ "password": "Salas\u00f5na", "port": "", "username": "Kasutajanimi" - } + }, + "description": "Muutda Insteon Hubi \u00fchenduse teavet. P\u00e4rast selle muudatuse tegemist pead Home Assistanti taask\u00e4ivitama. See ei muuda jaoturi enda konfiguratsiooni. Hubis muudatuste tegemiseks kasutage rakendust Hub.", + "title": "" + }, + "init": { + "data": { + "add_override": "Lisa seadme alistamine.", + "add_x10": "Lisa X10 seade.", + "change_hub_config": "Muuda jaoturi konfiguratsiooni.", + "remove_override": "Seadme alistamise eemaldamine.", + "remove_x10": "Eemalda X10 seade." + }, + "description": "Vali seadistussuvand.", + "title": "" + }, + "remove_override": { + "data": { + "address": "Vali eemaldatava seadme aadress" + }, + "description": "Seadme alistamise eemaldamine", + "title": "" }, "remove_x10": { + "data": { + "address": "Vali eemaldatava seadme aadress" + }, + "description": "Eemalda X10 seade", "title": "" } } diff --git a/homeassistant/components/insteon/translations/fr.json b/homeassistant/components/insteon/translations/fr.json index f18df011048..a0bd2f4048e 100644 --- a/homeassistant/components/insteon/translations/fr.json +++ b/homeassistant/components/insteon/translations/fr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Une connexion Insteon par modem est d\u00e9j\u00e0 configur\u00e9e", "cannot_connect": "\u00c9chec de connexion", "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, @@ -10,24 +9,6 @@ "select_single": "S\u00e9lectionnez une option." }, "step": { - "hub1": { - "data": { - "host": "Adresse IP du hub", - "port": "Port IP" - }, - "description": "Configurer le Hub Insteon Version 1 (avant 2014).", - "title": "Hub Insteon Version 1" - }, - "hub2": { - "data": { - "host": "Adresse IP du hub", - "password": "Mot de passe", - "port": "Port IP", - "username": "Nom d'utilisateur" - }, - "description": "Configurez le Hub Insteon version 2.", - "title": "Hub Insteon Version 2" - }, "hubv1": { "data": { "host": "Adresse IP", @@ -46,15 +27,6 @@ "description": "Configurez le Hub Insteon version 2.", "title": "Hub Insteon Version 2" }, - "init": { - "data": { - "hubv1": "Hub Version 1 (avant 2014)", - "hubv2": "Hub version 2", - "plm": "Modem PowerLink (PLM)" - }, - "description": "S\u00e9lectionnez le type de modem Insteon.", - "title": "Insteon" - }, "plm": { "data": { "device": "Chemin du p\u00e9riph\u00e9rique USB" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "Une connexion Insteon par modem est d\u00e9j\u00e0 configur\u00e9e", - "cannot_connect": "Impossible de se connecter au modem Insteon" - }, "error": { "cannot_connect": "\u00c9chec de connexion", "input_error": "Entr\u00e9es non valides, veuillez v\u00e9rifier vos valeurs.", diff --git a/homeassistant/components/insteon/translations/it.json b/homeassistant/components/insteon/translations/it.json index ab9902ec0ca..f328c5a5f7e 100644 --- a/homeassistant/components/insteon/translations/it.json +++ b/homeassistant/components/insteon/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Una connessione modem Insteon \u00e8 gi\u00e0 configurata", "cannot_connect": "Impossibile connettersi", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, @@ -10,24 +9,6 @@ "select_single": "Selezionare un'opzione." }, "step": { - "hub1": { - "data": { - "host": "Indirizzo IP dell'hub", - "port": "Porta IP" - }, - "description": "Configurare la versione 1 di Insteon Hub (pre-2014).", - "title": "Insteon Hub versione 1" - }, - "hub2": { - "data": { - "host": "Indirizzo IP dell'hub", - "password": "Password", - "port": "Porta IP", - "username": "Nome utente" - }, - "description": "Configurare la versione 2 di Insteon Hub.", - "title": "Insteon Hub versione 2" - }, "hubv1": { "data": { "host": "Indirizzo IP", @@ -46,15 +27,6 @@ "description": "Configurare la versione 2 di Insteon Hub.", "title": "Insteon Hub Versione 2" }, - "init": { - "data": { - "hubv1": "Hub versione 1 (precedente al 2014)", - "hubv2": "Hub versione 2", - "plm": "Modem PowerLink (PLM)" - }, - "description": "Selezionare il tipo di modem Insteon.", - "title": "Insteon" - }, "plm": { "data": { "device": "Percorso del dispositivo USB" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "Una connessione modem Insteon \u00e8 gi\u00e0 configurata", - "cannot_connect": "Impossibile connettersi al modem Insteon" - }, "error": { "cannot_connect": "Impossibile connettersi", "input_error": "Voci non valide, si prega di controllare i valori.", diff --git a/homeassistant/components/insteon/translations/ko.json b/homeassistant/components/insteon/translations/ko.json index 7c77bd49e27..76ef9566725 100644 --- a/homeassistant/components/insteon/translations/ko.json +++ b/homeassistant/components/insteon/translations/ko.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Insteon \ubaa8\ub380 \uc5f0\uacb0\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "cannot_connect": "\uc5f0\uacb0 \uc2e4\ud328", "single_instance_allowed": "\uc774\ubbf8 \uad6c\uc131\ub428. \ud558\ub098\uc758 \uad6c\uc131\ub9cc \uac00\ub2a5\ud569\ub2c8\ub2e4." }, @@ -10,22 +9,6 @@ "select_single": "\ud558\ub098\uc758 \uc635\uc158\uc744 \uc120\ud0dd\ud558\uc2ed\uc2dc\uc624." }, "step": { - "hub1": { - "data": { - "host": "\ud5c8\ube0c IP \uc8fc\uc18c", - "port": "IP \ud3ec\ud2b8" - }, - "description": "Insteon Hub \ubc84\uc804 1 (2014 \ub144 \uc774\uc804)\uc744 \uad6c\uc131\ud569\ub2c8\ub2e4.", - "title": "Insteon Hub \ubc84\uc804 1" - }, - "hub2": { - "data": { - "host": "\ud5c8\ube0c IP \uc8fc\uc18c", - "port": "IP \ud3ec\ud2b8" - }, - "description": "Insteon Hub \ubc84\uc804 2\ub97c \uad6c\uc131\ud569\ub2c8\ub2e4.", - "title": "Insteon Hub \ubc84\uc804 2" - }, "hubv1": { "data": { "host": "IP \uc8fc\uc18c", @@ -44,11 +27,6 @@ "description": "Insteon Hub \ubc84\uc804 2\ub97c \uad6c\uc131\ud569\ub2c8\ub2e4.", "title": "Insteon Hub \ubc84\uc804 2" }, - "init": { - "data": { - "hubv1": "\ud5c8\ube0c \ubc84\uc804 1 (2014 \ub144 \uc774\uc804)" - } - }, "plm": { "data": { "device": "USB \uc7a5\uce58 \uacbd\ub85c" @@ -64,9 +42,6 @@ } }, "options": { - "abort": { - "cannot_connect": "Insteon \ubaa8\ub380\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." - }, "error": { "cannot_connect": "\uc5f0\uacb0 \uc2e4\ud328", "select_single": "\uc635\uc158 \uc120\ud0dd" diff --git a/homeassistant/components/insteon/translations/lb.json b/homeassistant/components/insteon/translations/lb.json index d6b8bf13b5b..ea8bd295900 100644 --- a/homeassistant/components/insteon/translations/lb.json +++ b/homeassistant/components/insteon/translations/lb.json @@ -1,32 +1,14 @@ { "config": { "abort": { - "already_configured": "Eng Insteon Modem Verbindung ass scho konfigur\u00e9iert", - "cannot_connect": "Feeler beim verbannen" + "cannot_connect": "Feeler beim verbannen", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { "cannot_connect": "Feeler beim verbannen mam", "select_single": "Eng Optioun auswielen." }, "step": { - "hub1": { - "data": { - "host": "Hub IP Adress", - "port": "IP Port" - }, - "description": "Insteon Hub Versioun 1 (pre-2014) konfigur\u00e9ieren.", - "title": "Insteon Hub Versioun 1" - }, - "hub2": { - "data": { - "host": "Hub IP Adress", - "password": "Passwuert", - "port": "IP Port", - "username": "Benotzernumm" - }, - "description": "Insteon Hub Versioun 2 konfigur\u00e9ieren.", - "title": "Insteon Hub Versioun 2" - }, "hubv1": { "data": { "host": "IP Adresse", @@ -45,15 +27,6 @@ "description": "Insteon Hub Versioun 2 konfigur\u00e9ieren.", "title": "Insteon Hub Versioun 2" }, - "init": { - "data": { - "hubv1": "Hub Versioun 1 (Pre-2014)", - "hubv2": "Hub Versioun 2", - "plm": "Powerlink Modem (PLM)" - }, - "description": "Insteon Modem Typ auswielen.", - "title": "Insteon" - }, "plm": { "data": { "device": "Pad vum USB Apparat" @@ -71,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "Eng Insteon Modem Verbindung ass scho konfigur\u00e9iert", - "cannot_connect": "Keng Verbindung mam Insteon Modem m\u00e9iglech" - }, "error": { "cannot_connect": "Feeler beim verbannen", "input_error": "Ong\u00eblteg Entr\u00e9e\u00ebn, iwwerpr\u00e9if deng W\u00e4erter.", diff --git a/homeassistant/components/insteon/translations/nl.json b/homeassistant/components/insteon/translations/nl.json index 5c8ffa91cff..923fdbfb449 100644 --- a/homeassistant/components/insteon/translations/nl.json +++ b/homeassistant/components/insteon/translations/nl.json @@ -1,15 +1,13 @@ { "config": { "abort": { + "cannot_connect": "Kon niet verbinden", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, + "error": { + "cannot_connect": "Kon niet verbinden" + }, "step": { - "hub2": { - "data": { - "password": "Wachtwoord", - "username": "Gebruikersnaam" - } - }, "hubv1": { "data": { "host": "IP-adres", @@ -34,14 +32,21 @@ } }, "options": { + "error": { + "cannot_connect": "Kon niet verbinden" + }, "step": { + "add_x10": { + "description": "Wijzig het wachtwoord van de Insteon Hub." + }, "change_hub_config": { "data": { "host": "IP-adres", "password": "Wachtwoord", "port": "Poort", "username": "Gebruikersnaam" - } + }, + "description": "Wijzig de verbindingsgegevens van de Insteon Hub. Je moet Home Assistant opnieuw opstarten nadat je deze wijziging hebt aangebracht. Dit verandert niets aan de configuratie van de Hub zelf. Gebruik de Hub-app om de configuratie in de Hub te wijzigen." } } } diff --git a/homeassistant/components/insteon/translations/no.json b/homeassistant/components/insteon/translations/no.json index 4e0e4e01cc5..b5d6a2c3105 100644 --- a/homeassistant/components/insteon/translations/no.json +++ b/homeassistant/components/insteon/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "En Insteon-modemtilkobling er allerede konfigurert", "cannot_connect": "Tilkobling mislyktes", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, @@ -10,24 +9,6 @@ "select_single": "Velg ett alternativ." }, "step": { - "hub1": { - "data": { - "host": "Hub-IP-adresse", - "port": "" - }, - "description": "Konfigurer Insteon Hub versjon 1 (f\u00f8r 2014).", - "title": "Insteon Hub versjon 1" - }, - "hub2": { - "data": { - "host": "Hub-IP-adresse", - "password": "Passord", - "port": "", - "username": "Brukernavn" - }, - "description": "Konfigurer Insteon Hub versjon 2.", - "title": "Insteon Hub versjon 2" - }, "hubv1": { "data": { "host": "IP adresse", @@ -46,15 +27,6 @@ "description": "Konfigurer Insteon Hub versjon 2.", "title": "Insteon Hub versjon 2" }, - "init": { - "data": { - "hubv1": "Hub versjon 1 (f\u00f8r 2014)", - "hubv2": "Hub versjon 2", - "plm": "PowerLink-modem (PLM)" - }, - "description": "Velg Insteon modemtype.", - "title": "" - }, "plm": { "data": { "device": "USB enhetsbane" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "En Insteon-modemtilkobling er allerede konfigurert", - "cannot_connect": "Kan ikke koble til Insteon-modemet" - }, "error": { "cannot_connect": "Tilkobling mislyktes", "input_error": "Ugyldige oppf\u00f8ringer, vennligst sjekk verdiene dine.", diff --git a/homeassistant/components/insteon/translations/pl.json b/homeassistant/components/insteon/translations/pl.json index 688fae3ed74..28c4414b9da 100644 --- a/homeassistant/components/insteon/translations/pl.json +++ b/homeassistant/components/insteon/translations/pl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Po\u0142\u0105czenie z modemem Insteon jest ju\u017c skonfigurowane", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, @@ -10,24 +9,6 @@ "select_single": "Wybierz jedn\u0105 z opcji" }, "step": { - "hub1": { - "data": { - "host": "Adres IP Huba", - "port": "Numer portu IP" - }, - "description": "Konfiguracja Huba Insteon \u2014 wersja 1 (sprzed 2014r.)", - "title": "Hub Insteon \u2014 wersja 1" - }, - "hub2": { - "data": { - "host": "Adres IP Huba", - "password": "Has\u0142o", - "port": "Numer portu IP", - "username": "Nazwa u\u017cytkownika" - }, - "description": "Konfiguracja Huba Insteon \u2014 wersja 2.", - "title": "Hub Insteon \u2014 wersja 2" - }, "hubv1": { "data": { "host": "Adres IP", @@ -43,18 +24,9 @@ "port": "Port", "username": "Nazwa u\u017cytkownika" }, - "description": "Konfiguracja Huba Insteon \u2014 wersja 2.", + "description": "Konfiguracja Huba Insteon \u2014 wersja 2", "title": "Hub Insteon \u2014 wersja 2" }, - "init": { - "data": { - "hubv1": "Hub \u2014 wersja 1 (sprzed 2014r.)", - "hubv2": "Hub \u2014 wersja 2", - "plm": "Modem PowerLink (PLM)" - }, - "description": "Wybierz typ modemu Insteon.", - "title": "Insteon" - }, "plm": { "data": { "device": "\u015acie\u017cka urz\u0105dzenia USB" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "Po\u0142\u0105czenie z modemem Insteon jest ju\u017c skonfigurowane", - "cannot_connect": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z modemem Insteon" - }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "input_error": "Nieprawid\u0142owe wpisy, sprawd\u017a wpisane warto\u015bci", diff --git a/homeassistant/components/insteon/translations/pt-BR.json b/homeassistant/components/insteon/translations/pt-BR.json index e14afa3e18f..f888c15874b 100644 --- a/homeassistant/components/insteon/translations/pt-BR.json +++ b/homeassistant/components/insteon/translations/pt-BR.json @@ -1,30 +1,5 @@ { - "config": { - "step": { - "hub2": { - "data": { - "host": "Endere\u00e7o IP do hub", - "password": "Senha", - "port": "Porta IP", - "username": "Nome de usu\u00e1rio" - }, - "description": "Configure o Insteon Hub Vers\u00e3o 2.", - "title": "Insteon Hub vers\u00e3o 2" - }, - "init": { - "data": { - "hubv1": "Hub Vers\u00e3o 1 (Pr\u00e9-2014)", - "hubv2": "Hub vers\u00e3o 2" - }, - "description": "Selecione o tipo de modem Insteon." - } - } - }, "options": { - "abort": { - "already_configured": "Uma conex\u00e3o com modem Insteon j\u00e1 est\u00e1 configurada", - "cannot_connect": "N\u00e3o \u00e9 poss\u00edvel conectar-se ao modem Insteon." - }, "error": { "cannot_connect": "Falha na conex\u00e3o com o modem Insteon, por favor tente novamente.", "input_error": "Entradas inv\u00e1lidas, por favor, verifique seus valores.", diff --git a/homeassistant/components/insteon/translations/ru.json b/homeassistant/components/insteon/translations/ru.json index 65861a0a161..dec25f1fe4b 100644 --- a/homeassistant/components/insteon/translations/ru.json +++ b/homeassistant/components/insteon/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u044d\u0442\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, @@ -10,24 +9,6 @@ "select_single": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u043f\u0446\u0438\u044e." }, "step": { - "hub1": { - "data": { - "host": "IP-\u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0430\u0442\u043e\u0440\u0430", - "port": "IP \u043f\u043e\u0440\u0442" - }, - "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Insteon Hub \u0432\u0435\u0440\u0441\u0438\u0438 1 (\u0434\u043e 2014 \u0433\u043e\u0434\u0430)", - "title": "Insteon Hub. \u0412\u0435\u0440\u0441\u0438\u044f 1" - }, - "hub2": { - "data": { - "host": "IP-\u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0430\u0442\u043e\u0440\u0430", - "password": "\u041f\u0430\u0440\u043e\u043b\u044c", - "port": "IP \u043f\u043e\u0440\u0442", - "username": "\u041b\u043e\u0433\u0438\u043d" - }, - "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Insteon Hub \u0432\u0435\u0440\u0441\u0438\u0438 2", - "title": "Insteon Hub. \u0412\u0435\u0440\u0441\u0438\u044f 2" - }, "hubv1": { "data": { "host": "IP-\u0430\u0434\u0440\u0435\u0441", @@ -46,15 +27,6 @@ "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Insteon Hub \u0432\u0435\u0440\u0441\u0438\u0438 2", "title": "Insteon Hub. \u0412\u0435\u0440\u0441\u0438\u044f 2" }, - "init": { - "data": { - "hubv1": "\u0412\u0435\u0440\u0441\u0438\u044f 1 (\u0434\u043e 2014 \u0433\u043e\u0434\u0430)", - "hubv2": "\u0412\u0435\u0440\u0441\u0438\u044f 2", - "plm": "\u041c\u043e\u0434\u0435\u043c PowerLink (PLM)" - }, - "description": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0438\u043f \u043c\u043e\u0434\u0435\u043c\u0430 Insteon.", - "title": "Insteon" - }, "plm": { "data": { "device": "\u041f\u0443\u0442\u044c \u043a USB-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u044d\u0442\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443." - }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "input_error": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.", diff --git a/homeassistant/components/insteon/translations/zh-Hans.json b/homeassistant/components/insteon/translations/zh-Hans.json index eb9facef178..050d31bc0d7 100644 --- a/homeassistant/components/insteon/translations/zh-Hans.json +++ b/homeassistant/components/insteon/translations/zh-Hans.json @@ -1,11 +1,6 @@ { "config": { "step": { - "hub2": { - "data": { - "username": "\u7528\u6237\u540d" - } - }, "hubv2": { "data": { "username": "\u7528\u6237\u540d" diff --git a/homeassistant/components/insteon/translations/zh-Hant.json b/homeassistant/components/insteon/translations/zh-Hant.json index d561bac9aea..5358cccb85b 100644 --- a/homeassistant/components/insteon/translations/zh-Hant.json +++ b/homeassistant/components/insteon/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Insteon \u6578\u64da\u6a5f\u9023\u7dda\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "cannot_connect": "\u9023\u7dda\u5931\u6557", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, @@ -10,24 +9,6 @@ "select_single": "\u9078\u64c7\u9078\u9805\u3002" }, "step": { - "hub1": { - "data": { - "host": "Hub IP \u4f4d\u5740", - "port": "IP \u57e0" - }, - "description": "\u8a2d\u5b9a Insteon Hub \u7b2c 1 \u7248\uff082014 \u5e74\u4ee5\u524d\uff09\u3002", - "title": "Insteon Hub \u7b2c 1 \u7248" - }, - "hub2": { - "data": { - "host": "Hub IP \u4f4d\u5740", - "password": "\u5bc6\u78bc", - "port": "IP \u57e0", - "username": "\u4f7f\u7528\u8005\u540d\u7a31" - }, - "description": "\u8a2d\u5b9a Insteon Hub \u7b2c 2 \u7248\u3002", - "title": "Insteon Hub \u7b2c 2 \u7248" - }, "hubv1": { "data": { "host": "IP \u4f4d\u5740", @@ -46,15 +27,6 @@ "description": "\u8a2d\u5b9a Insteon Hub \u7b2c 2 \u7248\u3002", "title": "Insteon Hub \u7b2c 2 \u7248" }, - "init": { - "data": { - "hubv1": "Insteon Hub \u7b2c 1 \u7248\uff082014 \u5e74\u4ee5\u524d\uff09", - "hubv2": "Insteon Hub \u7b2c 2 \u7248", - "plm": "PowerLink Modem (PLM)" - }, - "description": "\u9078\u64c7 Insteon \u6578\u64da\u6a5f\u985e\u578b\u3002", - "title": "Insteon" - }, "plm": { "data": { "device": "USB \u8a2d\u5099\u8def\u5f91" @@ -72,10 +44,6 @@ } }, "options": { - "abort": { - "already_configured": "Insteon \u6578\u64da\u6a5f\u9023\u7dda\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "cannot_connect": "\u7121\u6cd5\u9023\u7dda\u81f3 Insteon \u6578\u64da\u6a5f\u3002" - }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", "input_error": "\u5be6\u9ad4\u7121\u6548\uff0c\u8acb\u6aa2\u67e5\u8a2d\u5b9a\u503c\u3002", diff --git a/homeassistant/components/ios/translations/lb.json b/homeassistant/components/ios/translations/lb.json index 85d78613d55..5a963a3b728 100644 --- a/homeassistant/components/ios/translations/lb.json +++ b/homeassistant/components/ios/translations/lb.json @@ -1,11 +1,11 @@ { "config": { "abort": { - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun Home Assistant iOS ass n\u00e9ideg." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "confirm": { - "description": "W\u00ebllt dir d'Home Assistant iOS Komponent ariichten?" + "description": "Soll den Ariichtungs Prozess gestart ginn?" } } } diff --git a/homeassistant/components/ipma/strings.json b/homeassistant/components/ipma/strings.json index e3825bd4b27..bf0cf7a9ff8 100644 --- a/homeassistant/components/ipma/strings.json +++ b/homeassistant/components/ipma/strings.json @@ -2,13 +2,13 @@ "config": { "step": { "user": { - "title": "Location", + "title": "[%key:common::config_flow::data::location%]", "description": "Instituto Portugu\u00eas do Mar e Atmosfera", "data": { "name": "[%key:common::config_flow::data::name%]", "latitude": "[%key:common::config_flow::data::latitude%]", "longitude": "[%key:common::config_flow::data::longitude%]", - "mode": "Mode" + "mode": "[%key:common::config_flow::data::mode%]" } } }, diff --git a/homeassistant/components/ipma/translations/et.json b/homeassistant/components/ipma/translations/et.json index 9147ada7b5e..a45685c96e2 100644 --- a/homeassistant/components/ipma/translations/et.json +++ b/homeassistant/components/ipma/translations/et.json @@ -1,12 +1,17 @@ { "config": { + "error": { + "name_exists": "Nimi on juba olemas" + }, "step": { "user": { "data": { "latitude": "Laiuskraad", "longitude": "Pikkuskraad", + "mode": "Re\u017eiim", "name": "Nimi" }, + "description": "", "title": "Asukoht" } } diff --git a/homeassistant/components/ipma/translations/it.json b/homeassistant/components/ipma/translations/it.json index ceee3c9091f..467cc64f561 100644 --- a/homeassistant/components/ipma/translations/it.json +++ b/homeassistant/components/ipma/translations/it.json @@ -12,7 +12,7 @@ "name": "Nome" }, "description": "Instituto Portugu\u00eas do Mar e Atmosfera", - "title": "Localit\u00e0" + "title": "Posizione" } } } diff --git a/homeassistant/components/ipma/translations/lb.json b/homeassistant/components/ipma/translations/lb.json index e4896df58ba..7b2d374b6f5 100644 --- a/homeassistant/components/ipma/translations/lb.json +++ b/homeassistant/components/ipma/translations/lb.json @@ -12,7 +12,7 @@ "name": "Numm" }, "description": "Instituto Portugu\u00eas do Mar e Atmosfera", - "title": "Uertschaft" + "title": "Standuert" } } } diff --git a/homeassistant/components/ipma/weather.py b/homeassistant/components/ipma/weather.py index a2c47f43ffb..d8ac0c039da 100644 --- a/homeassistant/components/ipma/weather.py +++ b/homeassistant/components/ipma/weather.py @@ -25,7 +25,8 @@ from homeassistant.const import ( CONF_NAME, TEMP_CELSIUS, ) -from homeassistant.helpers import config_validation as cv +from homeassistant.core import callback +from homeassistant.helpers import config_validation as cv, entity_registry from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.util import Throttle from homeassistant.util.dt import now, parse_datetime @@ -89,10 +90,33 @@ async def async_setup_entry(hass, config_entry, async_add_entities): """Add a weather entity from a config_entry.""" latitude = config_entry.data[CONF_LATITUDE] longitude = config_entry.data[CONF_LONGITUDE] + mode = config_entry.data[CONF_MODE] api = await async_get_api(hass) location = await async_get_location(hass, api, latitude, longitude) + # Migrate old unique_id + @callback + def _async_migrator(entity_entry: entity_registry.RegistryEntry): + # Reject if new unique_id + if entity_entry.unique_id.count(",") == 2: + return None + + new_unique_id = ( + f"{location.station_latitude}, {location.station_longitude}, {mode}" + ) + + _LOGGER.info( + "Migrating unique_id from [%s] to [%s]", + entity_entry.unique_id, + new_unique_id, + ) + return {"new_unique_id": new_unique_id} + + await entity_registry.async_migrate_entries( + hass, config_entry.entry_id, _async_migrator + ) + async_add_entities([IPMAWeather(location, api, config_entry.data)], True) @@ -157,7 +181,7 @@ class IPMAWeather(WeatherEntity): @property def unique_id(self) -> str: """Return a unique id.""" - return f"{self._location.station_latitude}, {self._location.station_longitude}" + return f"{self._location.station_latitude}, {self._location.station_longitude}, {self._mode}" @property def attribution(self): diff --git a/homeassistant/components/ipp/translations/ca.json b/homeassistant/components/ipp/translations/ca.json index f282838a757..9f508c18246 100644 --- a/homeassistant/components/ipp/translations/ca.json +++ b/homeassistant/components/ipp/translations/ca.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "Ha fallat la connexi\u00f3", "connection_upgrade": "No s'ha pogut connectar amb la impressora, es necessita actualitzar la connexi\u00f3.", "ipp_error": "S'ha produ\u00eft un error IPP.", "ipp_version_error": "La versi\u00f3 IPP no \u00e9s compatible amb la impressora.", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "Ha fallat la connexi\u00f3", "connection_upgrade": "No s'ha pogut connectar amb la impressora. Prova-ho novament amb l'opci\u00f3 SSL/TLS activada." }, "flow_title": "Impressora: {name}", diff --git a/homeassistant/components/ipp/translations/cs.json b/homeassistant/components/ipp/translations/cs.json index 1e62dbefbcf..13dedef27d1 100644 --- a/homeassistant/components/ipp/translations/cs.json +++ b/homeassistant/components/ipp/translations/cs.json @@ -3,12 +3,11 @@ "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit", + "connection_upgrade": "P\u0159ipojen\u00ed k tisk\u00e1rn\u011b se nezda\u0159ilo. Je nutn\u00e9 nejprve aktualizovat p\u0159ipojen\u00ed.", "ipp_version_error": "Verze IPP nen\u00ed tisk\u00e1rnou podporov\u00e1na." }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit" + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "flow_title": "Tisk\u00e1rna: {name}", "step": { @@ -19,6 +18,7 @@ "ssl": "Pou\u017e\u00edv\u00e1 SSL certifik\u00e1t", "verify_ssl": "Ov\u011b\u0159it certifik\u00e1t SSL" }, + "description": "Nastavte svou tisk\u00e1rnu pomoc\u00ed protokolu IPP (Internet Printing Protocol) pro integraci s Home Assistant.", "title": "Propojte svou tisk\u00e1rnu" }, "zeroconf_confirm": { diff --git a/homeassistant/components/ipp/translations/da.json b/homeassistant/components/ipp/translations/da.json index 19ad3f2eedf..320c09686c8 100644 --- a/homeassistant/components/ipp/translations/da.json +++ b/homeassistant/components/ipp/translations/da.json @@ -2,11 +2,9 @@ "config": { "abort": { "already_configured": "Denne printer er allerede konfigureret.", - "connection_error": "Kunne ikke oprette forbindelse til printeren.", "connection_upgrade": "Der kunne ikke oprettes forbindelse til printeren, fordi der kr\u00e6ves opgradering af forbindelsen." }, "error": { - "connection_error": "Kunne ikke oprette forbindelse til printeren.", "connection_upgrade": "Kunne ikke oprette forbindelse til printeren. Pr\u00f8v igen med indstillingen SSL/TLS markeret." }, "flow_title": "Printer: {name}", diff --git a/homeassistant/components/ipp/translations/de.json b/homeassistant/components/ipp/translations/de.json index 07d681f4172..73dd3f69bcc 100644 --- a/homeassistant/components/ipp/translations/de.json +++ b/homeassistant/components/ipp/translations/de.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Ger\u00e4t ist bereits konfiguriert", - "connection_error": "Verbindung fehlgeschlagen.", "connection_upgrade": "Verbindung zum Drucker fehlgeschlagen, da ein Verbindungsupgrade erforderlich ist.", "ipp_error": "IPP-Fehler festgestellt.", "ipp_version_error": "IPP-Version wird vom Drucker nicht unterst\u00fctzt.", @@ -10,7 +9,6 @@ "unique_id_required": "Ger\u00e4t fehlt die f\u00fcr die Entdeckung erforderliche eindeutige Identifizierung." }, "error": { - "connection_error": "Verbindung fehlgeschlagen", "connection_upgrade": "Verbindung zum Drucker fehlgeschlagen. Bitte versuchen Sie es erneut mit aktivierter SSL / TLS-Option." }, "flow_title": "Drucker: {name}", diff --git a/homeassistant/components/ipp/translations/en.json b/homeassistant/components/ipp/translations/en.json index 85233866f0d..69bc0b091ab 100644 --- a/homeassistant/components/ipp/translations/en.json +++ b/homeassistant/components/ipp/translations/en.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Device is already configured", "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect", "connection_upgrade": "Failed to connect to printer due to connection upgrade being required.", "ipp_error": "Encountered IPP error.", "ipp_version_error": "IPP version not supported by printer.", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect", "connection_upgrade": "Failed to connect to printer. Please try again with SSL/TLS option checked." }, "flow_title": "Printer: {name}", diff --git a/homeassistant/components/ipp/translations/es-419.json b/homeassistant/components/ipp/translations/es-419.json index eb9c21eb28c..a8141bee3dd 100644 --- a/homeassistant/components/ipp/translations/es-419.json +++ b/homeassistant/components/ipp/translations/es-419.json @@ -2,14 +2,12 @@ "config": { "abort": { "already_configured": "Esta impresora ya est\u00e1 configurada.", - "connection_error": "No se pudo conectar a la impresora.", "connection_upgrade": "No se pudo conectar a la impresora debido a que se requiere una actualizaci\u00f3n de la conexi\u00f3n.", "ipp_error": "Error de IPP encontrado.", "ipp_version_error": "La versi\u00f3n IPP no es compatible con la impresora.", "parse_error": "Error al analizar la respuesta de la impresora." }, "error": { - "connection_error": "No se pudo conectar a la impresora.", "connection_upgrade": "No se pudo conectar a la impresora. Intente nuevamente con la opci\u00f3n SSL/TLS marcada." }, "flow_title": "Impresora: {name}", diff --git a/homeassistant/components/ipp/translations/es.json b/homeassistant/components/ipp/translations/es.json index b357768b191..be1b38f08db 100644 --- a/homeassistant/components/ipp/translations/es.json +++ b/homeassistant/components/ipp/translations/es.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Dispositivo ya configurado", "cannot_connect": "No se pudo conectar", - "connection_error": "Error al conectar", "connection_upgrade": "No se pudo conectar con la impresora debido a que se requiere una actualizaci\u00f3n de la conexi\u00f3n.", "ipp_error": "Error IPP encontrado.", "ipp_version_error": "Versi\u00f3n de IPP no compatible con la impresora.", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "connection_error": "Error al conectar", "connection_upgrade": "No se pudo conectar con la impresora. Int\u00e9ntalo de nuevo con la opci\u00f3n SSL/TLS marcada." }, "flow_title": "Impresora: {name}", diff --git a/homeassistant/components/ipp/translations/et.json b/homeassistant/components/ipp/translations/et.json index aef1e90129d..622b71d758a 100644 --- a/homeassistant/components/ipp/translations/et.json +++ b/homeassistant/components/ipp/translations/et.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Seade on juba seadistatud", "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "\u00dchendamine nurjus", "connection_upgrade": "Printeriga \u00fchenduse loomine nurjus kuna vajalik on \u00fchenduse uuendamine.", "ipp_error": "Ilmnes IPP viga.", "ipp_version_error": "Printer ei toeta seda IPP versiooni.", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "\u00dchendamine nurjus", "connection_upgrade": "Printeriga \u00fchenduse loomine nurjus. Proovige uuesti kui SSL/TLS-i suvand on m\u00e4rgitud." }, "flow_title": "Printer: {name}", diff --git a/homeassistant/components/ipp/translations/fr.json b/homeassistant/components/ipp/translations/fr.json index be2166ad433..17d7375dbf4 100644 --- a/homeassistant/components/ipp/translations/fr.json +++ b/homeassistant/components/ipp/translations/fr.json @@ -2,7 +2,7 @@ "config": { "abort": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", - "connection_error": "\u00c9chec de connexion", + "cannot_connect": "\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.", "ipp_version_error": "Version d'IPP non prise en charge par l'imprimante.", @@ -10,7 +10,7 @@ "unique_id_required": "Dispositif ne portant pas l'identification unique requise pour la d\u00e9couverte." }, "error": { - "connection_error": "\u00c9chec de connexion", + "cannot_connect": "\u00c9chec de connexion", "connection_upgrade": "Impossible de se connecter \u00e0 l'imprimante. Veuillez r\u00e9essayer avec l'option SSL / TLS coch\u00e9e." }, "flow_title": "Imprimante: {name}", diff --git a/homeassistant/components/ipp/translations/hu.json b/homeassistant/components/ipp/translations/hu.json index 657491280df..f4bcbbf586e 100644 --- a/homeassistant/components/ipp/translations/hu.json +++ b/homeassistant/components/ipp/translations/hu.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van", - "connection_error": "Sikertelen csatlakoz\u00e1s" - }, - "error": { - "connection_error": "Sikertelen csatlakoz\u00e1s" + "already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van" }, "flow_title": "Nyomtat\u00f3: {name}", "step": { diff --git a/homeassistant/components/ipp/translations/it.json b/homeassistant/components/ipp/translations/it.json index 1223705bacc..7e3d5a853ad 100644 --- a/homeassistant/components/ipp/translations/it.json +++ b/homeassistant/components/ipp/translations/it.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi", "connection_upgrade": "Impossibile connettersi alla stampante a causa della necessit\u00e0 dell'aggiornamento della connessione.", "ipp_error": "Si \u00e8 verificato un errore IPP.", "ipp_version_error": "Versione IPP non supportata dalla stampante.", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi", "connection_upgrade": "Impossibile connettersi alla stampante. Riprovare selezionando l'opzione SSL/TLS." }, "flow_title": "Stampante: {name}", diff --git a/homeassistant/components/ipp/translations/ko.json b/homeassistant/components/ipp/translations/ko.json index dd071ed41ec..bc2e18cb5c2 100644 --- a/homeassistant/components/ipp/translations/ko.json +++ b/homeassistant/components/ipp/translations/ko.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "connection_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4", "connection_upgrade": "\ud504\ub9b0\ud130\uc5d0 \uc5f0\uacb0\ud558\ub824\uba74 \uc5f0\uacb0\uc744 \uc5c5\uadf8\ub808\uc774\ub4dc\ud574\uc57c \ud569\ub2c8\ub2e4.", "ipp_error": "IPP \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.", "ipp_version_error": "\ud504\ub9b0\ud130\uc5d0\uc11c IPP \ubc84\uc804\uc744 \uc9c0\uc6d0\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.", @@ -10,7 +9,6 @@ "unique_id_required": "\uae30\uae30 \uac80\uc0c9\uc5d0 \ud544\uc694\ud55c \uace0\uc720\ud55c ID \uac00 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4." }, "error": { - "connection_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4", "connection_upgrade": "\ud504\ub9b0\ud130\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. SSL/TLS \uc635\uc158\uc744 \ud655\uc778\ud558\uace0 \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694." }, "flow_title": "\ud504\ub9b0\ud130: {name}", diff --git a/homeassistant/components/ipp/translations/lb.json b/homeassistant/components/ipp/translations/lb.json index 0752e9ca64d..d388d66eeb0 100644 --- a/homeassistant/components/ipp/translations/lb.json +++ b/homeassistant/components/ipp/translations/lb.json @@ -2,7 +2,7 @@ "config": { "abort": { "already_configured": "Apparat ass scho konfigur\u00e9iert.", - "connection_error": "Feeler beim verbannen", + "cannot_connect": "Feeler beim verbannen", "connection_upgrade": "Feeler beim verbannen mam Printer well eng Aktualis\u00e9ierung vun der Verbindung erfuerderlech ass.", "ipp_error": "IPP Feeler opgetrueden.", "ipp_version_error": "IPP Versioun net vum Printer \u00ebnnerst\u00ebtzt.", @@ -10,7 +10,7 @@ "unique_id_required": "Dem Apparat feelt eng eenzegarteg Identifikatioun d\u00e9i ben\u00e9idegt ass fir d'Entdeckung." }, "error": { - "connection_error": "Feeler beim verbannen", + "cannot_connect": "Feeler beim verbannen", "connection_upgrade": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol mat aktiv\u00e9ierter SSL/TLS Optioun." }, "flow_title": "Printer: {name}", @@ -20,8 +20,8 @@ "base_path": "Relative Pad zum Printer", "host": "Host", "port": "Port", - "ssl": "Printer \u00ebnnerst\u00ebtze Kommunikatioun iwwer SSL/TLS", - "verify_ssl": "Printer benotzt ee g\u00ebltegen SSL Zertifikat" + "ssl": "Benotzt ee SSL Zertifikat", + "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" }, "description": "Konfigur\u00e9ier d\u00e4in Printer mat Internet Printing Protocol (IPP) fir en am Home Assistant z'int\u00e9gr\u00e9ieren.", "title": "\u00c4re Printer verbannen" diff --git a/homeassistant/components/ipp/translations/nl.json b/homeassistant/components/ipp/translations/nl.json index fbcfac358ea..bcbd495be91 100644 --- a/homeassistant/components/ipp/translations/nl.json +++ b/homeassistant/components/ipp/translations/nl.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Deze printer is al geconfigureerd.", "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met de printer.", "connection_upgrade": "Kan geen verbinding maken met de printer omdat een upgrade van de verbinding vereist is.", "ipp_error": "Er is een IPP-fout opgetreden.", "ipp_version_error": "IPP-versie wordt niet ondersteund door printer.", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met de printer.", "connection_upgrade": "Kan geen verbinding maken met de printer. Probeer het opnieuw met SSL / TLS-optie aangevinkt." }, "flow_title": "Printer: {name}", diff --git a/homeassistant/components/ipp/translations/no.json b/homeassistant/components/ipp/translations/no.json index 65837f6a632..c612163d51e 100644 --- a/homeassistant/components/ipp/translations/no.json +++ b/homeassistant/components/ipp/translations/no.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Enheten er allerede konfigurert", "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes", "connection_upgrade": "Kunne ikke koble til skriveren fordi tilkoblingsoppgradering var n\u00f8dvendig.", "ipp_error": "Oppdaget IPP-feil.", "ipp_version_error": "IPP-versjon st\u00f8ttes ikke av skriveren.", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes", "connection_upgrade": "Kunne ikke koble til skriveren. Vennligst pr\u00f8v igjen med alternativet SSL / TLS merket." }, "flow_title": "Skriver: {name}", diff --git a/homeassistant/components/ipp/translations/pl.json b/homeassistant/components/ipp/translations/pl.json index 3ed47613bce..fa8e9a3ca0b 100644 --- a/homeassistant/components/ipp/translations/pl.json +++ b/homeassistant/components/ipp/translations/pl.json @@ -3,8 +3,7 @@ "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_upgrade": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z drukark\u0105 z powodu konieczno\u015bci uaktualnienia po\u0142\u0105czenia", + "connection_upgrade": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z drukark\u0105 z powodu konieczno\u015bci uaktualnienia po\u0142\u0105czenia", "ipp_error": "Wyst\u0105pi\u0142 b\u0142\u0105d IPP", "ipp_version_error": "Wersja IPP nieobs\u0142ugiwana przez drukark\u0119", "parse_error": "Nie mo\u017cna przeanalizowa\u0107 odpowiedzi z drukarki", @@ -12,8 +11,7 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_upgrade": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z drukark\u0105. Spr\u00f3buj ponownie z zaznaczon\u0105 opcj\u0105 SSL/TLS." + "connection_upgrade": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z drukark\u0105. Spr\u00f3buj ponownie z zaznaczon\u0105 opcj\u0105 SSL/TLS." }, "flow_title": "Drukarka: {name}", "step": { diff --git a/homeassistant/components/ipp/translations/ru.json b/homeassistant/components/ipp/translations/ru.json index 37502ccf9b0..44521b1ae0d 100644 --- a/homeassistant/components/ipp/translations/ru.json +++ b/homeassistant/components/ipp/translations/ru.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "connection_upgrade": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u0438\u043d\u0442\u0435\u0440\u0443 \u0438\u0437-\u0437\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f.", "ipp_error": "\u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 IPP.", "ipp_version_error": "\u0412\u0435\u0440\u0441\u0438\u044f IPP \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043d\u0442\u0435\u0440\u043e\u043c.", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "connection_upgrade": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u0438\u043d\u0442\u0435\u0440\u0443. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 SSL/TLS." }, "flow_title": "\u041f\u0440\u0438\u043d\u0442\u0435\u0440: {name}", diff --git a/homeassistant/components/ipp/translations/sl.json b/homeassistant/components/ipp/translations/sl.json index 8141aa276bd..243e9b510a8 100644 --- a/homeassistant/components/ipp/translations/sl.json +++ b/homeassistant/components/ipp/translations/sl.json @@ -2,14 +2,12 @@ "config": { "abort": { "already_configured": "Ta tiskalnik je \u017ee konfiguriran.", - "connection_error": "Povezava s tiskalnikom ni uspela.", "connection_upgrade": "Povezava s tiskalnikom ni uspela, ker je potrebna nadgradnja povezave.", "ipp_error": "Naletel na napako IPP.", "ipp_version_error": "Razli\u010dica IPP ni podprta s tiskalnikom.", "parse_error": "Odziva tiskalnika ni bilo mogo\u010de raz\u010dleniti." }, "error": { - "connection_error": "Povezava s tiskalnikom ni uspela.", "connection_upgrade": "Povezave s tiskalnikom ni bilo mogo\u010de vzpostaviti. Prosimo, poskusite znova z odkljukano mo\u017enostjo SSL/TLS." }, "flow_title": "Tiskalnik: {name}", diff --git a/homeassistant/components/ipp/translations/sv.json b/homeassistant/components/ipp/translations/sv.json index ffa6a6ae955..70b270e63a2 100644 --- a/homeassistant/components/ipp/translations/sv.json +++ b/homeassistant/components/ipp/translations/sv.json @@ -2,14 +2,12 @@ "config": { "abort": { "already_configured": "Den h\u00e4r skrivaren \u00e4r redan konfigurerad.", - "connection_error": "Kunde inte ansluta till skrivaren", "connection_upgrade": "Misslyckades att ansluta till skrivaren d\u00e5 anslutningen beh\u00f6ver uppgraderas.", "ipp_error": "IPP-fel p\u00e5tr\u00e4ffades.", "ipp_version_error": "IPP versionen st\u00f6ds inte av skrivaren", "parse_error": "Det gick inte att f\u00f6rst\u00e5 responsen fr\u00e5n skrivaren" }, "error": { - "connection_error": "Kunde inte ansluta till skrivaren", "connection_upgrade": "Kunde inte ansluta till skrivaren. F\u00f6rs\u00f6k igen med SSL/TLS alternativet ifyllt." }, "flow_title": "Skrivare: {name}", diff --git a/homeassistant/components/ipp/translations/zh-Hant.json b/homeassistant/components/ipp/translations/zh-Hant.json index 335ae984414..9fcb91c4627 100644 --- a/homeassistant/components/ipp/translations/zh-Hant.json +++ b/homeassistant/components/ipp/translations/zh-Hant.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557", "connection_upgrade": "\u7531\u65bc\u9700\u8981\u5148\u5347\u7d1a\u9023\u7dda\u3001\u9023\u7dda\u81f3\u5370\u8868\u6a5f\u5931\u6557\u3002", "ipp_error": "\u767c\u751f IPP \u932f\u8aa4\u3002", "ipp_version_error": "\u4e0d\u652f\u63f4\u5370\u8868\u6a5f\u7684 IPP \u7248\u672c\u3002", @@ -12,7 +11,6 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557", "connection_upgrade": "\u9023\u7dda\u81f3\u5370\u8868\u6a5f\u5931\u6557\u3002\u8acb\u52fe\u9078 SSL/TLS \u9078\u9805\u5f8c\u518d\u8a66\u4e00\u6b21\u3002" }, "flow_title": "\u5370\u8868\u6a5f\uff1a{name}", diff --git a/homeassistant/components/iqvia/__init__.py b/homeassistant/components/iqvia/__init__.py index 9aa00ef3f3f..d730b406896 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_setup_entry(hass, entry): 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 @@ class IQVIAEntity(CoordinatorEntity): """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() diff --git a/homeassistant/components/iqvia/translations/cs.json b/homeassistant/components/iqvia/translations/cs.json index 6754cdc84af..04829af0b8f 100644 --- a/homeassistant/components/iqvia/translations/cs.json +++ b/homeassistant/components/iqvia/translations/cs.json @@ -11,6 +11,7 @@ "data": { "zip_code": "PS\u010c" }, + "description": "Vypl\u0148te sv\u00e9 americk\u00e9 nebo kanadsk\u00e9 PS\u010c.", "title": "IQVIA" } } diff --git a/homeassistant/components/iqvia/translations/de.json b/homeassistant/components/iqvia/translations/de.json index 6f076e8b998..1318a9c90cc 100644 --- a/homeassistant/components/iqvia/translations/de.json +++ b/homeassistant/components/iqvia/translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Dienst ist bereits konfiguriert" + }, "error": { "invalid_zip_code": "Postleitzahl ist ung\u00fcltig" }, diff --git a/homeassistant/components/iqvia/translations/et.json b/homeassistant/components/iqvia/translations/et.json index 13ebab64c86..e1f6e51ef7c 100644 --- a/homeassistant/components/iqvia/translations/et.json +++ b/homeassistant/components/iqvia/translations/et.json @@ -3,8 +3,15 @@ "abort": { "already_configured": "Teenus on juba seadistatud" }, + "error": { + "invalid_zip_code": "Sihtnumber ei sobi" + }, "step": { "user": { + "data": { + "zip_code": "Sihtnumber" + }, + "description": "Sisesta oma USA v\u00f5i Kanada sihtnumber.", "title": "" } } diff --git a/homeassistant/components/iqvia/translations/nl.json b/homeassistant/components/iqvia/translations/nl.json index 9ecd9f12f11..753e35c74ea 100644 --- a/homeassistant/components/iqvia/translations/nl.json +++ b/homeassistant/components/iqvia/translations/nl.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Service is al geconfigureerd" + }, "error": { "invalid_zip_code": "Postcode is ongeldig" }, diff --git a/homeassistant/components/islamic_prayer_times/translations/ca.json b/homeassistant/components/islamic_prayer_times/translations/ca.json index 436534f1a3b..e855628541b 100644 --- a/homeassistant/components/islamic_prayer_times/translations/ca.json +++ b/homeassistant/components/islamic_prayer_times/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/cs.json b/homeassistant/components/islamic_prayer_times/translations/cs.json index f48b2736bfa..c0b1be7c08a 100644 --- a/homeassistant/components/islamic_prayer_times/translations/cs.json +++ b/homeassistant/components/islamic_prayer_times/translations/cs.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/de.json b/homeassistant/components/islamic_prayer_times/translations/de.json index 85020d2bf51..af38303c9a2 100644 --- a/homeassistant/components/islamic_prayer_times/translations/de.json +++ b/homeassistant/components/islamic_prayer_times/translations/de.json @@ -1,8 +1,3 @@ { - "config": { - "abort": { - "one_instance_allowed": "Es ist nur eine einzige Instanz erforderlich." - } - }, "title": "Islamische Gebetszeiten" } \ No newline at end of file diff --git a/homeassistant/components/islamic_prayer_times/translations/en.json b/homeassistant/components/islamic_prayer_times/translations/en.json index e028ee8fdf6..502800cfc72 100644 --- a/homeassistant/components/islamic_prayer_times/translations/en.json +++ b/homeassistant/components/islamic_prayer_times/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Already configured. Only a single configuration possible.", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/es-419.json b/homeassistant/components/islamic_prayer_times/translations/es-419.json index 2a5105a4054..9df22e5fce1 100644 --- a/homeassistant/components/islamic_prayer_times/translations/es-419.json +++ b/homeassistant/components/islamic_prayer_times/translations/es-419.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Solo una instancia es necesaria." - }, "step": { "user": { "description": "\u00bfDesea establecer tiempos de oraci\u00f3n isl\u00e1mica?", diff --git a/homeassistant/components/islamic_prayer_times/translations/es.json b/homeassistant/components/islamic_prayer_times/translations/es.json index 6460d121f60..00a65de8c18 100644 --- a/homeassistant/components/islamic_prayer_times/translations/es.json +++ b/homeassistant/components/islamic_prayer_times/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/et.json b/homeassistant/components/islamic_prayer_times/translations/et.json index 0557547563e..01df356f422 100644 --- a/homeassistant/components/islamic_prayer_times/translations/et.json +++ b/homeassistant/components/islamic_prayer_times/translations/et.json @@ -1,13 +1,23 @@ { "config": { "abort": { - "one_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "step": { "user": { - "description": "Kas soovitd seadistada Islam Prayer Times?" + "description": "Kas soovitd seadistada Islam Prayer Times?", + "title": "Seadista Islamic Prayer Times" } } - } + }, + "options": { + "step": { + "init": { + "data": { + "calculation_method": "Palve arvutamise meetod" + } + } + } + }, + "title": "" } \ No newline at end of file diff --git a/homeassistant/components/islamic_prayer_times/translations/fr.json b/homeassistant/components/islamic_prayer_times/translations/fr.json index 6270620a412..3a5c6d01668 100644 --- a/homeassistant/components/islamic_prayer_times/translations/fr.json +++ b/homeassistant/components/islamic_prayer_times/translations/fr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/it.json b/homeassistant/components/islamic_prayer_times/translations/it.json index a8a5f389f90..256746291d8 100644 --- a/homeassistant/components/islamic_prayer_times/translations/it.json +++ b/homeassistant/components/islamic_prayer_times/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/ko.json b/homeassistant/components/islamic_prayer_times/translations/ko.json index 300e4661795..52ac6869855 100644 --- a/homeassistant/components/islamic_prayer_times/translations/ko.json +++ b/homeassistant/components/islamic_prayer_times/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "step": { "user": { "description": "\uc774\uc2ac\ub78c \uae30\ub3c4 \uc2dc\uac04\uc744 \uc124\uc815\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?", diff --git a/homeassistant/components/islamic_prayer_times/translations/lb.json b/homeassistant/components/islamic_prayer_times/translations/lb.json index 20cec66ded5..34597f61fcc 100644 --- a/homeassistant/components/islamic_prayer_times/translations/lb.json +++ b/homeassistant/components/islamic_prayer_times/translations/lb.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/nl.json b/homeassistant/components/islamic_prayer_times/translations/nl.json index 9cfc67e2049..387a519ee92 100644 --- a/homeassistant/components/islamic_prayer_times/translations/nl.json +++ b/homeassistant/components/islamic_prayer_times/translations/nl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Slechts \u00e9\u00e9n exemplaar is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/no.json b/homeassistant/components/islamic_prayer_times/translations/no.json index 5fc3230390e..39fde298873 100644 --- a/homeassistant/components/islamic_prayer_times/translations/no.json +++ b/homeassistant/components/islamic_prayer_times/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/pl.json b/homeassistant/components/islamic_prayer_times/translations/pl.json index b203b6096a8..7a6b7a6f3eb 100644 --- a/homeassistant/components/islamic_prayer_times/translations/pl.json +++ b/homeassistant/components/islamic_prayer_times/translations/pl.json @@ -1,13 +1,12 @@ { "config": { "abort": { - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "step": { "user": { - "description": "Czy chcesz skonfigurowa\u0107 Islamskie czasy modlitwy?", - "title": "Skonfiguruj Islamskie czasy modlitwy" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", + "title": "Konfiguracja Islamskich czas\u00f3w modlitwy" } } }, diff --git a/homeassistant/components/islamic_prayer_times/translations/pt-BR.json b/homeassistant/components/islamic_prayer_times/translations/pt-BR.json deleted file mode 100644 index ee9946cf834..00000000000 --- a/homeassistant/components/islamic_prayer_times/translations/pt-BR.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "abort": { - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - } - } -} \ No newline at end of file diff --git a/homeassistant/components/islamic_prayer_times/translations/ru.json b/homeassistant/components/islamic_prayer_times/translations/ru.json index 696671eeb7e..23761a66170 100644 --- a/homeassistant/components/islamic_prayer_times/translations/ru.json +++ b/homeassistant/components/islamic_prayer_times/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "step": { diff --git a/homeassistant/components/islamic_prayer_times/translations/sl.json b/homeassistant/components/islamic_prayer_times/translations/sl.json index 6cef11fccac..1222c185d24 100644 --- a/homeassistant/components/islamic_prayer_times/translations/sl.json +++ b/homeassistant/components/islamic_prayer_times/translations/sl.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "step": { "user": { "description": "Ali \u017eelite nastaviti Islamski \u010das molitve?", diff --git a/homeassistant/components/islamic_prayer_times/translations/zh-Hant.json b/homeassistant/components/islamic_prayer_times/translations/zh-Hant.json index 2a2325bfc35..b94faab25c0 100644 --- a/homeassistant/components/islamic_prayer_times/translations/zh-Hant.json +++ b/homeassistant/components/islamic_prayer_times/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "step": { diff --git a/homeassistant/components/isy994/const.py b/homeassistant/components/isy994/const.py index 3b129776b31..ef75a974377 100644 --- a/homeassistant/components/isy994/const.py +++ b/homeassistant/components/isy994/const.py @@ -44,13 +44,14 @@ from homeassistant.components.lock import DOMAIN as LOCK from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.components.switch import DOMAIN as SWITCH from homeassistant.const import ( - AREA_SQUARE_METERS, CONCENTRATION_PARTS_PER_MILLION, CURRENCY_CENT, CURRENCY_DOLLAR, DEGREE, ENERGY_KILO_WATT_HOUR, + ENERGY_WATT_HOUR, FREQUENCY_HERTZ, + IRRADIATION_WATTS_PER_SQUARE_METER, LENGTH_CENTIMETERS, LENGTH_FEET, LENGTH_INCHES, @@ -62,15 +63,20 @@ from homeassistant.const import ( MASS_KILOGRAMS, MASS_POUNDS, PERCENTAGE, + POWER_KILO_WATT, POWER_WATT, + PRECIPITATION_MILLIMETERS_PER_HOUR, PRESSURE_HPA, PRESSURE_INHG, PRESSURE_MBAR, SERVICE_LOCK, SERVICE_UNLOCK, + SPEED_INCHES_PER_DAY, + SPEED_INCHES_PER_HOUR, SPEED_KILOMETERS_PER_HOUR, SPEED_METERS_PER_SECOND, SPEED_MILES_PER_HOUR, + SPEED_MILLIMETERS_PER_DAY, STATE_CLOSED, STATE_CLOSING, STATE_LOCKED, @@ -95,6 +101,8 @@ from homeassistant.const import ( VOLT, VOLUME_CUBIC_FEET, VOLUME_CUBIC_METERS, + VOLUME_FLOW_RATE_CUBIC_FEET_PER_MINUTE, + VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, VOLUME_GALLONS, VOLUME_LITERS, ) @@ -193,6 +201,7 @@ UOM_HVAC_MODE_INSTEON = "98" UOM_FAN_MODES = "99" UOM_INDEX = "25" UOM_ON_OFF = "2" +UOM_PERCENTAGE = "51" # Do not use the Home Assistant consts for the states here - we're matching exact API # responses, not using them for Home Assistant states @@ -327,8 +336,8 @@ UOM_FRIENDLY_NAME = { "4": TEMP_CELSIUS, "5": LENGTH_CENTIMETERS, "6": VOLUME_CUBIC_FEET, - "7": f"{VOLUME_CUBIC_FEET}/{TIME_MINUTES}", - "8": f"{VOLUME_CUBIC_METERS}", + "7": VOLUME_FLOW_RATE_CUBIC_FEET_PER_MINUTE, + "8": VOLUME_CUBIC_METERS, "9": TIME_DAYS, "10": TIME_DAYS, "12": "dB", @@ -342,13 +351,13 @@ UOM_FRIENDLY_NAME = { "21": "%AH", "22": "%RH", "23": PRESSURE_INHG, - "24": f"{LENGTH_INCHES}/{TIME_HOURS}", + "24": SPEED_INCHES_PER_HOUR, UOM_INDEX: "index", # Index type. Use "node.formatted" for value "26": TEMP_KELVIN, "27": "keyword", "28": MASS_KILOGRAMS, "29": "kV", - "30": "kW", + "30": POWER_KILO_WATT, "31": "kPa", "32": SPEED_KILOMETERS_PER_HOUR, "33": ENERGY_KILO_WATT_HOUR, @@ -357,19 +366,19 @@ UOM_FRIENDLY_NAME = { "36": LIGHT_LUX, "37": "mercalli", "38": LENGTH_METERS, - "39": f"{VOLUME_CUBIC_METERS}/{TIME_HOURS}", + "39": VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, "40": SPEED_METERS_PER_SECOND, "41": "mA", "42": TIME_MILLISECONDS, "43": "mV", "44": TIME_MINUTES, "45": TIME_MINUTES, - "46": f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", + "46": PRECIPITATION_MILLIMETERS_PER_HOUR, "47": TIME_MONTHS, "48": SPEED_MILES_PER_HOUR, "49": SPEED_METERS_PER_SECOND, "50": "Ω", - "51": PERCENTAGE, + UOM_PERCENTAGE: PERCENTAGE, "52": MASS_POUNDS, "53": "pf", "54": CONCENTRATION_PARTS_PER_MILLION, @@ -387,7 +396,7 @@ UOM_FRIENDLY_NAME = { "71": UV_INDEX, "72": VOLT, "73": POWER_WATT, - "74": f"{POWER_WATT}/{AREA_SQUARE_METERS}", + "74": IRRADIATION_WATTS_PER_SQUARE_METER, "75": "weekday", "76": DEGREE, "77": TIME_YEARS, @@ -407,7 +416,7 @@ UOM_FRIENDLY_NAME = { "103": CURRENCY_DOLLAR, "104": CURRENCY_CENT, "105": LENGTH_INCHES, - "106": f"{LENGTH_MILLIMETERS}/{TIME_DAYS}", + "106": SPEED_MILLIMETERS_PER_DAY, "107": "", # raw 1-byte unsigned value "108": "", # raw 2-byte unsigned value "109": "", # raw 3-byte unsigned value @@ -419,8 +428,8 @@ UOM_FRIENDLY_NAME = { "116": LENGTH_MILES, "117": PRESSURE_MBAR, "118": PRESSURE_HPA, - "119": f"{POWER_WATT}{TIME_HOURS}", - "120": f"{LENGTH_INCHES}/{TIME_DAYS}", + "119": ENERGY_WATT_HOUR, + "120": SPEED_INCHES_PER_DAY, } UOM_TO_STATES = { diff --git a/homeassistant/components/isy994/cover.py b/homeassistant/components/isy994/cover.py index 51a26585778..bdc2bc7f6d4 100644 --- a/homeassistant/components/isy994/cover.py +++ b/homeassistant/components/isy994/cover.py @@ -53,7 +53,7 @@ class ISYCoverEntity(ISYNodeEntity, CoverEntity): if self._node.status == ISY_VALUE_UNKNOWN: return None if self._node.uom == UOM_8_BIT_RANGE: - return int(self._node.status * 100 / 255) + return round(self._node.status * 100.0 / 255.0) return sorted((0, self._node.status, 100))[1] @property @@ -83,7 +83,7 @@ class ISYCoverEntity(ISYNodeEntity, CoverEntity): """Move the cover to a specific position.""" position = kwargs[ATTR_POSITION] if self._node.uom == UOM_8_BIT_RANGE: - position = int(position * 255 / 100) + position = round(position * 255.0 / 100.0) if not self._node.turn_on(val=position): _LOGGER.error("Unable to set cover position") diff --git a/homeassistant/components/isy994/light.py b/homeassistant/components/isy994/light.py index 7f94c68714d..7ff44863f6b 100644 --- a/homeassistant/components/isy994/light.py +++ b/homeassistant/components/isy994/light.py @@ -17,6 +17,7 @@ from .const import ( CONF_RESTORE_LIGHT_STATE, DOMAIN as ISY994_DOMAIN, ISY994_NODES, + UOM_PERCENTAGE, ) from .entity import ISYNodeEntity from .helpers import migrate_old_unique_ids @@ -65,6 +66,9 @@ class ISYLightEntity(ISYNodeEntity, LightEntity, RestoreEntity): """Get the brightness of the ISY994 light.""" if self._node.status == ISY_VALUE_UNKNOWN: return None + # Special Case for ISY Z-Wave Devices using % instead of 0-255: + if self._node.uom == UOM_PERCENTAGE: + return round(self._node.status * 255.0 / 100.0) return int(self._node.status) def turn_off(self, **kwargs) -> None: @@ -76,7 +80,10 @@ class ISYLightEntity(ISYNodeEntity, LightEntity, RestoreEntity): def on_update(self, event: object) -> None: """Save brightness in the update event from the ISY994 Node.""" if self._node.status not in (0, ISY_VALUE_UNKNOWN): - self._last_brightness = self._node.status + if self._node.uom == UOM_PERCENTAGE: + self._last_brightness = round(self._node.status * 255.0 / 100.0) + else: + self._last_brightness = self._node.status super().on_update(event) # pylint: disable=arguments-differ @@ -84,6 +91,9 @@ class ISYLightEntity(ISYNodeEntity, LightEntity, RestoreEntity): """Send the turn on command to the ISY994 light device.""" if self._restore_light_state and brightness is None and self._last_brightness: brightness = self._last_brightness + # Special Case for ISY Z-Wave Devices using % instead of 0-255: + if brightness is not None and self._node.uom == UOM_PERCENTAGE: + brightness = round(brightness * 100.0 / 255.0) if not self._node.turn_on(val=brightness): _LOGGER.debug("Unable to turn on light") diff --git a/homeassistant/components/isy994/services.py b/homeassistant/components/isy994/services.py index ee12cedbca4..3e9e0ae1d29 100644 --- a/homeassistant/components/isy994/services.py +++ b/homeassistant/components/isy994/services.py @@ -87,7 +87,7 @@ VALID_PROGRAM_COMMANDS = [ def valid_isy_commands(value: Any) -> str: """Validate the command is valid.""" value = str(value).upper() - if value in COMMAND_FRIENDLY_NAME.keys(): + if value in COMMAND_FRIENDLY_NAME: return value raise vol.Invalid("Invalid ISY Command.") @@ -162,7 +162,7 @@ def async_setup_services(hass: HomeAssistantType): """Create and register services for the ISY integration.""" existing_services = hass.services.async_services().get(DOMAIN) if existing_services and any( - service in INTEGRATION_SERVICES for service in existing_services.keys() + service in INTEGRATION_SERVICES for service in existing_services ): # Integration-level services have already been added. Return. return @@ -388,7 +388,7 @@ def async_unload_services(hass: HomeAssistantType): existing_services = hass.services.async_services().get(DOMAIN) if not existing_services or not any( - service in INTEGRATION_SERVICES for service in existing_services.keys() + service in INTEGRATION_SERVICES for service in existing_services ): return diff --git a/homeassistant/components/isy994/strings.json b/homeassistant/components/isy994/strings.json index 18e08b65009..b08b40ac0c5 100644 --- a/homeassistant/components/isy994/strings.json +++ b/homeassistant/components/isy994/strings.json @@ -1,5 +1,4 @@ { - "title": "Universal Devices ISY994", "config": { "flow_title": "Universal Devices ISY994 {name} ({host})", "step": { diff --git a/homeassistant/components/isy994/translations/ca.json b/homeassistant/components/isy994/translations/ca.json index 1fd7c21793e..d8d5911e871 100644 --- a/homeassistant/components/isy994/translations/ca.json +++ b/homeassistant/components/isy994/translations/ca.json @@ -36,6 +36,5 @@ "title": "Opcions d'ISY994" } } - }, - "title": "Dispositius universals ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/cs.json b/homeassistant/components/isy994/translations/cs.json index f5024d177fd..e2d3dc4c883 100644 --- a/homeassistant/components/isy994/translations/cs.json +++ b/homeassistant/components/isy994/translations/cs.json @@ -6,6 +6,7 @@ "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", + "invalid_host": "Z\u00e1znam hostitele nebyl v \u00fapln\u00e9m form\u00e1tu URL, nap\u0159. http://192.168.10.100:80", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { @@ -13,8 +14,10 @@ "data": { "host": "URL", "password": "Heslo", + "tls": "Verze TLS ovlada\u010de ISY.", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" }, + "description": "Polo\u017eka hostitele mus\u00ed b\u00fdt v \u00fapln\u00e9m form\u00e1tu URL, nap\u0159 http://192.168.10.100:80.", "title": "P\u0159ipojen\u00ed k ISY994" } } diff --git a/homeassistant/components/isy994/translations/en.json b/homeassistant/components/isy994/translations/en.json index 61fe07fd1fc..a2c71fbfd95 100644 --- a/homeassistant/components/isy994/translations/en.json +++ b/homeassistant/components/isy994/translations/en.json @@ -36,6 +36,5 @@ "title": "ISY994 Options" } } - }, - "title": "Universal Devices ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/es.json b/homeassistant/components/isy994/translations/es.json index 23ed579d473..06824938c9d 100644 --- a/homeassistant/components/isy994/translations/es.json +++ b/homeassistant/components/isy994/translations/es.json @@ -36,6 +36,5 @@ "title": "Opciones ISY994" } } - }, - "title": "Dispositivos Universales ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/et.json b/homeassistant/components/isy994/translations/et.json index 4554a58c3ff..010e5ec9a03 100644 --- a/homeassistant/components/isy994/translations/et.json +++ b/homeassistant/components/isy994/translations/et.json @@ -9,15 +9,32 @@ "invalid_host": "Hostikirje ei olnud sobivas URL-vormingus, nt http://192.168.10.100:80", "unknown": "Tundmatu viga" }, + "flow_title": "", "step": { "user": { "data": { "host": "", "password": "Salas\u00f5na", + "tls": "ISY kontrolleri TLS-versioon.", "username": "Kasutajanimi" - } + }, + "description": "Hostikirje peab olema t\u00e4ielikus URL-vormingus, nt http://192.168.10.100:80", + "title": "\u00dchendu oma ISY994-ga" } } }, - "title": "" + "options": { + "step": { + "init": { + "data": { + "ignore_string": "Eira stringi", + "restore_light_state": "Taasta valguse heledus", + "sensor_string": "S\u00f5lme anduri string", + "variable_sensor_string": "Muutuja sensori string" + }, + "description": "Isy isidumisei suvandite m\u00e4\u00e4ramine: \n \u2022 S\u00f5lme sensor string: iga seade v\u00f5i kaust, mis sisaldab nimes \"Node Sensor String\" k\u00e4sitletakse sensorina v\u00f5i binaarandurina. \n \u2022 Ignoreeri stringi: iga seadet, mille nimes on \"Ignore String\", ignoreeritakse. \n \u2022 Muutuv sensorstring: andurina lisatakse k\u00f5ik muutujad, mis sisaldavad \"Variable Sensor String\". \n \u2022 Valguse heleduse taastamine: kui see on lubatud, taastatakse eelmine heledus, kui l\u00fclitate sisse seadme sisseehitatud taseme asemel valguse.", + "title": "ISY994 valikud" + } + } + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/fi.json b/homeassistant/components/isy994/translations/fi.json index c5b20ac47a4..73919f4aa3e 100644 --- a/homeassistant/components/isy994/translations/fi.json +++ b/homeassistant/components/isy994/translations/fi.json @@ -25,6 +25,5 @@ "title": "ISY994-asetukset" } } - }, - "title": "Universaalit laitteet ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/fr.json b/homeassistant/components/isy994/translations/fr.json index 5afaf2ad830..01f2145cd12 100644 --- a/homeassistant/components/isy994/translations/fr.json +++ b/homeassistant/components/isy994/translations/fr.json @@ -36,6 +36,5 @@ "title": "Options ISY994" } } - }, - "title": "Universal Devices ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/it.json b/homeassistant/components/isy994/translations/it.json index 9b35a464c1b..77d9f8206bd 100644 --- a/homeassistant/components/isy994/translations/it.json +++ b/homeassistant/components/isy994/translations/it.json @@ -36,6 +36,5 @@ "title": "Opzioni ISY994" } } - }, - "title": "Universal Devices ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/ko.json b/homeassistant/components/isy994/translations/ko.json index 289609adbf7..b8c80f1ee74 100644 --- a/homeassistant/components/isy994/translations/ko.json +++ b/homeassistant/components/isy994/translations/ko.json @@ -36,6 +36,5 @@ "title": "ISY994 \uc635\uc158" } } - }, - "title": "ISY994 \ubc94\uc6a9 \uae30\uae30" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/lb.json b/homeassistant/components/isy994/translations/lb.json index b60ce03e43a..d1c7d5fecf5 100644 --- a/homeassistant/components/isy994/translations/lb.json +++ b/homeassistant/components/isy994/translations/lb.json @@ -36,6 +36,5 @@ "title": "ISY994 Optiounen" } } - }, - "title": "Universal Devices ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/nl.json b/homeassistant/components/isy994/translations/nl.json index d22d721de0f..d263815158a 100644 --- a/homeassistant/components/isy994/translations/nl.json +++ b/homeassistant/components/isy994/translations/nl.json @@ -1,12 +1,38 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "invalid_host": "De hostvermelding had de niet volledig URL-indeling, bijvoorbeeld http://192.168.10.100:80", + "unknown": "Onverwachte fout" + }, "flow_title": "Universele apparaten ISY994 {name} ({host})", "step": { "user": { "data": { "host": "URL", + "password": "Wachtwoord", + "tls": "De TLS-versie van de ISY-controller.", "username": "Gebruikersnaam" - } + }, + "description": "Het hostvermelding moet de volledige URL-indeling hebben, bijvoorbeeld http://192.168.10.100:80", + "title": "Maak verbinding met uw ISY994" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "ignore_string": "Tekenreeks negeren", + "restore_light_state": "Herstel lichthelderheid", + "sensor_string": "Node Sensor String" + }, + "description": "Stel de opties in voor de ISY-integratie:\n \u2022 Node Sensor String: elk apparaat of elke map die 'Node Sensor String' in de naam bevat, wordt behandeld als een sensor of binaire sensor.\n \u2022 Ignore String: elk apparaat met 'Ignore String' in de naam wordt genegeerd.\n \u2022 Variabele sensorreeks: elke variabele die 'Variabele sensorreeks' bevat, wordt als sensor toegevoegd.\n \u2022 Lichthelderheid herstellen: indien ingeschakeld, wordt de vorige helderheid hersteld wanneer u een lamp inschakelt in plaats van het ingebouwde Aan-niveau van het apparaat.", + "title": "ISY994-opties" } } } diff --git a/homeassistant/components/isy994/translations/no.json b/homeassistant/components/isy994/translations/no.json index 694669d7864..422c8fb7c9d 100644 --- a/homeassistant/components/isy994/translations/no.json +++ b/homeassistant/components/isy994/translations/no.json @@ -36,6 +36,5 @@ "title": "ISY994 Alternativer" } } - }, - "title": "Universelle enheter ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/pl.json b/homeassistant/components/isy994/translations/pl.json index b4c9bfa639e..532d0a72cd5 100644 --- a/homeassistant/components/isy994/translations/pl.json +++ b/homeassistant/components/isy994/translations/pl.json @@ -36,6 +36,5 @@ "title": "Opcje ISY994" } } - }, - "title": "Urz\u0105dzenia uniwersalne ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/pt-BR.json b/homeassistant/components/isy994/translations/pt-BR.json index 090e9a21530..2bc8cd2ef5a 100644 --- a/homeassistant/components/isy994/translations/pt-BR.json +++ b/homeassistant/components/isy994/translations/pt-BR.json @@ -28,6 +28,5 @@ "title": "ISY994 Op\u00e7\u00f5es" } } - }, - "title": "Dispositivos universais ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/ru.json b/homeassistant/components/isy994/translations/ru.json index b6222417295..c0a658423c6 100644 --- a/homeassistant/components/isy994/translations/ru.json +++ b/homeassistant/components/isy994/translations/ru.json @@ -36,6 +36,5 @@ "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 ISY994" } } - }, - "title": "Universal Devices ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/isy994/translations/zh-Hant.json b/homeassistant/components/isy994/translations/zh-Hant.json index 4327cca65e4..43b43661b6d 100644 --- a/homeassistant/components/isy994/translations/zh-Hant.json +++ b/homeassistant/components/isy994/translations/zh-Hant.json @@ -36,6 +36,5 @@ "title": "ISY994 \u9078\u9805" } } - }, - "title": "Universal Devices ISY994" + } } \ No newline at end of file diff --git a/homeassistant/components/izone/climate.py b/homeassistant/components/izone/climate.py index cd14d1cadcf..443a80298f1 100644 --- a/homeassistant/components/izone/climate.py +++ b/homeassistant/components/izone/climate.py @@ -509,7 +509,7 @@ class ZoneDevice(ClimateEntity): @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/izone/translations/lb.json b/homeassistant/components/izone/translations/lb.json index 2c8f2573e75..71929531601 100644 --- a/homeassistant/components/izone/translations/lb.json +++ b/homeassistant/components/izone/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "no_devices_found": "Keng iZone Apparater am Netzwierk fonnt.", - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun iZone ass n\u00e9ideg." + "no_devices_found": "Keng Apparater am Netzwierk fonnt.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "confirm": { diff --git a/homeassistant/components/izone/translations/pl.json b/homeassistant/components/izone/translations/pl.json index 38a2b3858fc..a8ee3fa57ac 100644 --- a/homeassistant/components/izone/translations/pl.json +++ b/homeassistant/components/izone/translations/pl.json @@ -6,7 +6,7 @@ }, "step": { "confirm": { - "description": "Chcesz skonfigurowa\u0107 iZone?" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } } diff --git a/homeassistant/components/jewish_calendar/sensor.py b/homeassistant/components/jewish_calendar/sensor.py index 7b3a3af9c11..6881f29b963 100644 --- a/homeassistant/components/jewish_calendar/sensor.py +++ b/homeassistant/components/jewish_calendar/sensor.py @@ -3,7 +3,7 @@ import logging import hdate -from homeassistant.const import SUN_EVENT_SUNSET +from homeassistant.const import DEVICE_CLASS_TIMESTAMP, SUN_EVENT_SUNSET from homeassistant.helpers.entity import Entity from homeassistant.helpers.sun import get_astral_event_date import homeassistant.util.dt as dt_util @@ -150,7 +150,7 @@ class JewishCalendarTimeSensor(JewishCalendarSensor): @property def device_class(self): """Return the class of this sensor.""" - return "timestamp" + return DEVICE_CLASS_TIMESTAMP @property def device_state_attributes(self): @@ -160,8 +160,6 @@ class JewishCalendarTimeSensor(JewishCalendarSensor): if self._state is None: return attrs - attrs["timestamp"] = self._state.timestamp() - return attrs def get_state(self, daytime_date, after_shkia_date, after_tzais_date): diff --git a/homeassistant/components/juicenet/translations/et.json b/homeassistant/components/juicenet/translations/et.json index aecf63a3b9b..872626c35aa 100644 --- a/homeassistant/components/juicenet/translations/et.json +++ b/homeassistant/components/juicenet/translations/et.json @@ -12,7 +12,9 @@ "user": { "data": { "api_token": "API string" - } + }, + "description": "Vaja on https://home.juice.net/Manage API luba.", + "title": "Loo \u00fchendus JuiceNet-iga" } } } diff --git a/homeassistant/components/juicenet/translations/lb.json b/homeassistant/components/juicenet/translations/lb.json index d4b1fb22bf8..9d9d4c4cbaa 100644 --- a/homeassistant/components/juicenet/translations/lb.json +++ b/homeassistant/components/juicenet/translations/lb.json @@ -1,17 +1,17 @@ { "config": { "abort": { - "already_configured": "D\u00ebse JuiceNet Kont ass scho konfigur\u00e9iert" + "already_configured": "Kont ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, "step": { "user": { "data": { - "api_token": "JuiceNet API Jeton" + "api_token": "API Jeton" }, "description": "Du brauchs een API Schl\u00ebssel vun https://home.juice.net/Manage.", "title": "Mat JuiceNet verbannen" diff --git a/homeassistant/components/juicenet/translations/nl.json b/homeassistant/components/juicenet/translations/nl.json index 42978a06b37..5f1b0d37e25 100644 --- a/homeassistant/components/juicenet/translations/nl.json +++ b/homeassistant/components/juicenet/translations/nl.json @@ -2,6 +2,20 @@ "config": { "abort": { "already_configured": "Account is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, + "step": { + "user": { + "data": { + "api_token": "API-token" + }, + "description": "U hebt het API-token nodig van https://home.juice.net/Manage.", + "title": "Maak verbinding met JuiceNet" + } } } } \ No newline at end of file diff --git a/homeassistant/components/knx/binary_sensor.py b/homeassistant/components/knx/binary_sensor.py index a62e95f1def..35feb09dc1d 100644 --- a/homeassistant/components/knx/binary_sensor.py +++ b/homeassistant/components/knx/binary_sensor.py @@ -41,3 +41,13 @@ class KNXBinarySensor(KnxEntity, BinarySensorEntity): def device_state_attributes(self) -> Optional[Dict[str, Any]]: """Return device specific state attributes.""" return {ATTR_COUNTER: self._device.counter} + + @property + def force_update(self) -> bool: + """ + Return True if state updates should be forced. + + If True, a state change will be triggered anytime the state property is + updated, not just when the value changes. + """ + return self._device.ignore_internal_state diff --git a/homeassistant/components/knx/climate.py b/homeassistant/components/knx/climate.py index 1960627a8d6..070f635cc48 100644 --- a/homeassistant/components/knx/climate.py +++ b/homeassistant/components/knx/climate.py @@ -2,7 +2,7 @@ from typing import List, Optional from xknx.devices import Climate as XknxClimate -from xknx.dpt import HVACOperationMode +from xknx.dpt import HVACControllerMode, HVACOperationMode from homeassistant.components.climate import ClimateEntity from homeassistant.components.climate.const import ( @@ -14,11 +14,11 @@ from homeassistant.components.climate.const import ( ) from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS -from .const import DOMAIN, OPERATION_MODES, PRESET_MODES +from .const import CONTROLLER_MODES, DOMAIN, PRESET_MODES from .knx_entity import KnxEntity -OPERATION_MODES_INV = dict(reversed(item) for item in OPERATION_MODES.items()) -PRESET_MODES_INV = dict(reversed(item) for item in PRESET_MODES.items()) +CONTROLLER_MODES_INV = {value: key for key, value in CONTROLLER_MODES.items()} +PRESET_MODES_INV = {value: key for key, value in PRESET_MODES.items()} async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): @@ -92,27 +92,27 @@ class KNXClimate(KnxEntity, ClimateEntity): """Return current operation ie. heat, cool, idle.""" if self._device.supports_on_off and not self._device.is_on: return HVAC_MODE_OFF - if self._device.mode.supports_operation_mode: - return OPERATION_MODES.get( - self._device.mode.operation_mode.value, HVAC_MODE_HEAT + if self._device.mode.supports_controller_mode: + return CONTROLLER_MODES.get( + self._device.mode.controller_mode.value, HVAC_MODE_HEAT ) # default to "heat" return HVAC_MODE_HEAT @property def hvac_modes(self) -> Optional[List[str]]: - """Return the list of available operation modes.""" - _operations = [ - OPERATION_MODES.get(operation_mode.value) - for operation_mode in self._device.mode.operation_modes + """Return the list of available operation/controller modes.""" + _controller_modes = [ + CONTROLLER_MODES.get(controller_mode.value) + for controller_mode in self._device.mode.controller_modes ] if self._device.supports_on_off: - if not _operations: - _operations.append(HVAC_MODE_HEAT) - _operations.append(HVAC_MODE_OFF) + if not _controller_modes: + _controller_modes.append(HVAC_MODE_HEAT) + _controller_modes.append(HVAC_MODE_OFF) - _modes = list(set(filter(None, _operations))) + _modes = list(set(filter(None, _controller_modes))) # default to ["heat"] return _modes if _modes else [HVAC_MODE_HEAT] @@ -123,11 +123,11 @@ class KNXClimate(KnxEntity, ClimateEntity): else: if self._device.supports_on_off and not self._device.is_on: await self._device.turn_on() - if self._device.mode.supports_operation_mode: - knx_operation_mode = HVACOperationMode( - OPERATION_MODES_INV.get(hvac_mode) + if self._device.mode.supports_controller_mode: + knx_controller_mode = HVACControllerMode( + CONTROLLER_MODES_INV.get(hvac_mode) ) - await self._device.mode.set_operation_mode(knx_operation_mode) + await self._device.mode.set_controller_mode(knx_controller_mode) self.async_write_ha_state() @property diff --git a/homeassistant/components/knx/const.py b/homeassistant/components/knx/const.py index 8b0dd90393b..e434aed395d 100644 --- a/homeassistant/components/knx/const.py +++ b/homeassistant/components/knx/const.py @@ -11,13 +11,16 @@ from homeassistant.components.climate.const import ( PRESET_AWAY, PRESET_COMFORT, PRESET_ECO, + PRESET_NONE, PRESET_SLEEP, ) DOMAIN = "knx" +CONF_INVERT = "invert" CONF_STATE_ADDRESS = "state_address" CONF_SYNC_STATE = "sync_state" +CONF_RESET_AFTER = "reset_after" class ColorTempModes(Enum): @@ -41,8 +44,8 @@ class SupportedPlatforms(Enum): weather = "weather" -# Map KNX operation modes to HA modes. This list might not be complete. -OPERATION_MODES = { +# Map KNX controller modes to HA modes. This list might not be complete. +CONTROLLER_MODES = { # Map DPT 20.105 HVAC control modes "Auto": HVAC_MODE_AUTO, "Heat": HVAC_MODE_HEAT, @@ -54,6 +57,7 @@ OPERATION_MODES = { PRESET_MODES = { # Map DPT 20.102 HVAC operating modes to HA presets + "Auto": PRESET_NONE, "Frost Protection": PRESET_ECO, "Night": PRESET_SLEEP, "Standby": PRESET_AWAY, diff --git a/homeassistant/components/knx/factory.py b/homeassistant/components/knx/factory.py index 3334e49ce38..6da2b73cd6a 100644 --- a/homeassistant/components/knx/factory.py +++ b/homeassistant/components/knx/factory.py @@ -164,6 +164,7 @@ def _create_climate(knx_module: XKNX, config: ConfigType) -> XknxClimate: ClimateSchema.CONF_HEAT_COOL_STATE_ADDRESS ), operation_modes=config.get(ClimateSchema.CONF_OPERATION_MODES), + controller_modes=config.get(ClimateSchema.CONF_CONTROLLER_MODES), ) return XknxClimate( @@ -202,6 +203,7 @@ def _create_switch(knx_module: XKNX, config: ConfigType) -> XknxSwitch: name=config[CONF_NAME], group_address=config[CONF_ADDRESS], group_address_state=config.get(SwitchSchema.CONF_STATE_ADDRESS), + invert=config.get(SwitchSchema.CONF_INVERT), ) @@ -212,6 +214,7 @@ def _create_sensor(knx_module: XKNX, config: ConfigType) -> XknxSensor: name=config[CONF_NAME], group_address_state=config[SensorSchema.CONF_STATE_ADDRESS], sync_state=config[SensorSchema.CONF_SYNC_STATE], + always_callback=config[SensorSchema.CONF_ALWAYS_CALLBACK], value_type=config[CONF_TYPE], ) @@ -243,10 +246,11 @@ def _create_binary_sensor(knx_module: XKNX, config: ConfigType) -> XknxBinarySen knx_module, name=device_name, group_address_state=config[BinarySensorSchema.CONF_STATE_ADDRESS], + invert=config.get(BinarySensorSchema.CONF_INVERT), sync_state=config[BinarySensorSchema.CONF_SYNC_STATE], device_class=config.get(CONF_DEVICE_CLASS), ignore_internal_state=config[BinarySensorSchema.CONF_IGNORE_INTERNAL_STATE], - context_timeout=config[BinarySensorSchema.CONF_CONTEXT_TIMEOUT], + context_timeout=config.get(BinarySensorSchema.CONF_CONTEXT_TIMEOUT), reset_after=config.get(BinarySensorSchema.CONF_RESET_AFTER), ) diff --git a/homeassistant/components/knx/manifest.json b/homeassistant/components/knx/manifest.json index 2d387f0653d..4055048fd2d 100644 --- a/homeassistant/components/knx/manifest.json +++ b/homeassistant/components/knx/manifest.json @@ -2,7 +2,7 @@ "domain": "knx", "name": "KNX", "documentation": "https://www.home-assistant.io/integrations/knx", - "requirements": ["xknx==0.15.0"], + "requirements": ["xknx==0.15.3"], "codeowners": ["@Julius2342", "@farmio", "@marvin-w"], "quality_scale": "silver" } diff --git a/homeassistant/components/knx/schema.py b/homeassistant/components/knx/schema.py index 84a54536db5..cbf06925163 100644 --- a/homeassistant/components/knx/schema.py +++ b/homeassistant/components/knx/schema.py @@ -15,9 +15,11 @@ from homeassistant.const import ( import homeassistant.helpers.config_validation as cv from .const import ( + CONF_INVERT, + CONF_RESET_AFTER, CONF_STATE_ADDRESS, CONF_SYNC_STATE, - OPERATION_MODES, + CONTROLLER_MODES, PRESET_MODES, ColorTempModes, ) @@ -84,9 +86,10 @@ class BinarySensorSchema: CONF_STATE_ADDRESS = CONF_STATE_ADDRESS CONF_SYNC_STATE = CONF_SYNC_STATE + CONF_INVERT = CONF_INVERT CONF_IGNORE_INTERNAL_STATE = "ignore_internal_state" CONF_CONTEXT_TIMEOUT = "context_timeout" - CONF_RESET_AFTER = "reset_after" + CONF_RESET_AFTER = CONF_RESET_AFTER DEFAULT_NAME = "KNX Binary Sensor" @@ -101,12 +104,13 @@ class BinarySensorSchema: cv.boolean, cv.string, ), - vol.Optional(CONF_IGNORE_INTERNAL_STATE, default=True): cv.boolean, - vol.Optional(CONF_CONTEXT_TIMEOUT, default=1.0): vol.All( + vol.Optional(CONF_IGNORE_INTERNAL_STATE, default=False): cv.boolean, + vol.Required(CONF_STATE_ADDRESS): cv.string, + vol.Optional(CONF_CONTEXT_TIMEOUT): vol.All( vol.Coerce(float), vol.Range(min=0, max=10) ), - vol.Required(CONF_STATE_ADDRESS): cv.string, vol.Optional(CONF_DEVICE_CLASS): cv.string, + vol.Optional(CONF_INVERT): cv.boolean, vol.Optional(CONF_RESET_AFTER): cv.positive_int, } ), @@ -187,6 +191,7 @@ class ClimateSchema: CONF_OPERATION_MODE_COMFORT_ADDRESS = "operation_mode_comfort_address" CONF_OPERATION_MODE_STANDBY_ADDRESS = "operation_mode_standby_address" CONF_OPERATION_MODES = "operation_modes" + CONF_CONTROLLER_MODES = "controller_modes" CONF_ON_OFF_ADDRESS = "on_off_address" CONF_ON_OFF_STATE_ADDRESS = "on_off_state_address" CONF_ON_OFF_INVERT = "on_off_invert" @@ -240,7 +245,10 @@ class ClimateSchema: CONF_ON_OFF_INVERT, default=DEFAULT_ON_OFF_INVERT ): cv.boolean, vol.Optional(CONF_OPERATION_MODES): vol.All( - cv.ensure_list, [vol.In({**OPERATION_MODES, **PRESET_MODES})] + cv.ensure_list, [vol.In({**PRESET_MODES})] + ), + vol.Optional(CONF_CONTROLLER_MODES): vol.All( + cv.ensure_list, [vol.In({**CONTROLLER_MODES})] ), vol.Optional(CONF_MIN_TEMP): vol.Coerce(float), vol.Optional(CONF_MAX_TEMP): vol.Coerce(float), @@ -252,6 +260,7 @@ class ClimateSchema: class SwitchSchema: """Voluptuous schema for KNX switches.""" + CONF_INVERT = CONF_INVERT CONF_STATE_ADDRESS = CONF_STATE_ADDRESS DEFAULT_NAME = "KNX Switch" @@ -260,6 +269,7 @@ class SwitchSchema: vol.Required(CONF_ADDRESS): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_STATE_ADDRESS): cv.string, + vol.Optional(CONF_INVERT): cv.boolean, } ) @@ -299,6 +309,7 @@ class NotifySchema: class SensorSchema: """Voluptuous schema for KNX sensors.""" + CONF_ALWAYS_CALLBACK = "always_callback" CONF_STATE_ADDRESS = CONF_STATE_ADDRESS CONF_SYNC_STATE = CONF_SYNC_STATE DEFAULT_NAME = "KNX Sensor" @@ -311,6 +322,7 @@ class SensorSchema: cv.boolean, cv.string, ), + vol.Optional(CONF_ALWAYS_CALLBACK, default=False): cv.boolean, vol.Required(CONF_STATE_ADDRESS): cv.string, vol.Required(CONF_TYPE): vol.Any(int, float, str), } diff --git a/homeassistant/components/knx/sensor.py b/homeassistant/components/knx/sensor.py index fc2cbced8bb..dc9ffcb61b7 100644 --- a/homeassistant/components/knx/sensor.py +++ b/homeassistant/components/knx/sensor.py @@ -41,3 +41,13 @@ class KNXSensor(KnxEntity, Entity): if device_class in DEVICE_CLASSES: return device_class return None + + @property + def force_update(self) -> bool: + """ + Return True if state updates should be forced. + + If True, a state change will be triggered anytime the state property is + updated, not just when the value changes. + """ + return self._device.always_callback diff --git a/homeassistant/components/kodi/translations/ca.json b/homeassistant/components/kodi/translations/ca.json index 09b16682083..8dd03fe9fff 100644 --- a/homeassistant/components/kodi/translations/ca.json +++ b/homeassistant/components/kodi/translations/ca.json @@ -24,14 +24,6 @@ "description": "Vols afegir Kodi (`{name}`) a Home Assistant?", "title": "Kodi descobert" }, - "host": { - "data": { - "host": "Amfitri\u00f3", - "port": "Port", - "ssl": "Connexi\u00f3 mitjan\u00e7ant SSL" - }, - "description": "Informaci\u00f3 de connexi\u00f3 de Kodi. Assegura't d'activar \"Permet el control de Kodi via HTTP\" a Sistema/Configuraci\u00f3/Xarxa/Serveis." - }, "user": { "data": { "host": "Amfitri\u00f3", diff --git a/homeassistant/components/kodi/translations/cs.json b/homeassistant/components/kodi/translations/cs.json index 5075f9e1335..e21c08b0758 100644 --- a/homeassistant/components/kodi/translations/cs.json +++ b/homeassistant/components/kodi/translations/cs.json @@ -21,22 +21,16 @@ "description": "Zadejte sv\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no a heslo pro Kodi. To lze nal\u00e9zt v Syst\u00e9m/Nastaven\u00ed/S\u00ed\u0165/Slu\u017eby." }, "discovery_confirm": { - "description": "Chcete p\u0159idat Kodi (\"{name}\") do Home Assistant?", + "description": "Chcete p\u0159idat Kodi (`{name}`) do Home Assistant?", "title": "Objeven\u00e9 Kodi" }, - "host": { - "data": { - "host": "Hostitel", - "port": "Port", - "ssl": "P\u0159ipojen\u00ed p\u0159es SSL" - } - }, "user": { "data": { "host": "Hostitel", "port": "Port", "ssl": "Pou\u017e\u00edv\u00e1 SSL certifik\u00e1t" - } + }, + "description": "Informace o p\u0159ipojen\u00ed Kodi. Nezapome\u0148te povolit mo\u017enost \"Povolit ovl\u00e1d\u00e1n\u00ed Kodi prost\u0159ednictv\u00edm protokolu HTTP\" v Syst\u00e9m/Nastaven\u00ed/S\u00ed\u0165/Slu\u017eby." }, "ws_port": { "data": { diff --git a/homeassistant/components/kodi/translations/de.json b/homeassistant/components/kodi/translations/de.json index d8db0e86137..f50a90c8a88 100644 --- a/homeassistant/components/kodi/translations/de.json +++ b/homeassistant/components/kodi/translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "cannot_connect": "Verbindung fehlgeschlagen" + }, "flow_title": "Kodi: {name}", "step": { "credentials": { @@ -12,17 +15,11 @@ "discovery_confirm": { "description": "M\u00f6chtest du Kodi (` {name} `) zu Home Assistant hinzuf\u00fcgen?" }, - "host": { - "data": { - "host": "Host", - "port": "Port", - "ssl": "\u00dcber SSL verbinden" - } - }, "user": { "data": { "host": "Host", - "port": "Port" + "port": "Port", + "ssl": "Verwendet ein SSL Zertifikat" } }, "ws_port": { diff --git a/homeassistant/components/kodi/translations/el.json b/homeassistant/components/kodi/translations/el.json index 93b077fbe1d..805490698bb 100644 --- a/homeassistant/components/kodi/translations/el.json +++ b/homeassistant/components/kodi/translations/el.json @@ -9,13 +9,6 @@ "description": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03c0\u03c1\u03bf\u03c3\u03b8\u03ad\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf Kodi ('{name}') \u03c3\u03c4\u03bf Home Assistant;", "title": "\u0391\u03bd\u03b1\u03ba\u03b1\u03bb\u03cd\u03c6\u03b8\u03b7\u03ba\u03b5 Kodi" }, - "host": { - "data": { - "port": "\u0398\u03cd\u03c1\u03b1", - "ssl": "\u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03bc\u03ad\u03c3\u03c9 SSL" - }, - "description": "\u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2 Kodi. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03bf\u03cd\u03bc\u03b5 \u03b2\u03b5\u03b2\u03b1\u03b9\u03c9\u03b8\u03b5\u03af\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03b9 \u03c4\u03bf \"\u039d\u03b1 \u03b5\u03c0\u03b9\u03c4\u03c1\u03ad\u03c0\u03b5\u03c4\u03b1\u03b9 \u03bf \u03ad\u03bb\u03b5\u03b3\u03c7\u03bf\u03c2 \u03c4\u03bf\u03c5 Kodi \u03bc\u03ad\u03c3\u03c9 HTTP\" \u03c3\u03c4\u03bf \u03a3\u03cd\u03c3\u03c4\u03b7\u03bc\u03b1/\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2/\u0394\u03af\u03ba\u03c4\u03c5\u03bf/\u03a5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b5\u03c2." - }, "user": { "data": { "ssl": "\u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03bc\u03ad\u03c3\u03c9 SSL" diff --git a/homeassistant/components/kodi/translations/en.json b/homeassistant/components/kodi/translations/en.json index 0f703057dcf..be87d312146 100644 --- a/homeassistant/components/kodi/translations/en.json +++ b/homeassistant/components/kodi/translations/en.json @@ -24,14 +24,6 @@ "description": "Do you want to add Kodi (`{name}`) to Home Assistant?", "title": "Discovered Kodi" }, - "host": { - "data": { - "host": "Host", - "port": "Port", - "ssl": "Connect over SSL" - }, - "description": "Kodi connection information. Please make sure to enable \"Allow control of Kodi via HTTP\" in System/Settings/Network/Services." - }, "user": { "data": { "host": "Host", diff --git a/homeassistant/components/kodi/translations/es.json b/homeassistant/components/kodi/translations/es.json index 79324509e3b..ddea2a65a2f 100644 --- a/homeassistant/components/kodi/translations/es.json +++ b/homeassistant/components/kodi/translations/es.json @@ -24,14 +24,6 @@ "description": "\u00bfQuieres agregar Kodi (`{name}`) a Home Assistant?", "title": "Descubierto Kodi" }, - "host": { - "data": { - "host": "Host", - "port": "Puerto", - "ssl": "Conectar a trav\u00e9s de SSL" - }, - "description": "Informaci\u00f3n de la conexi\u00f3n de Kodi. Por favor, aseg\u00farese de habilitar \"Permitir el control de Kodi v\u00eda HTTP\" en Sistema/Configuraci\u00f3n/Red/Servicios." - }, "user": { "data": { "host": "Host", diff --git a/homeassistant/components/kodi/translations/et.json b/homeassistant/components/kodi/translations/et.json index 691cc085dd6..a569c470e1d 100644 --- a/homeassistant/components/kodi/translations/et.json +++ b/homeassistant/components/kodi/translations/et.json @@ -11,33 +11,32 @@ "invalid_auth": "Tuvastamine nurjus", "unknown": "Tundmatu viga" }, + "flow_title": "", "step": { "credentials": { "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "description": "Sisesta oma Kodi kasutajanimi ja salas\u00f5na. Need leiad System/Settings/Network/Services." }, "discovery_confirm": { - "description": "Kas soovid lisada Kodi {name} Home Assistanti?" - }, - "host": { - "data": { - "host": "", - "port": "" - } + "description": "Kas soovid lisada Kodi {name} Home Assistanti?", + "title": "Avastatud Kodi seadmed" }, "user": { "data": { "host": "", "port": "", "ssl": "Kasutab SSL serti" - } + }, + "description": "Kodi \u00fchenduse teave. Veendu, et lubaksid jaotises S\u00fcsteem / Seaded / V\u00f5rk / Teenused valiku \"Luba Kodi juhtimine HTTP kaudu\"." }, "ws_port": { "data": { "ws_port": "" - } + }, + "description": "WebSocket'i port (mida Kodis nimetatakse m\u00f5nikord ka TCP-pordiks). WebSocket'i kaudu \u00fchenduse loomiseks peadmen\u00fc\u00fcs S\u00fcsteem / Seaded / V\u00f5rk / Teenused lubama \"Luba programmidel ... Kodit juhtida\". Kui WebSocket pole lubatud, eemalda port ja j\u00e4tat\u00fchjaks." } } }, diff --git a/homeassistant/components/kodi/translations/fr.json b/homeassistant/components/kodi/translations/fr.json index a4fde763d65..fd0d3e38e81 100644 --- a/homeassistant/components/kodi/translations/fr.json +++ b/homeassistant/components/kodi/translations/fr.json @@ -24,14 +24,6 @@ "description": "Voulez-vous ajouter Kodi (` {name} `) \u00e0 Home Assistant ?", "title": "Kodi d\u00e9couvert" }, - "host": { - "data": { - "host": "H\u00f4te", - "port": "Port", - "ssl": "Connexion via SSL" - }, - "description": "Informations de connexion Kodi. Veuillez vous assurer d'activer \"Autoriser le contr\u00f4le de Kodi via HTTP\" dans Syst\u00e8me / Param\u00e8tres / R\u00e9seau / Services." - }, "user": { "data": { "host": "H\u00f4te", diff --git a/homeassistant/components/kodi/translations/it.json b/homeassistant/components/kodi/translations/it.json index 565aaa9d39a..ad783a26a6b 100644 --- a/homeassistant/components/kodi/translations/it.json +++ b/homeassistant/components/kodi/translations/it.json @@ -24,14 +24,6 @@ "description": "Vuoi aggiungere Kodi (`{name}`) a Home Assistant?", "title": "Rilevato Kodi" }, - "host": { - "data": { - "host": "Host", - "port": "Porta", - "ssl": "Connettiti tramite SSL" - }, - "description": "Informazioni sulla connessione Kodi. Assicurati di abilitare \"Consenti il controllo di Kodi tramite HTTP\" in Sistema/Impostazioni/Rete/Servizi." - }, "user": { "data": { "host": "Host", diff --git a/homeassistant/components/kodi/translations/ko.json b/homeassistant/components/kodi/translations/ko.json index 6dc6b8bf87a..64b08475b68 100644 --- a/homeassistant/components/kodi/translations/ko.json +++ b/homeassistant/components/kodi/translations/ko.json @@ -18,12 +18,6 @@ "description": "Kodi (` {name} `)\ub97c Home Assistant\uc5d0 \ucd94\uac00 \ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?", "title": "Kodi \ubc1c\uacac" }, - "host": { - "data": { - "ssl": "SSL\uc744 \ud1b5\ud574 \uc5f0\uacb0" - }, - "description": "Kodi \uc5f0\uacb0 \uc815\ubcf4. \uc2dc\uc2a4\ud15c / \uc124\uc815 / \ub124\ud2b8\uc6cc\ud06c / \uc11c\ube44\uc2a4\uc5d0\uc11c \"HTTP\ub97c \ud1b5\ud55c Kodi \uc81c\uc5b4 \ud5c8\uc6a9\"\uc744 \ud65c\uc131\ud654\ud588\ub294\uc9c0 \ud655\uc778\ud558\uc2ed\uc2dc\uc624." - }, "user": { "description": "Kodi \uc5f0\uacb0 \uc815\ubcf4. \uc2dc\uc2a4\ud15c / \uc124\uc815 / \ub124\ud2b8\uc6cc\ud06c / \uc11c\ube44\uc2a4\uc5d0\uc11c \"HTTP\ub97c \ud1b5\ud55c Kodi \uc81c\uc5b4 \ud5c8\uc6a9\"\uc744 \ud65c\uc131\ud654\ud588\ub294\uc9c0 \ud655\uc778\ud558\uc2ed\uc2dc\uc624." }, diff --git a/homeassistant/components/kodi/translations/lb.json b/homeassistant/components/kodi/translations/lb.json index 0fde1e6ffdf..c00f0e127bb 100644 --- a/homeassistant/components/kodi/translations/lb.json +++ b/homeassistant/components/kodi/translations/lb.json @@ -24,19 +24,11 @@ "description": "Soll Kodi (`{name}`) am Home Assistant dob\u00e4i gesaat ginn?", "title": "Kodi entdeckt" }, - "host": { - "data": { - "host": "Host", - "port": "Port", - "ssl": "Iwwer SSL verbannen" - }, - "description": "Kodi Verbindungs Informatiounen. Stell s\u00e9cher dass d'Optioun \"Allow control of Kodi via HTTP\" aktiv ass an System/Settings/Network/Services." - }, "user": { "data": { "host": "Host", "port": "Port", - "ssl": "Iwwer SSL verbannen" + "ssl": "Benotzt ee SSL Zertifikat" }, "description": "Kodi Verbindungs Informatiounen. Stell s\u00e9cher dass d'Optioun \"Allow control of Kodi via HTTP\" aktiv ass an System/Settings/Network/Services." }, diff --git a/homeassistant/components/kodi/translations/nl.json b/homeassistant/components/kodi/translations/nl.json index c47fd73eea8..8eb4a39cfb6 100644 --- a/homeassistant/components/kodi/translations/nl.json +++ b/homeassistant/components/kodi/translations/nl.json @@ -2,30 +2,36 @@ "config": { "abort": { "already_configured": "Apparaat is al geconfigureerd", + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", "unknown": "Onverwachte fout" }, "step": { "credentials": { "data": { + "password": "Wachtwoord", "username": "Gebruikersnaam" - } - }, - "host": { - "data": { - "port": "Poort" - } + }, + "description": "Voer uw Kodi gebruikersnaam en wachtwoord in. Deze zijn te vinden in Systeem / Instellingen / Netwerk / Services." }, "user": { "data": { "host": "Host", "port": "Poort", "ssl": "Maak verbinding via SSL" - } + }, + "description": "Kodi-verbindingsinformatie. Zorg ervoor dat u \"Controle van Kodi via HTTP toestaan\" in Systeem / Instellingen / Netwerk / Services inschakelt." }, "ws_port": { "data": { "ws_port": "Poort" - } + }, + "description": "De WebSocket-poort (ook wel TCP-poort genoemd in Kodi). Om verbinding te maken via WebSocket, moet u \"Programma's toestaan ... om Kodi te besturen\" inschakelen in Systeem / Instellingen / Netwerk / Services. Als WebSocket niet is ingeschakeld, verwijdert u de poort en laat u deze leeg." } } } diff --git a/homeassistant/components/kodi/translations/no.json b/homeassistant/components/kodi/translations/no.json index c29f47e0957..594daf99e66 100644 --- a/homeassistant/components/kodi/translations/no.json +++ b/homeassistant/components/kodi/translations/no.json @@ -24,14 +24,6 @@ "description": "Vil du legge til Kodi ({name}) i Home Assistant?", "title": "Oppdaget Kodi" }, - "host": { - "data": { - "host": "Vert", - "port": "Port", - "ssl": "Koble til via SSL" - }, - "description": "Kodi-tilkoblingsinformasjon. Vennligst s\u00f8rg for \u00e5 aktivere \"Tillat kontroll av Kodi via HTTP\" i System / Innstillinger / Nettverk / Tjenester." - }, "user": { "data": { "host": "Vert", @@ -50,8 +42,8 @@ }, "device_automation": { "trigger_type": { - "turn_off": "{entity_name} ble bedt om \u00e5 sl\u00e5 av", - "turn_on": "{entity_name} ble bedt om \u00e5 sl\u00e5 p\u00e5" + "turn_off": "{entity_name} ble bedt om \u00e5 sl\u00e5es av", + "turn_on": "{entity_name} ble bedt om \u00e5 sl\u00e5es p\u00e5" } } } \ No newline at end of file diff --git a/homeassistant/components/kodi/translations/pl.json b/homeassistant/components/kodi/translations/pl.json index 9ea8c664510..78fdf95a7a8 100644 --- a/homeassistant/components/kodi/translations/pl.json +++ b/homeassistant/components/kodi/translations/pl.json @@ -24,14 +24,6 @@ "description": "Czy chcesz doda\u0107 Kodi (\"{name}\") do Home Assistant?", "title": "Wykryte urz\u0105dzenia Kodi" }, - "host": { - "data": { - "host": "Nazwa hosta lub adres IP", - "port": "Port", - "ssl": "Po\u0142\u0105cz przez SSL" - }, - "description": "Informacje o po\u0142\u0105czeniu Kodi. Upewnij si\u0119, \u017ce w\u0142\u0105czy\u0142e\u015b \"Zezwalaj na zdalne sterowanie przez HTTP\" w System/Ustawienia/Sieci/Us\u0142ugi." - }, "user": { "data": { "host": "Nazwa hosta lub adres IP", diff --git a/homeassistant/components/kodi/translations/pt.json b/homeassistant/components/kodi/translations/pt.json index f28cee08d1b..441d052867f 100644 --- a/homeassistant/components/kodi/translations/pt.json +++ b/homeassistant/components/kodi/translations/pt.json @@ -21,13 +21,6 @@ "discovery_confirm": { "title": "Kodi descoberto" }, - "host": { - "data": { - "host": "Servidor", - "port": "Porta", - "ssl": "Conecte-se por SSL" - } - }, "user": { "data": { "host": "Servidor", diff --git a/homeassistant/components/kodi/translations/ru.json b/homeassistant/components/kodi/translations/ru.json index 3e6a898bf43..a6a982dfdee 100644 --- a/homeassistant/components/kodi/translations/ru.json +++ b/homeassistant/components/kodi/translations/ru.json @@ -24,14 +24,6 @@ "description": "\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c Kodi (`{name}`)?", "title": "\u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0439 Kodi" }, - "host": { - "data": { - "host": "\u0425\u043e\u0441\u0442", - "port": "\u041f\u043e\u0440\u0442", - "ssl": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u043e SSL" - }, - "description": "\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \"\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e HTTP\" \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\" - \"\u0421\u043b\u0443\u0436\u0431\u044b\" - \"\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\"." - }, "user": { "data": { "host": "\u0425\u043e\u0441\u0442", diff --git a/homeassistant/components/kodi/translations/zh-Hant.json b/homeassistant/components/kodi/translations/zh-Hant.json index c36fe96740b..3e9065c140f 100644 --- a/homeassistant/components/kodi/translations/zh-Hant.json +++ b/homeassistant/components/kodi/translations/zh-Hant.json @@ -24,14 +24,6 @@ "description": "\u662f\u5426\u8981\u65b0\u589e Kodi (`{name}`) \u81f3 Home Assistant\uff1f", "title": "\u5df2\u641c\u7d22\u5230\u7684 Kodi" }, - "host": { - "data": { - "host": "\u4e3b\u6a5f\u7aef", - "port": "\u901a\u8a0a\u57e0", - "ssl": "\u901a\u904e SSL \u9023\u7dda" - }, - "description": "Kodi \u9023\u7dda\u8cc7\u8a0a\uff0c\u8acb\u78ba\u5b9a\u5df2\u65bc\u300c\u7cfb\u7d71/\u8a2d\u5b9a/\u7db2\u8def/\u670d\u52d9\u300d\u4e2d\u958b\u555f \"\u5141\u8a31\u900f\u904e HTTP \u63a7\u5236 Kodi\"\u3002" - }, "user": { "data": { "host": "\u4e3b\u6a5f\u7aef", diff --git a/homeassistant/components/konnected/translations/cs.json b/homeassistant/components/konnected/translations/cs.json index 774d1c70851..f2cd8759a54 100644 --- a/homeassistant/components/konnected/translations/cs.json +++ b/homeassistant/components/konnected/translations/cs.json @@ -30,6 +30,9 @@ "abort": { "not_konn_panel": "Nejedn\u00e1 se o rozpoznan\u00e9 Konnected.io za\u0159\u00edzen\u00ed" }, + "error": { + "bad_host": "Neplatn\u00e1 p\u0159epsan\u00e1 URL adresa API hostitele" + }, "step": { "options_binary": { "data": { @@ -58,7 +61,8 @@ "5": "Z\u00f3na 5", "6": "Z\u00f3na 6", "7": "Z\u00f3na 7" - } + }, + "title": "Nastaven\u00ed vstupu/v\u00fdstupu" }, "options_io_ext": { "data": { @@ -71,8 +75,15 @@ "alarm2_out2": "OUT2/ALARM2" } }, + "options_misc": { + "data": { + "api_host": "P\u0159epsat URL adresu API hostitele (voliteln\u00e9)", + "override_api_host": "P\u0159epsat v\u00fdchoz\u00ed URL adresu API hostitelsk\u00e9ho panelu Home Assistant" + } + }, "options_switch": { "data": { + "more_states": "Nastavte dal\u0161\u00ed stavy t\u00e9to z\u00f3ny", "name": "Jm\u00e9no (voliteln\u00e9)" }, "description": "Mo\u017enosti {zone} : stav {state}" diff --git a/homeassistant/components/konnected/translations/et.json b/homeassistant/components/konnected/translations/et.json index 21a01329fce..34c361fd9c6 100644 --- a/homeassistant/components/konnected/translations/et.json +++ b/homeassistant/components/konnected/translations/et.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", "already_in_progress": "Seadistamine on juba k\u00e4imas", + "not_konn_panel": "Tuvastamata Konnected.io seade", "unknown": "Tundmatu viga" }, "error": { @@ -10,7 +11,12 @@ }, "step": { "confirm": { - "description": "" + "description": "", + "title": "Konnected seade on valmis" + }, + "import_confirm": { + "description": "Configuration.yaml kirjest leiti Konnected Alarm Panel ID-ga {id}. See voog v\u00f5imaldabl selle importida seadistusikirjesse.", + "title": "Konnektedi seadme import" }, "user": { "data": { @@ -22,33 +28,80 @@ } }, "options": { + "abort": { + "not_konn_panel": "Tuvastamata Konnected.io seade" + }, "error": { "bad_host": "Sobimatu API hosti alistamise URL" }, "step": { "options_binary": { "data": { - "name": "Nimi (valikuline)" - } + "inverse": "Vaheta avatud / suletud olek", + "name": "Nimi (valikuline)", + "type": "Binaaranduri t\u00fc\u00fcp" + }, + "description": "{zone} suvandid", + "title": "Binaaranduri seadistamine" }, "options_digital": { "data": { - "name": "Nimi (valikuline)" - } + "name": "Nimi (valikuline)", + "poll_interval": "P\u00e4ringute intervall (sekundites) (valikuline)", + "type": "Anduri t\u00fc\u00fcp" + }, + "description": "{zone} valikud", + "title": "Digitaalse anduri seadistamine" }, "options_io": { - "description": "Avastati {model} kohas {host}. Vali iga allpool oleva I/O baaskonfiguratsioon \u2013 s\u00f5ltuvalt I/O-st v\u00f5ib see lubada binaarsensoreid (avatud/suletud), digitaalseid andureid (dht ja ds18b20) v\u00f5i vahetatavaid v\u00e4ljundeid. Saad konfigureerida \u00fcksikasjalikke suvandeid j\u00e4rgmistes etappides." + "data": { + "1": "Tsoon 1", + "2": "Tsoon 2", + "3": "Tsoon 3", + "4": "Tsoon 4", + "5": "Tsoon 5", + "6": "Tsoon 6", + "7": "Tsoon 7", + "out": "" + }, + "description": "Avastati {model} kohas {host}. Vali iga allpool oleva I/O baaskonfiguratsioon \u2013 s\u00f5ltuvalt I/O-st v\u00f5ib see lubada binaarsensoreid (avatud/suletud), digitaalseid andureid (dht ja ds18b20) v\u00f5i vahetatavaid v\u00e4ljundeid. Saad konfigureerida \u00fcksikasjalikke suvandeid j\u00e4rgmistes etappides.", + "title": "I/O seadistamine" + }, + "options_io_ext": { + "data": { + "10": "Tsoon 10", + "11": "Tsoon 11", + "12": "Tsoon 12", + "8": "Tsoon 8", + "9": "Tsoon 9", + "alarm1": "", + "alarm2_out2": "", + "out1": "" + }, + "description": "Vali allpool \u00fclej\u00e4\u00e4nud I/O s\u00e4tted. \u00dcksikasjalikke suvandeid saab seadistada j\u00e4rgmistes etappides.", + "title": "Laiendatud I/O seadistamine" }, "options_misc": { "data": { "api_host": "Alista API hosti URL (valikuline)", + "blink": "Vilguts paneeli LEDi oleku muudatuse saatmisel", + "discovery": "V\u00f5rgus esitatud tuvastusp\u00e4ringutele vastamine", "override_api_host": "Alista Home Assistanti API hostipaneeli vaikimisi URL" - } + }, + "description": "Vali oma paneeli jaoks soovitud k\u00e4itumine", + "title": "Muud seadistused" }, "options_switch": { "data": { - "name": "Nimi (valikuline)" - } + "activation": "V\u00e4ljund sissel\u00fclitatuna", + "momentary": "Impulsi kestus (ms) (valikuline)", + "more_states": "Selle tsooni t\u00e4iendavate olekute konfigureerimine", + "name": "Nimi (valikuline)", + "pause": "Paus impulsside vahel (ms) (valikuline)", + "repeat": "Korduste arv (-1 = l\u00f5pmatu) (valikuline)" + }, + "description": "{tsooni} suvandid: olek {state}", + "title": "Seadista l\u00fclitatav v\u00e4ljund" } } } diff --git a/homeassistant/components/konnected/translations/lb.json b/homeassistant/components/konnected/translations/lb.json index d90602c4005..1856d9b2e3d 100644 --- a/homeassistant/components/konnected/translations/lb.json +++ b/homeassistant/components/konnected/translations/lb.json @@ -2,12 +2,12 @@ "config": { "abort": { "already_configured": "Apparat ass scho konfigur\u00e9iert", - "already_in_progress": "Konfiguratioun's Oflaf fir den Apparat ass schonn am gaangen.", + "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaangen.", "not_konn_panel": "Keen erkannten Konnected.io Apparat", - "unknown": "Onbekannten Fehler opgetrueden" + "unknown": "Onerwaarte Feeler" }, "error": { - "cannot_connect": "Kann sech net mam Konnected Panel um {host}:{port} verbannen" + "cannot_connect": "Feeler beim verbannen" }, "step": { "confirm": { @@ -40,19 +40,19 @@ "options_binary": { "data": { "inverse": "Op/Zou Zoustand vertauschen", - "name": "Numm (optional)", + "name": "Numm (optionell)", "type": "Typ vun Bin\u00e4re Sensor" }, - "description": "Wiel d'Optioune fir den bin\u00e4ren Sensor dee mat {zone} verbonnen ass", + "description": "{zone} Optiounen", "title": "Bin\u00e4re Sensor konfigur\u00e9ieren" }, "options_digital": { "data": { - "name": "Numm (optional)", + "name": "Numm (optionell)", "poll_interval": "Intervall vun den Offroen (Minutten) (optional)", "type": "Typ vum Sensor" }, - "description": "Wiel d'Optioune fir den digitale Sensor dee mat {zone} verbonnen ass", + "description": "{zone} Optiounen", "title": "Digitale Sensor konfigur\u00e9ieren" }, "options_io": { @@ -98,11 +98,11 @@ "activation": "Ausgang wann un", "momentary": "Pulsatiounsdauer (ms) (optional)", "more_states": "Zous\u00e4tzlesch Zoust\u00e4nn fir d\u00ebs Zon konfigur\u00e9ieren", - "name": "Numm (optional)", + "name": "Numm (optionell)", "pause": "Pausen zw\u00ebscht den Impulser (ms) (optional)", "repeat": "Unzuel vu Widderhuelungen (-1= onendlech) (optional)" }, - "description": "Wielt w.e.g. d'Ausgaboptiounen fir {zone}: Status {state}", + "description": "{zone} Optioune: Status {state}", "title": "\u00cbmschltbaren Ausgang konfigur\u00e9ieren" } } diff --git a/homeassistant/components/konnected/translations/nl.json b/homeassistant/components/konnected/translations/nl.json index 43e86642727..9a7f20ac1e1 100644 --- a/homeassistant/components/konnected/translations/nl.json +++ b/homeassistant/components/konnected/translations/nl.json @@ -66,6 +66,7 @@ "7": "Zone 7", "out": "UIT" }, + "description": "Heeft een {model} bij {host} . Selecteer hieronder de basisconfiguratie van elke I / O - afhankelijk van de I / O kan het binaire sensoren (open / dicht contacten), digitale sensoren (dht en ds18b20) of schakelbare uitgangen mogelijk maken. U kunt in de volgende stappen gedetailleerde opties configureren.", "title": "Configureer I/O" }, "options_io_ext": { @@ -79,11 +80,13 @@ "alarm2_out2": "OUT2 / ALARM2", "out1": "OUT1" }, + "description": "Selecteer hieronder de configuratie van de resterende I/O. U kunt in de volgende stappen gedetailleerde opties configureren.", "title": "Configureer uitgebreide I/O" }, "options_misc": { "data": { "api_host": "API host-URL overschrijven (optioneel)", + "blink": "Led knipperen bij het verzenden van statuswijziging", "override_api_host": "Overschrijf standaard Home Assistant API hostpaneel-URL" }, "description": "Selecteer het gewenste gedrag voor uw paneel", @@ -91,6 +94,7 @@ }, "options_switch": { "data": { + "activation": "Uitvoer wanneer ingeschakeld", "momentary": "Pulsduur (ms) (optioneel)", "more_states": "Aanvullende statussen voor deze zone configureren", "name": "Naam (optioneel)", diff --git a/homeassistant/components/lacrosse/manifest.json b/homeassistant/components/lacrosse/manifest.json index f31d4b9fea5..a6517a2768b 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/homeassistant/components/launch_library/const.py b/homeassistant/components/launch_library/const.py new file mode 100644 index 00000000000..0d6e4f22f76 --- /dev/null +++ b/homeassistant/components/launch_library/const.py @@ -0,0 +1,10 @@ +"""Constants for launch_library.""" + +ATTR_AGENCY = "agency" +ATTR_AGENCY_COUNTRY_CODE = "agency_country_code" +ATTR_LAUNCH_TIME = "launch_time" +ATTR_STREAM = "stream" + +ATTRIBUTION = "Data provided by Launch Library." + +DEFAULT_NAME = "Next launch" diff --git a/homeassistant/components/launch_library/manifest.json b/homeassistant/components/launch_library/manifest.json index d1e4c17ec5a..023e15fea14 100644 --- a/homeassistant/components/launch_library/manifest.json +++ b/homeassistant/components/launch_library/manifest.json @@ -2,6 +2,6 @@ "domain": "launch_library", "name": "Launch Library", "documentation": "https://www.home-assistant.io/integrations/launch_library", - "requirements": ["pylaunches==0.2.0"], + "requirements": ["pylaunches==1.0.0"], "codeowners": ["@ludeeus"] } diff --git a/homeassistant/components/launch_library/sensor.py b/homeassistant/components/launch_library/sensor.py index 32335526194..ef816eef0ba 100644 --- a/homeassistant/components/launch_library/sensor.py +++ b/homeassistant/components/launch_library/sensor.py @@ -1,8 +1,9 @@ """A sensor platform that give you information about the next space launch.""" from datetime import timedelta import logging +from typing import Optional -from pylaunches.api import Launches +from pylaunches import PyLaunches, PyLaunchesException import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA @@ -11,12 +12,17 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity +from .const import ( + ATTR_AGENCY, + ATTR_AGENCY_COUNTRY_CODE, + ATTR_LAUNCH_TIME, + ATTR_STREAM, + ATTRIBUTION, + DEFAULT_NAME, +) + _LOGGER = logging.getLogger(__name__) -ATTRIBUTION = "Data provided by Launch Library." - -DEFAULT_NAME = "Next launch" - SCAN_INTERVAL = timedelta(hours=1) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( @@ -26,59 +32,58 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Create the launch sensor.""" - name = config[CONF_NAME] - session = async_get_clientsession(hass) - launches = Launches(hass.loop, session) - sensor = [LaunchLibrarySensor(launches, name)] - async_add_entities(sensor, True) + launches = PyLaunches(session) + + async_add_entities([LaunchLibrarySensor(launches, name)], True) class LaunchLibrarySensor(Entity): """Representation of a launch_library Sensor.""" - def __init__(self, launches, name): + def __init__(self, launches: PyLaunches, name: str) -> None: """Initialize the sensor.""" self.launches = launches - self._attributes = {} + self.next_launch = None self._name = name - self._state = None - async def async_update(self): + async def async_update(self) -> None: """Get the latest data.""" - await self.launches.get_launches() - if self.launches.launches is None: - _LOGGER.error("No data received") - return try: - data = self.launches.launches[0] - self._state = data["name"] - self._attributes["launch_time"] = data["start"] - self._attributes["agency"] = data["agency"] - agency_country_code = data["agency_country_code"] - self._attributes["agency_country_code"] = agency_country_code - self._attributes["stream"] = data["stream"] - self._attributes[ATTR_ATTRIBUTION] = ATTRIBUTION - except (KeyError, IndexError) as error: - _LOGGER.debug("Error getting data, %s", error) + launches = await self.launches.upcoming_launches() + except PyLaunchesException as exception: + _LOGGER.error("Error getting data, %s", exception) + else: + if launches: + self.next_launch = launches[0] @property - def name(self): + def name(self) -> str: """Return the name of the sensor.""" return self._name @property - def state(self): + def state(self) -> Optional[str]: """Return the state of the sensor.""" - return self._state + if self.next_launch: + return self.next_launch.name + return None @property - def icon(self): + def icon(self) -> str: """Return the icon of the sensor.""" return "mdi:rocket" @property - def device_state_attributes(self): + def device_state_attributes(self) -> Optional[dict]: """Return attributes for the sensor.""" - return self._attributes + if self.next_launch: + return { + ATTR_LAUNCH_TIME: self.next_launch.net, + ATTR_AGENCY: self.next_launch.launch_service_provider.name, + ATTR_AGENCY_COUNTRY_CODE: self.next_launch.pad.location.country_code, + ATTR_STREAM: self.next_launch.webcast_live, + ATTR_ATTRIBUTION: ATTRIBUTION, + } + return None diff --git a/homeassistant/components/lcn/light.py b/homeassistant/components/lcn/light.py index e76becc0e9f..8fd24c43069 100644 --- a/homeassistant/components/lcn/light.py +++ b/homeassistant/components/lcn/light.py @@ -71,10 +71,9 @@ class LcnOutputLight(LcnDevice, LightEntity): @property def supported_features(self): """Flag supported features.""" - features = SUPPORT_TRANSITION if self.dimmable: - features |= SUPPORT_BRIGHTNESS - return features + return SUPPORT_TRANSITION | SUPPORT_BRIGHTNESS + return SUPPORT_TRANSITION @property def brightness(self): diff --git a/homeassistant/components/lcn/manifest.json b/homeassistant/components/lcn/manifest.json index 6eeb4a69b26..dca4436d5c2 100644 --- a/homeassistant/components/lcn/manifest.json +++ b/homeassistant/components/lcn/manifest.json @@ -2,6 +2,6 @@ "domain": "lcn", "name": "LCN", "documentation": "https://www.home-assistant.io/integrations/lcn", - "requirements": ["pypck==0.7.2"], + "requirements": ["pypck==0.7.4"], "codeowners": ["@alengwenus"] } diff --git a/homeassistant/components/life360/config_flow.py b/homeassistant/components/life360/config_flow.py index 83ad4138de8..de37068cd56 100644 --- a/homeassistant/components/life360/config_flow.py +++ b/homeassistant/components/life360/config_flow.py @@ -58,10 +58,10 @@ class Life360ConfigFlow(config_entries.ConfigFlow): _LOGGER.error( "Unexpected error communicating with Life360 server: %s", error ) - errors["base"] = "unexpected" + errors["base"] = "unknown" else: if self._username in self.configured_usernames: - errors["base"] = "user_already_configured" + errors["base"] = "already_configured" else: return self.async_create_entry( title=self._username, @@ -99,7 +99,7 @@ class Life360ConfigFlow(config_entries.ConfigFlow): _LOGGER.error( "Unexpected error communicating with Life360 server: %s", error ) - return self.async_abort(reason="unexpected") + return self.async_abort(reason="unknown") return self.async_create_entry( title=f"{username} (from configuration)", data={ diff --git a/homeassistant/components/life360/strings.json b/homeassistant/components/life360/strings.json index 4018a899f44..0d554759ee7 100644 --- a/homeassistant/components/life360/strings.json +++ b/homeassistant/components/life360/strings.json @@ -13,15 +13,15 @@ "error": { "invalid_username": "Invalid username", "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", - "user_already_configured": "[%key:common::config_flow::abort::already_configured_account%]", - "unexpected": "Unexpected error communicating with Life360 server" + "already_configured": "[%key:common::config_flow::abort::already_configured_account%]", + "unknown": "[%key:common::config_flow::error::unknown%]" }, "create_entry": { "default": "To set advanced options, see [Life360 documentation]({docs_url})." }, "abort": { "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", - "user_already_configured": "[%key:common::config_flow::abort::already_configured_account%]" + "unknown": "[%key:common::config_flow::error::unknown%]" } } } \ No newline at end of file diff --git a/homeassistant/components/life360/translations/bg.json b/homeassistant/components/life360/translations/bg.json index 115639e5c3f..fe116225550 100644 --- a/homeassistant/components/life360/translations/bg.json +++ b/homeassistant/components/life360/translations/bg.json @@ -1,16 +1,10 @@ { "config": { - "abort": { - "invalid_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438" - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0437\u0430\u0434\u0430\u0434\u0435\u0442\u0435 \u0440\u0430\u0437\u0448\u0438\u0440\u0435\u043d\u0438 \u043e\u043f\u0446\u0438\u0438, \u0432\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043d\u0430 Life360]({docs_url})." }, "error": { - "invalid_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438", - "invalid_username": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435", - "unexpected": "\u041d\u0435\u043e\u0447\u0430\u043a\u0432\u0430\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u043a\u043e\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u044f \u0441\u044a\u0441 \u0441\u044a\u0440\u0432\u044a\u0440\u0430 Life360", - "user_already_configured": "\u0412\u0435\u0447\u0435 \u0438\u043c\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d \u043f\u0440\u043e\u0444\u0438\u043b" + "invalid_username": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/ca.json b/homeassistant/components/life360/translations/ca.json index 5c379e4fecf..cf57e4e1d2f 100644 --- a/homeassistant/components/life360/translations/ca.json +++ b/homeassistant/components/life360/translations/ca.json @@ -2,18 +2,16 @@ "config": { "abort": { "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Credencials inv\u00e0lides", - "user_already_configured": "[%key::common::config_flow::abort::already_configured_account%]" + "unknown": "Error inesperat" }, "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.", - "user_already_configured": "[%key::common::config_flow::abort::already_configured_account%]" + "unknown": "Error inesperat" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/cs.json b/homeassistant/components/life360/translations/cs.json index b574685ba21..0c267ef7163 100644 --- a/homeassistant/components/life360/translations/cs.json +++ b/homeassistant/components/life360/translations/cs.json @@ -2,17 +2,16 @@ "config": { "abort": { "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje", - "user_already_configured": "\u00da\u010det je ji\u017e nastaven" + "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "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", - "user_already_configured": "\u00da\u010det je ji\u017e nastaven" + "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { "user": { @@ -20,6 +19,7 @@ "password": "Heslo", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" }, + "description": "Chcete-li nastavit pokro\u010dil\u00e9 mo\u017enosti, pod\u00edvejte se do [dokumentace Life360]({docs_url}). Mo\u017en\u00e1 to budete cht\u00edt ud\u011blat p\u0159ed p\u0159id\u00e1n\u00edm \u00fa\u010dtu.", "title": "Informace o \u00fa\u010dtu Life360" } } diff --git a/homeassistant/components/life360/translations/da.json b/homeassistant/components/life360/translations/da.json index 7033496add3..71ce5215f25 100644 --- a/homeassistant/components/life360/translations/da.json +++ b/homeassistant/components/life360/translations/da.json @@ -1,16 +1,10 @@ { "config": { - "abort": { - "invalid_credentials": "Ugyldige legitimationsoplysninger" - }, "create_entry": { "default": "Hvis du vil angive avancerede indstillinger skal du se [Life360 dokumentation]({docs_url})." }, "error": { - "invalid_credentials": "Ugyldige legitimationsoplysninger", - "invalid_username": "Ugyldigt brugernavn", - "unexpected": "Uventet fejl under kommunikation med Life360-serveren", - "user_already_configured": "Kontoen er allerede konfigureret" + "invalid_username": "Ugyldigt brugernavn" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/de.json b/homeassistant/components/life360/translations/de.json index d689492ad58..731ebdceef7 100644 --- a/homeassistant/components/life360/translations/de.json +++ b/homeassistant/components/life360/translations/de.json @@ -1,17 +1,15 @@ { "config": { "abort": { - "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen", - "user_already_configured": "Account ist bereits konfiguriert" + "unknown": "Unerwarteter Fehler" }, "create_entry": { "default": "M\u00f6gliche erweiterte Einstellungen finden sich unter [Life360-Dokumentation]({docs_url})." }, "error": { - "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen", + "already_configured": "Konto ist bereits konfiguriert", "invalid_username": "Ung\u00fcltiger Benutzername", - "unexpected": "Unerwarteter Fehler bei der Kommunikation mit dem Life360-Server", - "user_already_configured": "Konto wurde bereits konfiguriert" + "unknown": "Unerwarteter Fehler" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/en.json b/homeassistant/components/life360/translations/en.json index 1d7b80db4c9..fa836c62b61 100644 --- a/homeassistant/components/life360/translations/en.json +++ b/homeassistant/components/life360/translations/en.json @@ -2,18 +2,16 @@ "config": { "abort": { "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid credentials", - "user_already_configured": "Account is already configured" + "unknown": "Unexpected error" }, "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", - "user_already_configured": "Account is already configured" + "unknown": "Unexpected error" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/es-419.json b/homeassistant/components/life360/translations/es-419.json index fcc0561f11f..29b62e160fd 100644 --- a/homeassistant/components/life360/translations/es-419.json +++ b/homeassistant/components/life360/translations/es-419.json @@ -1,16 +1,10 @@ { "config": { - "abort": { - "invalid_credentials": "Credenciales no v\u00e1lidas" - }, "create_entry": { "default": "Para establecer opciones avanzadas, consulte [Documentaci\u00f3n de Life360] ({docs_url})." }, "error": { - "invalid_credentials": "Credenciales no v\u00e1lidas", - "invalid_username": "Nombre de usuario inv\u00e1lido", - "unexpected": "Error inesperado al comunicarse con el servidor Life360", - "user_already_configured": "La cuenta ya ha sido configurada" + "invalid_username": "Nombre de usuario inv\u00e1lido" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/es.json b/homeassistant/components/life360/translations/es.json index 72bedd1efb9..019d2bc88d8 100644 --- a/homeassistant/components/life360/translations/es.json +++ b/homeassistant/components/life360/translations/es.json @@ -1,17 +1,17 @@ { "config": { "abort": { - "invalid_credentials": "Credenciales no v\u00e1lidas", - "user_already_configured": "La cuenta ya est\u00e1 configurada" + "invalid_auth": "Autenticaci\u00f3n inv\u00e1lida", + "unknown": "Error inesperado" }, "create_entry": { "default": "Para configurar las opciones avanzadas, consulta la [documentaci\u00f3n de Life360]({docs_url})." }, "error": { - "invalid_credentials": "Credenciales no v\u00e1lidas", + "already_configured": "La cuenta ya ha sido configurada", + "invalid_auth": "Autenticaci\u00f3n inv\u00e1lida", "invalid_username": "Nombre de usuario no v\u00e1lido", - "unexpected": "Error inesperado al comunicarse con el servidor Life360", - "user_already_configured": "La cuenta ya ha sido configurada" + "unknown": "Error inesperado" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/et.json b/homeassistant/components/life360/translations/et.json index b621ef129d4..d9cbbbb30f5 100644 --- a/homeassistant/components/life360/translations/et.json +++ b/homeassistant/components/life360/translations/et.json @@ -2,20 +2,25 @@ "config": { "abort": { "invalid_auth": "Tuvastamise viga", - "user_already_configured": "Konto on juba seadistatud" + "unknown": "Ootamatu t\u00f5rge" + }, + "create_entry": { + "default": "T\u00e4psemate suvandite kohta leiad teemat [Life360 documentation]({docs_url})." }, "error": { + "already_configured": "Kasutaja on juba seadistatud", "invalid_auth": "Tuvastamise viga", "invalid_username": "Vale kasutajanimi", - "unexpected": "Ootamatu t\u00f5rge Life360 serveriga suhtlemisel", - "user_already_configured": "Konto on juba seadistatud" + "unknown": "Ootamatu t\u00f5rge" }, "step": { "user": { "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "description": "T\u00e4psemate suvandite kohta leiad teemat [Life360 documentation]({docs_url}).\nTee seda enne uute kontode lisamist.", + "title": "Life360 konto teave" } } } diff --git a/homeassistant/components/life360/translations/fr.json b/homeassistant/components/life360/translations/fr.json index cf004d4c03a..72f56ed8784 100644 --- a/homeassistant/components/life360/translations/fr.json +++ b/homeassistant/components/life360/translations/fr.json @@ -1,17 +1,17 @@ { "config": { "abort": { - "invalid_credentials": "Informations d'identification invalides", - "user_already_configured": "Compte d\u00e9j\u00e0 configur\u00e9" + "invalid_auth": "Authentification invalide", + "unknown": "Erreur inattendue" }, "create_entry": { "default": "Pour d\u00e9finir les options avanc\u00e9es, voir [Documentation de Life360]( {docs_url} )." }, "error": { - "invalid_credentials": "Informations d'identification invalides", + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", + "invalid_auth": "Authentification invalide", "invalid_username": "Nom d'utilisateur invalide", - "unexpected": "Erreur inattendue lors de la communication avec le serveur Life360", - "user_already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9" + "unknown": "Erreur inattendue" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/hr.json b/homeassistant/components/life360/translations/hr.json index 00cced7f635..bb4a0b4fcf9 100644 --- a/homeassistant/components/life360/translations/hr.json +++ b/homeassistant/components/life360/translations/hr.json @@ -1,15 +1,10 @@ { "config": { - "abort": { - "invalid_credentials": "Neva\u017ee\u0107e vjerodajnice" - }, "create_entry": { "default": "Da biste postavili napredne opcije, pogledajte [Life360 dokumentacija] ( {docs_url} )." }, "error": { - "invalid_credentials": "Neva\u017ee\u0107e vjerodajnice", - "invalid_username": "Neispravno korisni\u010dko ime", - "user_already_configured": "Ra\u010dun je ve\u0107 konfiguriran" + "invalid_username": "Neispravno korisni\u010dko ime" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/hu.json b/homeassistant/components/life360/translations/hu.json index 091e23e0d43..327dd40e386 100644 --- a/homeassistant/components/life360/translations/hu.json +++ b/homeassistant/components/life360/translations/hu.json @@ -1,12 +1,7 @@ { "config": { - "abort": { - "user_already_configured": "A fi\u00f3k m\u00e1r konfigur\u00e1lva van" - }, "error": { - "invalid_username": "\u00c9rv\u00e9nytelen felhaszn\u00e1l\u00f3n\u00e9v", - "unexpected": "V\u00e1ratlan hiba t\u00f6rt\u00e9nt a kommunik\u00e1ci\u00f3ban a Life360 szerverrel", - "user_already_configured": "A fi\u00f3k m\u00e1r konfigur\u00e1lva van" + "invalid_username": "\u00c9rv\u00e9nytelen felhaszn\u00e1l\u00f3n\u00e9v" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/it.json b/homeassistant/components/life360/translations/it.json index 8239a0fbe83..04d88e75378 100644 --- a/homeassistant/components/life360/translations/it.json +++ b/homeassistant/components/life360/translations/it.json @@ -1,17 +1,17 @@ { "config": { "abort": { - "invalid_credentials": "Credenziali non valide", - "user_already_configured": "L'account \u00e8 gi\u00e0 configurato" + "invalid_auth": "Autenticazione non valida", + "unknown": "Errore imprevisto" }, "create_entry": { "default": "Per impostare le opzioni avanzate, consultare la [Documentazione Life360]({docs_url})." }, "error": { - "invalid_credentials": "Credenziali non valide", + "already_configured": "L'account \u00e8 gi\u00e0 configurato", + "invalid_auth": "Autenticazione non valida", "invalid_username": "Nome utente non valido", - "unexpected": "Errore imprevisto durante la comunicazione con il server di Life360", - "user_already_configured": "L'account \u00e8 gi\u00e0 configurato" + "unknown": "Errore imprevisto" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/ko.json b/homeassistant/components/life360/translations/ko.json index 426f3b242a6..d419c5fdc02 100644 --- a/homeassistant/components/life360/translations/ko.json +++ b/homeassistant/components/life360/translations/ko.json @@ -1,17 +1,10 @@ { "config": { - "abort": { - "invalid_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ud639\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "user_already_configured": "\uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." - }, "create_entry": { "default": "\uace0\uae09 \uc635\uc158\uc744 \uc124\uc815\ud558\ub824\uba74 [Life360 \uc124\uba85\uc11c]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, "error": { - "invalid_credentials": "\ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "invalid_username": "\uc0ac\uc6a9\uc790 \uc774\ub984\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "unexpected": "Life360 \uc11c\ubc84 \uc5f0\uacb0\uc911 \uc608\uc0c1\uce58 \ubabb\ud55c \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4", - "user_already_configured": "\uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." + "invalid_username": "\uc0ac\uc6a9\uc790 \uc774\ub984\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/lb.json b/homeassistant/components/life360/translations/lb.json index f4a455212cb..ef359f37810 100644 --- a/homeassistant/components/life360/translations/lb.json +++ b/homeassistant/components/life360/translations/lb.json @@ -1,17 +1,17 @@ { "config": { "abort": { - "invalid_credentials": "Ong\u00eblteg Login Informatioune", - "user_already_configured": "Kont ass scho konfigur\u00e9iert" + "invalid_auth": "Ong\u00eblteg Authentifikatioun", + "unknown": "Onerwaarte Feeler" }, "create_entry": { "default": "Fir erweidert Optiounen anzestellen, kuckt [Life360 Dokumentatioun]({docs_url})." }, "error": { - "invalid_credentials": "Ong\u00eblteg Login Informatioune", + "already_configured": "Kont ass scho konfigur\u00e9iert", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", "invalid_username": "Ong\u00ebltege Benotzernumm", - "unexpected": "Onerwaarte Feeler bei der Kommunikatioun mam Life360 Server", - "user_already_configured": "Kont ass scho konfigur\u00e9iert" + "unknown": "Onerwaarte Feeler" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/nl.json b/homeassistant/components/life360/translations/nl.json index ad1ececc858..c3b667722d0 100644 --- a/homeassistant/components/life360/translations/nl.json +++ b/homeassistant/components/life360/translations/nl.json @@ -1,17 +1,15 @@ { "config": { "abort": { - "invalid_credentials": "Ongeldige gebruikersgegevens", - "user_already_configured": "Account is al geconfigureerd" + "invalid_auth": "Ongeldige authenticatie" }, "create_entry": { "default": "Om geavanceerde opties in te stellen, zie [Life360 documentatie]({docs_url})." }, "error": { - "invalid_credentials": "Ongeldige gebruikersgegevens", - "invalid_username": "Ongeldige gebruikersnaam", - "unexpected": "Onverwachte fout bij communicatie met Life360-server", - "user_already_configured": "Account is al geconfigureerd" + "already_configured": "Account is al geconfigureerd", + "invalid_auth": "Ongeldige authenticatie", + "invalid_username": "Ongeldige gebruikersnaam" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/no.json b/homeassistant/components/life360/translations/no.json index eb30640bf64..9a95a976657 100644 --- a/homeassistant/components/life360/translations/no.json +++ b/homeassistant/components/life360/translations/no.json @@ -2,18 +2,16 @@ "config": { "abort": { "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig legitimasjon", - "user_already_configured": "Kontoen er allerede konfigurert" + "unknown": "Uventet feil" }, "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": "Ugyldig legitimasjon", "invalid_username": "Ugyldig brukernavn", - "unexpected": "Uventet feil under kommunikasjon med Life360-servern", - "user_already_configured": "Kontoen er allerede konfigurert" + "unknown": "Uventet feil" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/pl.json b/homeassistant/components/life360/translations/pl.json index 54ca11f2bd4..30ba7ddc5b6 100644 --- a/homeassistant/components/life360/translations/pl.json +++ b/homeassistant/components/life360/translations/pl.json @@ -2,18 +2,16 @@ "config": { "abort": { "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce", - "user_already_configured": "Konto jest ju\u017c skonfigurowane" + "unknown": "Nieoczekiwany b\u0142\u0105d" }, "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", - "user_already_configured": "Konto jest ju\u017c skonfigurowane" + "unknown": "Nieoczekiwany b\u0142\u0105d" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/pt-BR.json b/homeassistant/components/life360/translations/pt-BR.json index 8fba3dce95d..5894376a065 100644 --- a/homeassistant/components/life360/translations/pt-BR.json +++ b/homeassistant/components/life360/translations/pt-BR.json @@ -1,16 +1,10 @@ { "config": { - "abort": { - "invalid_credentials": "Credenciais inv\u00e1lidas" - }, "create_entry": { "default": "Para definir op\u00e7\u00f5es avan\u00e7adas, consulte [Documenta\u00e7\u00e3o da Life360] ({docs_url})." }, "error": { - "invalid_credentials": "Credenciais inv\u00e1lidas", - "invalid_username": "Nome de usu\u00e1rio Inv\u00e1lido", - "unexpected": "Erro inesperado na comunica\u00e7\u00e3o com o servidor Life360", - "user_already_configured": "A conta j\u00e1 foi configurada" + "invalid_username": "Nome de usu\u00e1rio Inv\u00e1lido" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/pt.json b/homeassistant/components/life360/translations/pt.json index 5a6bb471b5e..9c848bd8ec8 100644 --- a/homeassistant/components/life360/translations/pt.json +++ b/homeassistant/components/life360/translations/pt.json @@ -1,13 +1,7 @@ { "config": { - "abort": { - "invalid_credentials": "Credenciais inv\u00e1lidas" - }, "error": { - "invalid_credentials": "Credenciais inv\u00e1lidas", - "invalid_username": "Nome de utilizador incorreto", - "unexpected": "Erro inesperado ao comunicar com o servidor do Life360", - "user_already_configured": "Conta j\u00e1 configurada" + "invalid_username": "Nome de utilizador incorreto" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/ru.json b/homeassistant/components/life360/translations/ru.json index f71fce78a85..2de2f63dbd6 100644 --- a/homeassistant/components/life360/translations/ru.json +++ b/homeassistant/components/life360/translations/ru.json @@ -2,18 +2,16 @@ "config": { "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.", - "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." + "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "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.", - "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." + "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/sl.json b/homeassistant/components/life360/translations/sl.json index 1e65cb692de..354c8c2618a 100644 --- a/homeassistant/components/life360/translations/sl.json +++ b/homeassistant/components/life360/translations/sl.json @@ -1,17 +1,10 @@ { "config": { - "abort": { - "invalid_credentials": "Napa\u010dno geslo", - "user_already_configured": "Ra\u010dun je \u017ee nastavljen" - }, "create_entry": { "default": "\u010ce \u017eelite nastaviti napredne mo\u017enosti, glejte [Life360 dokumentacija]({docs_url})." }, "error": { - "invalid_credentials": "Napa\u010dno geslo", - "invalid_username": "Napa\u010dno uporabni\u0161ko ime", - "unexpected": "Nepri\u010dakovana napaka pri komunikaciji s stre\u017enikom Life360", - "user_already_configured": "Ra\u010dun \u017ee nastavljen" + "invalid_username": "Napa\u010dno uporabni\u0161ko ime" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/sv.json b/homeassistant/components/life360/translations/sv.json index b8815f53643..27a669dfb5c 100644 --- a/homeassistant/components/life360/translations/sv.json +++ b/homeassistant/components/life360/translations/sv.json @@ -1,16 +1,10 @@ { "config": { - "abort": { - "invalid_credentials": "Ogiltiga autentiseringsuppgifter" - }, "create_entry": { "default": "F\u00f6r att st\u00e4lla in avancerade alternativ, se [Life360 documentation]({docs_url})." }, "error": { - "invalid_credentials": "Ogiltiga autentiseringsuppgifter", - "invalid_username": "Ogiltigt anv\u00e4ndarnmn", - "unexpected": "Ov\u00e4ntat fel vid kommunikation med Life360-servern", - "user_already_configured": "Konto har redan konfigurerats" + "invalid_username": "Ogiltigt anv\u00e4ndarnmn" }, "step": { "user": { diff --git a/homeassistant/components/life360/translations/tr.json b/homeassistant/components/life360/translations/tr.json new file mode 100644 index 00000000000..3f923c096cd --- /dev/null +++ b/homeassistant/components/life360/translations/tr.json @@ -0,0 +1,11 @@ +{ + "config": { + "abort": { + "unknown": "Beklenmedik hata" + }, + "error": { + "already_configured": "Hesap zaten konfig\u00fcre edilmi\u015fi durumda", + "unknown": "Beklenmedik hata" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/life360/translations/zh-Hans.json b/homeassistant/components/life360/translations/zh-Hans.json index 14e6d907861..a429b31dd82 100644 --- a/homeassistant/components/life360/translations/zh-Hans.json +++ b/homeassistant/components/life360/translations/zh-Hans.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "\u65e0\u6548\u7684\u8eab\u4efd\u9a8c\u8bc1", - "invalid_credentials": "\u65e0\u6548\u7684\u8eab\u4efd\u8ba4\u8bc1", "invalid_username": "\u65e0\u6548\u7684\u7528\u6237\u540d" }, "step": { diff --git a/homeassistant/components/life360/translations/zh-Hant.json b/homeassistant/components/life360/translations/zh-Hant.json index 886710f4788..ad7fde2e21d 100644 --- a/homeassistant/components/life360/translations/zh-Hant.json +++ b/homeassistant/components/life360/translations/zh-Hant.json @@ -2,18 +2,16 @@ "config": { "abort": { "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u6191\u8b49\u7121\u6548", - "user_already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "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", - "user_already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "step": { "user": { diff --git a/homeassistant/components/lifx/light.py b/homeassistant/components/lifx/light.py index 444bfe31480..e775b5623d3 100644 --- a/homeassistant/components/lifx/light.py +++ b/homeassistant/components/lifx/light.py @@ -199,11 +199,11 @@ def lifx_features(bulb): ) or aiolifx().products.features_map.get(1) -def find_hsbk(**kwargs): +def find_hsbk(hass, **kwargs): """Find the desired color from a number of possible inputs.""" hue, saturation, brightness, kelvin = [None] * 4 - preprocess_turn_on_alternatives(kwargs) + preprocess_turn_on_alternatives(hass, kwargs) if ATTR_HS_COLOR in kwargs: hue, saturation = kwargs[ATTR_HS_COLOR] @@ -330,11 +330,11 @@ class LIFXManager: period=kwargs.get(ATTR_PERIOD), cycles=kwargs.get(ATTR_CYCLES), mode=kwargs.get(ATTR_MODE), - hsbk=find_hsbk(**kwargs), + hsbk=find_hsbk(self.hass, **kwargs), ) await self.effects_conductor.start(effect, bulbs) elif service == SERVICE_EFFECT_COLORLOOP: - preprocess_turn_on_alternatives(kwargs) + preprocess_turn_on_alternatives(self.hass, kwargs) brightness = None if ATTR_BRIGHTNESS in kwargs: @@ -600,7 +600,7 @@ class LIFXLight(LightEntity): power_on = kwargs.get(ATTR_POWER, False) power_off = not kwargs.get(ATTR_POWER, True) - hsbk = find_hsbk(**kwargs) + hsbk = find_hsbk(self.hass, **kwargs) # Send messages, waiting for ACK each time ack = AwaitAioLIFX().wait diff --git a/homeassistant/components/lifx/translations/lb.json b/homeassistant/components/lifx/translations/lb.json index 0dcc857010c..5455195f822 100644 --- a/homeassistant/components/lifx/translations/lb.json +++ b/homeassistant/components/lifx/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "no_devices_found": "Keng LIFX Apparater am Netzwierk fonnt.", - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun LIFX ass erlaabt." + "no_devices_found": "Keng Apparater am Netzwierk fonnt.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "confirm": { diff --git a/homeassistant/components/lifx/translations/pl.json b/homeassistant/components/lifx/translations/pl.json index 5f78d90078d..a8ee3fa57ac 100644 --- a/homeassistant/components/lifx/translations/pl.json +++ b/homeassistant/components/lifx/translations/pl.json @@ -6,7 +6,7 @@ }, "step": { "confirm": { - "description": "Czy chcesz skonfigurowa\u0107 LIFX?" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } } diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index a179eca6957..fdef5e61a76 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -3,7 +3,6 @@ import csv from datetime import timedelta import logging import os -from typing import Dict, Optional, Tuple import voluptuous as vol @@ -13,6 +12,7 @@ from homeassistant.const import ( SERVICE_TURN_ON, STATE_ON, ) +from homeassistant.core import callback import homeassistant.helpers.config_validation as cv from homeassistant.helpers.config_validation import ( # noqa: F401 PLATFORM_SCHEMA, @@ -28,6 +28,7 @@ import homeassistant.util.color as color_util DOMAIN = "light" SCAN_INTERVAL = timedelta(seconds=30) +DATA_PROFILES = "light_profiles" ENTITY_ID_FORMAT = DOMAIN + ".{}" @@ -122,15 +123,6 @@ LIGHT_TURN_ON_SCHEMA = { } -PROFILE_SCHEMA = vol.Schema( - vol.Any( - vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte)), - vol.ExactSequence( - (str, cv.small_float, cv.small_float, cv.byte, cv.positive_int) - ), - ) -) - _LOGGER = logging.getLogger(__name__) @@ -140,14 +132,17 @@ def is_on(hass, entity_id): return hass.states.is_state(entity_id, STATE_ON) -def preprocess_turn_on_alternatives(params): - """Process extra data for turn light on request.""" - profile = Profiles.get(params.pop(ATTR_PROFILE, None)) - if profile is not None: - params.setdefault(ATTR_XY_COLOR, profile[:2]) - params.setdefault(ATTR_BRIGHTNESS, profile[2]) - if len(profile) > 3: - params.setdefault(ATTR_TRANSITION, profile[3]) +def preprocess_turn_on_alternatives(hass, params): + """Process extra data for turn light on request. + + Async friendly. + """ + # Bail out, we process this later. + if ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params: + return + + if ATTR_PROFILE in params: + hass.data[DATA_PROFILES].apply_profile(params.pop(ATTR_PROFILE), params) color_name = params.pop(ATTR_COLOR_NAME, None) if color_name is not None: @@ -174,24 +169,12 @@ def preprocess_turn_on_alternatives(params): if rgb_color is not None: params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color) - return params - def filter_turn_off_params(params): """Filter out params not used in turn off.""" return {k: v for k, v in params.items() if k in (ATTR_TRANSITION, ATTR_FLASH)} -def preprocess_turn_off(params): - """Process data for turning light off if brightness is 0.""" - if ATTR_BRIGHTNESS in params and params[ATTR_BRIGHTNESS] == 0: - # Zero brightness: Light will be turned off - params = filter_turn_off_params(params) - return (True, params) # Light should be turned off - - return (False, None) # Light should be turned on - - async def async_setup(hass, config): """Expose light control via state machine and services.""" component = hass.data[DOMAIN] = EntityComponent( @@ -199,10 +182,8 @@ async def async_setup(hass, config): ) await component.async_setup(config) - # load profiles from files - profiles_valid = await Profiles.load_profiles(hass) - if not profiles_valid: - return False + profiles = hass.data[DATA_PROFILES] = Profiles(hass) + await profiles.async_initialize() def preprocess_data(data): """Preprocess the service data.""" @@ -212,7 +193,8 @@ async def async_setup(hass, config): if entity_field in data } - base["params"] = preprocess_turn_on_alternatives(data) + preprocess_turn_on_alternatives(hass, data) + base["params"] = data return base async def async_handle_light_on_service(light, call): @@ -223,17 +205,14 @@ async def async_setup(hass, config): params = call.data["params"] if not params: - default_profile = Profiles.get_default(light.entity_id) + profiles.apply_default(light.entity_id, params) - if default_profile is not None: - params = {ATTR_PROFILE: default_profile} - preprocess_turn_on_alternatives(params) - - elif ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params: + # Only process params once we processed brightness step + if params and ( + ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params + ): brightness = light.brightness if light.is_on else 0 - params = params.copy() - if ATTR_BRIGHTNESS_STEP in params: brightness += params.pop(ATTR_BRIGHTNESS_STEP) @@ -242,19 +221,18 @@ async def async_setup(hass, config): params[ATTR_BRIGHTNESS] = max(0, min(255, brightness)) - turn_light_off, off_params = preprocess_turn_off(params) - if turn_light_off: - await light.async_turn_off(**off_params) + preprocess_turn_on_alternatives(hass, params) + + # Zero brightness: Light will be turned off + if params.get(ATTR_BRIGHTNESS) == 0: + await light.async_turn_off(**filter_turn_off_params(params)) else: await light.async_turn_on(**params) async def async_handle_toggle_service(light, call): - """Handle toggling a light. - - If brightness is set to 0, this service will turn the light off. - """ + """Handle toggling a light.""" if light.is_on: - off_params = filter_turn_off_params(call.data["params"]) + off_params = filter_turn_off_params(call.data) await light.async_turn_off(**off_params) else: await async_handle_light_on_service(light, call) @@ -295,73 +273,89 @@ async def async_unload_entry(hass, entry): class Profiles: """Representation of available color profiles.""" - _all: Optional[Dict[str, Tuple[float, float, int]]] = None + SCHEMA = vol.Schema( + vol.Any( + vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte)), + vol.ExactSequence( + (str, cv.small_float, cv.small_float, cv.byte, cv.positive_int) + ), + ) + ) - @classmethod - async def load_profiles(cls, hass): - """Load and cache profiles.""" + def __init__(self, hass): + """Initialize profiles.""" + self.hass = hass + self.data = None - def load_profile_data(hass): - """Load built-in profiles and custom profiles.""" - profile_paths = [ - os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE), - hass.config.path(LIGHT_PROFILES_FILE), - ] - profiles = {} + def _load_profile_data(self): + """Load built-in profiles and custom profiles.""" + profile_paths = [ + os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE), + self.hass.config.path(LIGHT_PROFILES_FILE), + ] + profiles = {} - for profile_path in profile_paths: - if not os.path.isfile(profile_path): - continue - with open(profile_path) as inp: - reader = csv.reader(inp) + for profile_path in profile_paths: + if not os.path.isfile(profile_path): + continue + with open(profile_path) as inp: + reader = csv.reader(inp) - # Skip the header - next(reader, None) + # Skip the header + next(reader, None) - try: - for rec in reader: - ( - profile, - color_x, - color_y, - brightness, - *transition, - ) = PROFILE_SCHEMA(rec) + try: + for rec in reader: + ( + profile, + color_x, + color_y, + brightness, + *transition, + ) = Profiles.SCHEMA(rec) - transition = transition[0] if transition else 0 + transition = transition[0] if transition else 0 - profiles[profile] = ( - color_x, - color_y, - brightness, - transition, - ) - except vol.MultipleInvalid as ex: - _LOGGER.error( - "Error parsing light profile from %s: %s", profile_path, ex + profiles[profile] = color_util.color_xy_to_hs( + color_x, color_y + ) + ( + brightness, + transition, ) - return None - return profiles + except vol.MultipleInvalid as ex: + _LOGGER.error( + "Error parsing light profile from %s: %s", profile_path, ex + ) + continue + return profiles - cls._all = await hass.async_add_executor_job(load_profile_data, hass) - return cls._all is not None + async def async_initialize(self): + """Load and cache profiles.""" + self.data = await self.hass.async_add_executor_job(self._load_profile_data) - @classmethod - def get(cls, name): - """Return a named profile.""" - return cls._all.get(name) - - @classmethod - def get_default(cls, entity_id): + @callback + def apply_default(self, entity_id, params): """Return the default turn-on profile for the given light.""" - # pylint: disable=unsupported-membership-test name = f"{entity_id}.default" - if name in cls._all: - return name + if name in self.data: + self.apply_profile(name, params) + return + name = "group.all_lights.default" - if name in cls._all: - return name - return None + if name in self.data: + self.apply_profile(name, params) + + @callback + def apply_profile(self, name, params): + """Apply a profile.""" + profile = self.data.get(name) + + if profile is None: + return + + params.setdefault(ATTR_HS_COLOR, profile[:2]) + params.setdefault(ATTR_BRIGHTNESS, profile[2]) + params.setdefault(ATTR_TRANSITION, profile[3]) class LightEntity(ToggleEntity): diff --git a/homeassistant/components/local_ip/translations/lb.json b/homeassistant/components/local_ip/translations/lb.json index 8d141a5f35f..877f1781e04 100644 --- a/homeassistant/components/local_ip/translations/lb.json +++ b/homeassistant/components/local_ip/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun Local IP ass erlaabt." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "user": { diff --git a/homeassistant/components/locative/strings.json b/homeassistant/components/locative/strings.json index 3a5821f40b1..d7149122be2 100644 --- a/homeassistant/components/locative/strings.json +++ b/homeassistant/components/locative/strings.json @@ -3,12 +3,12 @@ "step": { "user": { "title": "Set up the Locative Webhook", - "description": "Are you sure you want to set up the Locative Webhook?" + "description": "[%key:common::config_flow::description::confirm_setup%]" } }, "abort": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Geofency." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send locations to Home Assistant, you will need to setup the webhook feature in the Locative app.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/locative/translations/bg.json b/homeassistant/components/locative/translations/bg.json index 540724e578f..b75490ab4f8 100644 --- a/homeassistant/components/locative/translations/bg.json +++ b/homeassistant/components/locative/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 Geofency", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u044a\u043c Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0442\u0430 webhook \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u0442\u043e Locative. \n\n \u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: \n\n - URL: ` {webhook_url} ` \n - \u041c\u0435\u0442\u043e\u0434: POST \n\n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438." }, diff --git a/homeassistant/components/locative/translations/ca.json b/homeassistant/components/locative/translations/ca.json index 89dcafd65d5..637b937a568 100644 --- a/homeassistant/components/locative/translations/ca.json +++ b/homeassistant/components/locative/translations/ca.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de Geofency.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar ubicacions a Home Assistant, haur\u00e0s de configurar l'opci\u00f3 webhook de l'aplicaci\u00f3 Locative.\n\nCompleta la seg\u00fcent informaci\u00f3:\n\n- URL: `{webhook_url}` \n- M\u00e8tode: POST \n\nConsulta la [documentaci\u00f3]({docs_url}) per a m\u00e9s detalls." }, "step": { "user": { - "description": "Est\u00e0s segur que vols configurar el Webhook de Locative?", + "description": "Vols comen\u00e7ar la configuraci\u00f3?", "title": "Configuraci\u00f3 del Webhook de Locative" } } diff --git a/homeassistant/components/locative/translations/cs.json b/homeassistant/components/locative/translations/cs.json index 4459aac99c8..ac989f46dd3 100644 --- a/homeassistant/components/locative/translations/cs.json +++ b/homeassistant/components/locative/translations/cs.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "V\u00e1\u0161 Home Asistent mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy od Geofency.", - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "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 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": { - "description": "Opravdu chcete nastavit Locative Webhook?", + "description": "Chcete za\u010d\u00edt nastavovat?", "title": "Nastavit Locative Webhook" } } diff --git a/homeassistant/components/locative/translations/da.json b/homeassistant/components/locative/translations/da.json index afee5b832cc..2401428eff4 100644 --- a/homeassistant/components/locative/translations/da.json +++ b/homeassistant/components/locative/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage Geofency-meddelelser.", - "one_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning" - }, "create_entry": { "default": "For at sende lokationer til Home Assistant skal du konfigurere webhook funktionen i Locative applicationen.\n\n Udfyld f\u00f8lgende oplysninger: \n\n - URL: `{webhook_url}`\n - Metode: POST\n \n Se [dokumentationen]({docs_url}) for yderligere oplysninger." }, diff --git a/homeassistant/components/locative/translations/de.json b/homeassistant/components/locative/translations/de.json index 482d43c7117..32617094146 100644 --- a/homeassistant/components/locative/translations/de.json +++ b/homeassistant/components/locative/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Deine Home-Assistant-Instanz muss aus dem internet erreichbar sein, um Nachrichten von Geofency zu erhalten.", - "one_instance_allowed": "Nur eine einzige Instanz ist notwendig." - }, "create_entry": { "default": "Um Standorte Home Assistant zu senden, muss das Webhook Feature in der Locative App konfiguriert werden.\n\n F\u00fcge die folgenden Informationen ein: \n\n - URL: ` {webhook_url} ` \n - Methode: POST \n \n Weitere Informationen finden sich in der [Dokumentation]({docs_url})." }, diff --git a/homeassistant/components/locative/translations/en.json b/homeassistant/components/locative/translations/en.json index 59ff777603e..760835c8ea8 100644 --- a/homeassistant/components/locative/translations/en.json +++ b/homeassistant/components/locative/translations/en.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Geofency.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send locations to Home Assistant, you will need to setup the webhook feature in the Locative app.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details." }, "step": { "user": { - "description": "Are you sure you want to set up the Locative Webhook?", + "description": "Do you want to start set up?", "title": "Set up the Locative Webhook" } } diff --git a/homeassistant/components/locative/translations/es-419.json b/homeassistant/components/locative/translations/es-419.json index d28fb541825..e5017ad061a 100644 --- a/homeassistant/components/locative/translations/es-419.json +++ b/homeassistant/components/locative/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Geofency.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar ubicaciones a Home Assistant, deber\u00e1 configurar la funci\u00f3n de webhook en la aplicaci\u00f3n Locative. \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n\n Vea [la documentaci\u00f3n] ( {docs_url} ) para m\u00e1s detalles." }, diff --git a/homeassistant/components/locative/translations/es.json b/homeassistant/components/locative/translations/es.json index 11c789ddaed..9fa02248d42 100644 --- a/homeassistant/components/locative/translations/es.json +++ b/homeassistant/components/locative/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Tu Home Assistant debe ser accesible desde Internet para recibir mensajes de Geofency.", - "one_instance_allowed": "S\u00f3lo se necesita una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar ubicaciones a Home Assistant, es necesario configurar la caracter\u00edstica webhook en la app de Locative.\n\nRellena la siguiente informaci\u00f3n:\n\n- URL: `{webhook_url}`\n- M\u00e9todo: POST\n\nRevisa [la documentaci\u00f3n]({docs_url}) para m\u00e1s detalles." diff --git a/homeassistant/components/locative/translations/et.json b/homeassistant/components/locative/translations/et.json index 6fcb3233725..e73ad4da420 100644 --- a/homeassistant/components/locative/translations/et.json +++ b/homeassistant/components/locative/translations/et.json @@ -1,12 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Lubatud on ainult \u00fcks sidumine.", - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." + }, + "create_entry": { + "default": "S\u00fcndmuste saatmiseks Home Assistantile pead seadistama Locative veebihaagi. \n\n Sisesta j\u00e4rgmine teave: \n\n - URL: \" {webhook_url} \" \n - Meetod: POST \n \n Lisateavet leiad [documentation] ( {docs_url} )." }, "step": { "user": { - "description": "Kas soovid seadistada Locative Webhook'i?" + "description": "Kas soovid seadistamist alustada?", + "title": "Seadista Locative Webhook" } } } diff --git a/homeassistant/components/locative/translations/fr.json b/homeassistant/components/locative/translations/fr.json index 1327b2d0f8b..d17ede01d2e 100644 --- a/homeassistant/components/locative/translations/fr.json +++ b/homeassistant/components/locative/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance Home Assistant doit \u00eatre accessible \u00e0 partir d'Internet pour recevoir les messages Geofency.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des localisations \u00e0 Home Assistant, vous devez configurer la fonctionnalit\u00e9 Webhook dans l'application Locative. \n\n Remplissez les informations suivantes: \n\n - URL: ` {webhook_url} ` \n - M\u00e9thode: POST \n\n Voir [la documentation] ( {docs_url} ) pour plus de d\u00e9tails." diff --git a/homeassistant/components/locative/translations/hu.json b/homeassistant/components/locative/translations/hu.json index 7e3fe9bcb0f..a8c8bc05539 100644 --- a/homeassistant/components/locative/translations/hu.json +++ b/homeassistant/components/locative/translations/hu.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Az Home Assistantnek el\u00e9rhet\u0151nek kell lennie az internetr\u0151l, hogy megkapja a Geofency \u00fczeneteit.", - "one_instance_allowed": "Csak egy p\u00e9ld\u00e1ny sz\u00fcks\u00e9ges." - }, "step": { "user": { "description": "Biztosan be szeretn\u00e9d \u00e1ll\u00edtani a Locative Webhook-ot?", diff --git a/homeassistant/components/locative/translations/it.json b/homeassistant/components/locative/translations/it.json index 37e47c11aef..8e39c244555 100644 --- a/homeassistant/components/locative/translations/it.json +++ b/homeassistant/components/locative/translations/it.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi da Geofency.", - "one_instance_allowed": "\u00c8 necessaria una sola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare localit\u00e0 a Home Assistant, dovrai configurare la funzionalit\u00e0 Webhook nell'app Locative.\n\n Compila le seguenti informazioni: \n\n - URL: `{webhook_url}` \n - Method: POST \n\n Vedi [la documentazione]({docs_url}) for ulteriori dettagli." }, "step": { "user": { - "description": "Sei sicuro di voler configurare il webhook di Locative?", + "description": "Vuoi iniziare la configurazione?", "title": "Configura il webhook di Locative" } } diff --git a/homeassistant/components/locative/translations/ko.json b/homeassistant/components/locative/translations/ko.json index 73767678df4..eb10a8ca167 100644 --- a/homeassistant/components/locative/translations/ko.json +++ b/homeassistant/components/locative/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Locative \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\ub824\uba74 Locative \uc571\uc5d0\uc11c \uc6f9 \ud6c5\uc744 \uc124\uc815\ud574\uc57c\ud569\ub2c8\ub2e4. \n\n\ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694:\n\n - URL: `{webhook_url}`\n - Method: POST\n \n \uc790\uc138\ud55c \uc815\ubcf4\ub294 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/locative/translations/lb.json b/homeassistant/components/locative/translations/lb.json index 06d303ff0b1..bafc7d93459 100644 --- a/homeassistant/components/locative/translations/lb.json +++ b/homeassistant/components/locative/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir Geofency Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { diff --git a/homeassistant/components/locative/translations/nl.json b/homeassistant/components/locative/translations/nl.json index 340eeecb0a6..e02378432ab 100644 --- a/homeassistant/components/locative/translations/nl.json +++ b/homeassistant/components/locative/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Je Home Assistant instance moet bereikbaar zijn vanuit het internet om berichten van Geofency te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/locative/translations/no.json b/homeassistant/components/locative/translations/no.json index d061448ddfe..7eca10016ea 100644 --- a/homeassistant/components/locative/translations/no.json +++ b/homeassistant/components/locative/translations/no.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta meldinger fra Geofency.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { "default": "For \u00e5 kunne sende plasseringer til Home Assistant, m\u00e5 du sette opp webhook-funksjonen i Locative appen. \n\n Fyll ut f\u00f8lgende informasjon: \n\n - URL: `{webhook_url}` \n - Metode: POST \n\nSe [dokumentasjonen]({docs_url}) for ytterligere detaljer." }, "step": { "user": { - "description": "Er du sikker p\u00e5 at du vil sette opp Locative Webhook?", + "description": "Vil du starte oppsettet?", "title": "Sett opp Locative Webhook" } } diff --git a/homeassistant/components/locative/translations/pl.json b/homeassistant/components/locative/translations/pl.json index a35913198ab..018bca1f99b 100644 --- a/homeassistant/components/locative/translations/pl.json +++ b/homeassistant/components/locative/translations/pl.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Twoja instancja Home Assistant musi by\u0107 dost\u0119pna z Internetu, aby otrzymywa\u0107 wiadomo\u015bci z Geofency", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 lokalizacje do Home Assistant, musisz skonfigurowa\u0107 webhook w aplikacji Locative. \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}), by pozna\u0107 szczeg\u00f3\u0142y." }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 Locative Webhook?", + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", "title": "Konfiguracja Locative Webhook" } } diff --git a/homeassistant/components/locative/translations/pt-BR.json b/homeassistant/components/locative/translations/pt-BR.json index 11ea7c671b0..20bcaaad643 100644 --- a/homeassistant/components/locative/translations/pt-BR.json +++ b/homeassistant/components/locative/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia do Home Assistant precisa estar acess\u00edvel na Internet para receber mensagens da Geofency.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar locais para o Home Assistant, voc\u00ea precisar\u00e1 configurar o recurso webhook no aplicativo Locative. \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n\n Veja [a documenta\u00e7\u00e3o] ( {docs_url} ) para mais detalhes." }, diff --git a/homeassistant/components/locative/translations/pt.json b/homeassistant/components/locative/translations/pt.json index e7091e19c09..6ca0b0b1948 100644 --- a/homeassistant/components/locative/translations/pt.json +++ b/homeassistant/components/locative/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A sua inst\u00e2ncia Home Assistent precisa de ser acess\u00edvel a partir da internet para receber mensagens Geofency.", - "one_instance_allowed": "Apenas uma inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, \u00e9 necess\u00e1rio configurar um webhook no Locative. \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: `{webhook_url}`\n - M\u00e9todo: POST \n\n Veja [the documentation]({docs_url}) para obter mais detalhes." }, diff --git a/homeassistant/components/locative/translations/ru.json b/homeassistant/components/locative/translations/ru.json index 0981c9f2f1c..c9fc9cfd36a 100644 --- a/homeassistant/components/locative/translations/ru.json +++ b/homeassistant/components/locative/translations/ru.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 Locative.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Webhook \u0434\u043b\u044f Locative.\n\n\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\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 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438." }, "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 Locative?", + "description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443?", "title": "Locative" } } diff --git a/homeassistant/components/locative/translations/sl.json b/homeassistant/components/locative/translations/sl.json index 13a2a33aa5f..270eff28a0b 100644 --- a/homeassistant/components/locative/translations/sl.json +++ b/homeassistant/components/locative/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Va\u0161 Home Assistant mora biti dostopek prek interneta, da boste lahko prejemali Geofency sporo\u010dila.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "Za po\u0161iljanje lokacij v Home Assistant, morate namestiti funkcijo webhook v aplikaciji Locative. \n\n Izpolnite naslednje podatke: \n\n - URL: ` {webhook_url} ` \n - Metoda: POST \n\n Za ve\u010d podrobnosti si oglejte [dokumentacijo] ( {docs_url} )." }, diff --git a/homeassistant/components/locative/translations/sv.json b/homeassistant/components/locative/translations/sv.json index 45185a5feca..7f1991f8a7b 100644 --- a/homeassistant/components/locative/translations/sv.json +++ b/homeassistant/components/locative/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant instans m\u00e5ste vara \u00e5tkomlig ifr\u00e5n internet f\u00f6r att ta emot meddelanden ifr\u00e5n Geofency.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du konfigurera webhook funktionen i Locative appen.\n\n Fyll i f\u00f6ljande information:\n \n- URL: `{webhook_url}`\n- Method: POST\n\nSe [dokumentation]({docs_url}) om hur du konfigurerar detta f\u00f6r mer information." }, diff --git a/homeassistant/components/locative/translations/zh-Hans.json b/homeassistant/components/locative/translations/zh-Hans.json index 9a7245396a1..00eaf2929dd 100644 --- a/homeassistant/components/locative/translations/zh-Hans.json +++ b/homeassistant/components/locative/translations/zh-Hans.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u53ef\u4ece\u4e92\u8054\u7f51\u8bbf\u95ee\u4ee5\u63a5\u6536 Geofency \u6d88\u606f\u3002", - "one_instance_allowed": "\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u662f\u5fc5\u9700\u7684\u3002" - }, "create_entry": { "default": "\u8981\u5411 Home Assistant \u53d1\u9001\u4e8b\u4ef6\uff0c\u60a8\u9700\u8981\u914d\u7f6e Locative app \u7684 Webhook \u529f\u80fd\u3002\n\n\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\u8bf7\u53c2\u9605[\u6587\u6863]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u591a\u4fe1\u606f\u3002" }, diff --git a/homeassistant/components/locative/translations/zh-Hant.json b/homeassistant/components/locative/translations/zh-Hant.json index f84a40c1152..65dc4ff8da7 100644 --- a/homeassistant/components/locative/translations/zh-Hant.json +++ b/homeassistant/components/locative/translations/zh-Hant.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u8a2d\u5099\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 Locative \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u5ea7\u6a19\u81f3 Home Assistant\uff0c\u5c07\u9700\u65bc Locative App \u5167\u8a2d\u5b9a webhook \u529f\u80fd\u3002\n\n\u8acb\u586b\u5beb\u4e0b\u5217\u8cc7\u8a0a\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\u8acb\u53c3\u95b1 [\u6587\u4ef6]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u8a73\u7d30\u8cc7\u6599\u3002" }, "step": { "user": { - "description": "\u662f\u5426\u8981\u8a2d\u5b9a Locative Webhook\uff1f", + "description": "\u662f\u5426\u8981\u958b\u59cb\u8a2d\u5b9a\uff1f", "title": "\u8a2d\u5b9a Locative Webhook" } } diff --git a/homeassistant/components/lock/translations/zh-Hans.json b/homeassistant/components/lock/translations/zh-Hans.json index 07ab36a2d4d..4999c52f8e0 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/bg.json b/homeassistant/components/logi_circle/translations/bg.json index 792290656df..469532fdc73 100644 --- a/homeassistant/components/logi_circle/translations/bg.json +++ b/homeassistant/components/logi_circle/translations/bg.json @@ -1,17 +1,10 @@ { "config": { "abort": { - "already_setup": "\u041c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u0438\u043d Logi Circle \u0430\u043a\u0430\u0443\u043d\u0442.", "external_error": "\u0413\u0440\u0435\u0448\u043a\u0430 \u0432\u044a\u0437\u043d\u0438\u043a\u043d\u0430 \u0432 \u0434\u0440\u0443\u0433 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441.", - "external_setup": "Logi Circle \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d \u043e\u0442 \u0434\u0440\u0443\u0433 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441.", - "no_flows": "\u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 Logi Circle, \u043f\u0440\u0435\u0434\u0438 \u0434\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0430\u0442\u0435. [\u041c\u043e\u043b\u044f, \u043f\u0440\u043e\u0447\u0435\u0442\u0435\u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438\u0442\u0435](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "\u0423\u0441\u043f\u0435\u0448\u043d\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0438\u0440\u0430\u043d\u0435 \u0441 Logi Circle." + "external_setup": "Logi Circle \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d \u043e\u0442 \u0434\u0440\u0443\u0433 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441." }, "error": { - "auth_error": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u043e\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0441 API.", - "auth_timeout": "\u0418\u0437\u0442\u0435\u0447\u0435 \u0432\u0440\u0435\u043c\u0435\u0442\u043e \u0437\u0430 \u043e\u0442\u043e\u0440\u0438\u0437\u0438\u0446\u0438\u044f, \u0434\u043e\u043a\u0430\u0442\u043e \u0438\u0437\u0438\u0441\u043a\u0432\u0430\u0445\u043c\u0435 \u043a\u043e\u0434 \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f", "follow_link": "\u041c\u043e\u043b\u044f, \u043f\u043e\u0441\u043b\u0435\u0434\u0432\u0430\u0439\u0442\u0435 \u0432\u0440\u044a\u0437\u043a\u0430\u0442\u0430 \u0438 \u0441\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0438\u0440\u0430\u0439\u0442\u0435, \u043f\u0440\u0435\u0434\u0438 \u0434\u0430 \u043d\u0430\u0442\u0438\u0441\u043d\u0435\u0442\u0435 \u0418\u0437\u043f\u0440\u0430\u0449\u0430\u043d\u0435." }, "step": { diff --git a/homeassistant/components/logi_circle/translations/ca.json b/homeassistant/components/logi_circle/translations/ca.json index 5ce57701408..9f46b3f621a 100644 --- a/homeassistant/components/logi_circle/translations/ca.json +++ b/homeassistant/components/logi_circle/translations/ca.json @@ -2,18 +2,11 @@ "config": { "abort": { "already_configured": "El compte ja ha estat configurat", - "already_setup": "Nom\u00e9s pots configurar un \u00fanic compte de Logi Circule.", "external_error": "S'ha produ\u00eft una excepci\u00f3 d'un altre flux de dades.", "external_setup": "Logi Circle s'ha configurat correctament des d'un altre flux de dades.", - "missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3.", - "no_flows": "Necessites configurar Logi Circle abans de poder autenticar-t'hi. Llegeix les [instruccions](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Autenticaci\u00f3 exitosa amb Logi Circle." + "missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3." }, "error": { - "auth_error": "Ha fallat l'autoritzaci\u00f3 de l'API.", - "auth_timeout": "L'autoritzaci\u00f3 ha expirat durant l'obtenci\u00f3 del token d'acc\u00e9s.", "authorize_url_timeout": "Temps d'espera esgotat durant la generaci\u00f3 de l'URL d'autoritzaci\u00f3.", "follow_link": "V\u00e9s a l'enlla\u00e7 i autentica't abans de pr\u00e9mer Envia", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" diff --git a/homeassistant/components/logi_circle/translations/cs.json b/homeassistant/components/logi_circle/translations/cs.json index 26a2ef1eb0d..b6d6796b403 100644 --- a/homeassistant/components/logi_circle/translations/cs.json +++ b/homeassistant/components/logi_circle/translations/cs.json @@ -2,15 +2,12 @@ "config": { "abort": { "already_configured": "\u00da\u010det je ji\u017e nastaven", - "already_setup": "M\u016f\u017eete nastavit pouze jeden \u00fa\u010det Logi Circle.", "external_setup": "Logi Circle \u00fasp\u011b\u0161n\u011b nastaveno jin\u00fdm zp\u016fsobem.", "missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace." }, - "create_entry": { - "default": "\u00dasp\u011b\u0161n\u011b ov\u011b\u0159eno pomoc\u00ed Logi Circle." - }, "error": { "authorize_url_timeout": "\u010casov\u00fd limit autoriza\u010dn\u00edho URL vypr\u0161el", + "follow_link": "Postupujte podle odkazu a prove\u010fte ov\u011b\u0159en\u00ed p\u0159ed stisknut\u00edm tla\u010d\u00edtka Odeslat.", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { diff --git a/homeassistant/components/logi_circle/translations/da.json b/homeassistant/components/logi_circle/translations/da.json index fecab818295..6f835d58671 100644 --- a/homeassistant/components/logi_circle/translations/da.json +++ b/homeassistant/components/logi_circle/translations/da.json @@ -1,17 +1,10 @@ { "config": { "abort": { - "already_setup": "Du kan kun konfigurere en enkelt Logi Circle-konto.", "external_error": "Undtagelse skete fra et andet flow.", - "external_setup": "Logi Circle er konfigureret med succes fra et andet flow.", - "no_flows": "Du skal konfigurere Logi Circle f\u00f8r du kan godkende med det. [L\u00e6s venligst vejledningen](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Godkendt med Logi Circle." + "external_setup": "Logi Circle er konfigureret med succes fra et andet flow." }, "error": { - "auth_error": "API-godkendelse mislykkedes.", - "auth_timeout": "Godkendelsen fik timeout ved anmodning om adgangstoken.", "follow_link": "F\u00f8lg linket og godkend f\u00f8r du trykker p\u00e5 send." }, "step": { diff --git a/homeassistant/components/logi_circle/translations/de.json b/homeassistant/components/logi_circle/translations/de.json index 81292c8306d..ab4a194fda0 100644 --- a/homeassistant/components/logi_circle/translations/de.json +++ b/homeassistant/components/logi_circle/translations/de.json @@ -1,17 +1,10 @@ { "config": { "abort": { - "already_setup": "Es kann nur ein einziges Logi Circle-Konto konfiguriert werden.", "external_error": "Es ist eine Ausnahme in einem anderen Flow aufgetreten.", - "external_setup": "Logi Circle wurde erfolgreich aus einem anderen Flow konfiguriert.", - "no_flows": "Logi Circle muss konfiguriert werden, bevor die Authentifizierung erfolgen kann. [Bitte lies die Anweisungen] (https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Erfolgreiche Authentifizierung mit Logi Circle." + "external_setup": "Logi Circle wurde erfolgreich aus einem anderen Flow konfiguriert." }, "error": { - "auth_error": "Die API-Autorisierung ist fehlgeschlagen.", - "auth_timeout": "Zeit\u00fcberschreitung der Autorisierung beim Anfordern des Zugriffstokens.", "follow_link": "Bitte folge dem Link und authentifiziere dich, bevor du auf Senden klickst." }, "step": { diff --git a/homeassistant/components/logi_circle/translations/en.json b/homeassistant/components/logi_circle/translations/en.json index 999347768d3..d9eccca4fb4 100644 --- a/homeassistant/components/logi_circle/translations/en.json +++ b/homeassistant/components/logi_circle/translations/en.json @@ -2,18 +2,11 @@ "config": { "abort": { "already_configured": "Account is already configured", - "already_setup": "You can only configure a single Logi Circle account.", "external_error": "Exception occurred from another flow.", "external_setup": "Logi Circle successfully configured from another flow.", - "missing_configuration": "The component is not configured. Please follow the documentation.", - "no_flows": "You need to configure Logi Circle before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Successfully authenticated with Logi Circle." + "missing_configuration": "The component is not configured. Please follow the documentation." }, "error": { - "auth_error": "API authorization failed.", - "auth_timeout": "Authorization timed out when requesting access token.", "authorize_url_timeout": "Timeout generating authorize URL.", "follow_link": "Please follow the link and authenticate before pressing Submit.", "invalid_auth": "Invalid authentication" diff --git a/homeassistant/components/logi_circle/translations/es-419.json b/homeassistant/components/logi_circle/translations/es-419.json index 4f512189b32..22baee72628 100644 --- a/homeassistant/components/logi_circle/translations/es-419.json +++ b/homeassistant/components/logi_circle/translations/es-419.json @@ -1,17 +1,10 @@ { "config": { "abort": { - "already_setup": "Solo puede configurar una sola cuenta de Logi Circle.", "external_error": "Se produjo una excepci\u00f3n de otro flujo.", - "external_setup": "Logi Circle se configur\u00f3 correctamente desde otro flujo.", - "no_flows": "Debe configurar Logi Circle antes de poder autenticarse con \u00e9l. [Lea las instrucciones] (https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Autenticado con \u00e9xito con Logi Circle." + "external_setup": "Logi Circle se configur\u00f3 correctamente desde otro flujo." }, "error": { - "auth_error": "Autorizaci\u00f3n de API fallida.", - "auth_timeout": "La autorizaci\u00f3n agot\u00f3 el tiempo de espera al solicitar el token de acceso.", "follow_link": "Siga el enlace y autent\u00edquese antes de presionar Enviar." }, "step": { diff --git a/homeassistant/components/logi_circle/translations/es.json b/homeassistant/components/logi_circle/translations/es.json index 58044b73335..6bd99289230 100644 --- a/homeassistant/components/logi_circle/translations/es.json +++ b/homeassistant/components/logi_circle/translations/es.json @@ -2,18 +2,11 @@ "config": { "abort": { "already_configured": "La cuenta ya ha sido configurada", - "already_setup": "Solo puedes configurar una cuenta de Logi Circle.", "external_error": "Se produjo una excepci\u00f3n de otro flujo.", "external_setup": "Logi Circle se ha configurado correctamente a partir de otro flujo.", - "missing_configuration": "El componente no est\u00e1 configurado. Consulta la documentaci\u00f3n.", - "no_flows": "Es necesario configurar Logi Circle antes de poder autenticarse con \u00e9l. [Echa un vistazo a las instrucciones] (https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Autenticado correctamente con Logi Circle." + "missing_configuration": "El componente no est\u00e1 configurado. Consulta la documentaci\u00f3n." }, "error": { - "auth_error": "Error en la autorizaci\u00f3n de la API.", - "auth_timeout": "Se ha agotado el tiempo de espera de la autorizaci\u00f3n al solicitar el token de acceso.", "authorize_url_timeout": "Tiempo de espera agotado generando la url de autorizaci\u00f3n.", "follow_link": "Accede al enlace e identif\u00edcate antes de pulsar Enviar.", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" diff --git a/homeassistant/components/logi_circle/translations/et.json b/homeassistant/components/logi_circle/translations/et.json index 9508a1b2571..3aff36b4061 100644 --- a/homeassistant/components/logi_circle/translations/et.json +++ b/homeassistant/components/logi_circle/translations/et.json @@ -2,12 +2,27 @@ "config": { "abort": { "already_configured": "Konto on juba seadistatud", - "already_setup": "Saad h\u00e4\u00e4lestada ainult \u00fche Logi Circle konto.", + "external_error": "V\u00e4lise voo viga.", + "external_setup": "Logi Circle on teisest voost edukalt seadistatud.", "missing_configuration": "Osis pole seadistatud. Palun vaata dokumentatsiooni." }, "error": { "authorize_url_timeout": "Tuvastamise URL'i loomise ajal\u00f5pp.", + "follow_link": "Palun j\u00e4rgige linki ja tuvasta enne Submit vajutamist.", "invalid_auth": "Tuvastamine eba\u00f5nnestus" + }, + "step": { + "auth": { + "description": "J\u00e4rgi seda linki [link] ( {authorization_url} ) ja ** Luba** juurdep\u00e4\u00e4s oma Logi Circle kontole, siis tule tagasi ja vajuta allolevat nuppu ** Esita **.\n\n [Link]({authorization_url})", + "title": "Autentimine Logi Circle'ga" + }, + "user": { + "data": { + "flow_impl": "Teenuse pakkuja" + }, + "description": "Vali millise autentimisteenuse pakkujaga soovid Logi Circle't autentida.", + "title": "Autentimisteenuse pakkuja" + } } } } \ No newline at end of file diff --git a/homeassistant/components/logi_circle/translations/fi.json b/homeassistant/components/logi_circle/translations/fi.json index 84fe07d445e..37992273efc 100644 --- a/homeassistant/components/logi_circle/translations/fi.json +++ b/homeassistant/components/logi_circle/translations/fi.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "auth_error": "API-todennus ep\u00e4onnistui." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/logi_circle/translations/fr.json b/homeassistant/components/logi_circle/translations/fr.json index 003f44963c9..7ac388ccb3f 100644 --- a/homeassistant/components/logi_circle/translations/fr.json +++ b/homeassistant/components/logi_circle/translations/fr.json @@ -1,18 +1,15 @@ { "config": { "abort": { - "already_setup": "Vous ne pouvez configurer qu'un seul compte Logi Circle.", + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "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.", - "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": { - "default": "Authentifi\u00e9 avec succ\u00e8s avec Logi Circle." + "missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation." }, "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/logi_circle/translations/hu.json b/homeassistant/components/logi_circle/translations/hu.json index 8e304fa4ac9..04c8229f5ff 100644 --- a/homeassistant/components/logi_circle/translations/hu.json +++ b/homeassistant/components/logi_circle/translations/hu.json @@ -1,8 +1,6 @@ { "config": { "error": { - "auth_error": "Az API enged\u00e9lyez\u00e9se sikertelen.", - "auth_timeout": "A hozz\u00e1f\u00e9r\u00e9si token k\u00e9r\u00e9sekor az enged\u00e9lyez\u00e9s lej\u00e1rt.", "follow_link": "K\u00e9rlek, k\u00f6vesd a hivatkoz\u00e1st \u00e9s hiteles\u00edtsd magad miel\u0151tt megnyomod a K\u00fcld\u00e9s gombot" }, "step": { diff --git a/homeassistant/components/logi_circle/translations/it.json b/homeassistant/components/logi_circle/translations/it.json index d1dc253e79c..1299c4c53e4 100644 --- a/homeassistant/components/logi_circle/translations/it.json +++ b/homeassistant/components/logi_circle/translations/it.json @@ -2,18 +2,11 @@ "config": { "abort": { "already_configured": "L'account \u00e8 gi\u00e0 configurato", - "already_setup": "\u00c8 possibile configurare solo un singolo account Logi Circle.", "external_error": "Si \u00e8 verificata un'eccezione da un altro flusso.", "external_setup": "Logi Circle configurato con successo da un altro flusso.", - "missing_configuration": "Il componente non \u00e8 configurato. Si prega di seguire la documentazione.", - "no_flows": "Devi configurare Logi Circle prima di poter eseguire l'autenticazione. [Si prega di leggere le istruzioni](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Autenticato con successo con Logi Circle." + "missing_configuration": "Il componente non \u00e8 configurato. Si prega di seguire la documentazione." }, "error": { - "auth_error": "Autorizzazione API fallita.", - "auth_timeout": "Timeout dell'autorizzazione durante la richiesta del token di accesso.", "authorize_url_timeout": "Tempo scaduto nel generare l'URL di autorizzazione.", "follow_link": "Segui il link e autenticati prima di premere Invia", "invalid_auth": "Autenticazione non valida" diff --git a/homeassistant/components/logi_circle/translations/ko.json b/homeassistant/components/logi_circle/translations/ko.json index 97c4d755184..3fe8ce4824e 100644 --- a/homeassistant/components/logi_circle/translations/ko.json +++ b/homeassistant/components/logi_circle/translations/ko.json @@ -1,17 +1,10 @@ { "config": { "abort": { - "already_setup": "\ud558\ub098\uc758 Logi Circle \uacc4\uc815\ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.", "external_error": "\ub2e4\ub978 \uad6c\uc131 \ub2e8\uacc4\uc5d0\uc11c \uc608\uc678\uc0ac\ud56d\uc774 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.", - "external_setup": "Logi Circle \uc774 \ub2e4\ub978 \uad6c\uc131 \ub2e8\uacc4\uc5d0\uc11c \uc131\uacf5\uc801\uc73c\ub85c \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "no_flows": "Logi Circle \uc744 \uc778\uc99d\ud558\ub824\uba74 \uba3c\uc800 Logi Circle \uc744 \uad6c\uc131\ud574\uc57c \ud569\ub2c8\ub2e4. [\uc548\ub0b4](https://www.home-assistant.io/components/logi_circle/) \ub97c \uc77d\uc5b4\ubcf4\uc138\uc694." - }, - "create_entry": { - "default": "Logi Circle \ub85c \uc131\uacf5\uc801\uc73c\ub85c \uc778\uc99d\ub418\uc5c8\uc2b5\ub2c8\ub2e4." + "external_setup": "Logi Circle \uc774 \ub2e4\ub978 \uad6c\uc131 \ub2e8\uacc4\uc5d0\uc11c \uc131\uacf5\uc801\uc73c\ub85c \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "error": { - "auth_error": "API \uc2b9\uc778\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4.", - "auth_timeout": "\uc5d1\uc138\uc2a4 \ud1a0\ud070 \uc694\uccad\uc911 \uc2b9\uc778 \uc2dc\uac04\uc774 \ucd08\uacfc\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "follow_link": "\ud655\uc778\uc744 \ud074\ub9ad\ud558\uae30 \uc804\uc5d0 \ub9c1\ud06c\ub97c \ub530\ub77c \uc778\uc99d\uc744 \ubc1b\uc544\uc8fc\uc138\uc694" }, "step": { diff --git a/homeassistant/components/logi_circle/translations/lb.json b/homeassistant/components/logi_circle/translations/lb.json index dfa829ba8cd..fab157b2655 100644 --- a/homeassistant/components/logi_circle/translations/lb.json +++ b/homeassistant/components/logi_circle/translations/lb.json @@ -1,18 +1,14 @@ { "config": { "abort": { - "already_setup": "Dir k\u00ebnnt n\u00ebmmen een eenzegen Logi Circle Kont konfigur\u00e9ieren.", + "already_configured": "Kont ass scho registr\u00e9iert", "external_error": "Ausnam vun engem anere Floss.", "external_setup": "Logi Circle gouf vun engem anere Floss erfollegr\u00e4ich konfigur\u00e9iert.", - "no_flows": "Dir musst Logi Circle konfigur\u00e9ieren, ier Dir d\u00ebs Authentifiz\u00e9ierung k\u00ebnnt benotzen.[Liest w.e.g. d'Instruktioune](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Erfollegr\u00e4ich mat Logi Circle authentifiz\u00e9iert." + "missing_configuration": "Komponent net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun." }, "error": { - "auth_error": "Feeler bei der API Autorisatioun.", - "auth_timeout": "Z\u00e4it Iwwerschreidung vun der Autorisatioun beim ufroe vum Acc\u00e8s Jeton.", - "follow_link": "Follegt w.e.g dem Link an authentifiz\u00e9iert iech ier de op Ofsch\u00e9cken dr\u00e9ckt." + "follow_link": "Follegt w.e.g dem Link an authentifiz\u00e9iert iech ier de op Ofsch\u00e9cken dr\u00e9ckt.", + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "auth": { diff --git a/homeassistant/components/logi_circle/translations/nl.json b/homeassistant/components/logi_circle/translations/nl.json index 01b6309e90a..b521af1f969 100644 --- a/homeassistant/components/logi_circle/translations/nl.json +++ b/homeassistant/components/logi_circle/translations/nl.json @@ -1,18 +1,13 @@ { "config": { "abort": { - "already_setup": "U kunt slechts \u00e9\u00e9n Logi Circle-account configureren.", + "already_configured": "Account is al geconfigureerd", "external_error": "Uitzondering opgetreden uit een andere stroom.", - "external_setup": "Logi Circle is met succes geconfigureerd vanuit een andere stroom.", - "no_flows": "U moet Logi Circle configureren voordat u ermee kunt authenticeren. [Lees de instructies] (https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Succesvol geverifieerd met Logi Circle." + "external_setup": "Logi Circle is met succes geconfigureerd vanuit een andere stroom." }, "error": { - "auth_error": "API-autorisatie mislukt.", - "auth_timeout": "Er is een time-out opgetreden bij autorisatie bij het aanvragen van toegangstoken.", - "follow_link": "Volg de link en authenticeer voordat u op Verzenden drukt." + "follow_link": "Volg de link en authenticeer voordat u op Verzenden drukt.", + "invalid_auth": "Ongeldige authenticatie" }, "step": { "auth": { diff --git a/homeassistant/components/logi_circle/translations/nn.json b/homeassistant/components/logi_circle/translations/nn.json index f6c91435c06..2aa0f77dfd9 100644 --- a/homeassistant/components/logi_circle/translations/nn.json +++ b/homeassistant/components/logi_circle/translations/nn.json @@ -1,11 +1,5 @@ { "config": { - "create_entry": { - "default": "Vellukka autentisering med Logi Circle" - }, - "error": { - "auth_error": "API-autorisasjonen mislyktes." - }, "step": { "auth": { "title": "Godkjenn med Logi Circle" diff --git a/homeassistant/components/logi_circle/translations/no.json b/homeassistant/components/logi_circle/translations/no.json index 181697d95f6..14ffab87116 100644 --- a/homeassistant/components/logi_circle/translations/no.json +++ b/homeassistant/components/logi_circle/translations/no.json @@ -2,18 +2,11 @@ "config": { "abort": { "already_configured": "Kontoen er allerede konfigurert", - "already_setup": "Du kan bare konfigurere en Logi Circle konto.", "external_error": "Det oppstod et unntak fra en annen flow.", "external_setup": "Logi Circle er vellykket konfigurert fra en annen flow.", - "missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen.", - "no_flows": "Du m\u00e5 konfigurere Logi Circle f\u00f8r du kan godkjenne den. [Vennligst les instruksjonene](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Vellykket godkjenning med Logi Circle" + "missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen." }, "error": { - "auth_error": "API-godkjenning mislyktes.", - "auth_timeout": "Godkjenningen ble tidsavbrutt ved foresp\u00f8rsel om token.", "authorize_url_timeout": "Tidsavbrudd som genererer autorer URL-adresse.", "follow_link": "Vennligst f\u00f8lg lenken og godkjenn f\u00f8r du trykker send.", "invalid_auth": "Ugyldig godkjenning" diff --git a/homeassistant/components/logi_circle/translations/pl.json b/homeassistant/components/logi_circle/translations/pl.json index 19a1d945a83..0f9c7beebc7 100644 --- a/homeassistant/components/logi_circle/translations/pl.json +++ b/homeassistant/components/logi_circle/translations/pl.json @@ -2,18 +2,11 @@ "config": { "abort": { "already_configured": "Konto jest ju\u017c skonfigurowane", - "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno konto Logi Circle", "external_error": "Wyst\u0105pi\u0142 wyj\u0105tek z innego przep\u0142ywu", "external_setup": "Logi Circle zosta\u0142o pomy\u015blnie skonfigurowane z innego przep\u0142ywu", - "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105.", - "no_flows": "Musisz skonfigurowa\u0107 Logi Circle, aby m\u00f3c si\u0119 z nim uwierzytelni\u0107. Zapoznaj si\u0119 z [instrukcj\u0105](https://www.home-assistant.io/components/logi_circle/)" - }, - "create_entry": { - "default": "Pomy\u015blnie uwierzytelniono z Logi Circle." + "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105." }, "error": { - "auth_error": "Autoryzacja API nie powiod\u0142a si\u0119", - "auth_timeout": "Przekroczono limit czasu \u017c\u0105dania tokena dost\u0119pu", "authorize_url_timeout": "Przekroczono limit czasu generowania URL autoryzacji", "follow_link": "Post\u0119puj zgodnie z linkiem i uwierzytelnij si\u0119 przed naci\u015bni\u0119ciem przycisku \"Zatwierd\u017a\"", "invalid_auth": "Niepoprawne uwierzytelnienie" diff --git a/homeassistant/components/logi_circle/translations/pt-BR.json b/homeassistant/components/logi_circle/translations/pt-BR.json index ece65955dee..a319cf0e67e 100644 --- a/homeassistant/components/logi_circle/translations/pt-BR.json +++ b/homeassistant/components/logi_circle/translations/pt-BR.json @@ -1,17 +1,10 @@ { "config": { "abort": { - "already_setup": "Voc\u00ea s\u00f3 pode configurar uma \u00fanica conta do Logi Circle.", "external_error": "Exce\u00e7\u00e3o ocorreu a partir de outro fluxo.", - "external_setup": "Logi Circle configurado com sucesso a partir de outro fluxo.", - "no_flows": "Voc\u00ea precisa configurar o Logi Circle antes de poder autenticar com ele. [Por favor, leia as instru\u00e7\u00f5es] (https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Autenticado com sucesso com o Logi Circle." + "external_setup": "Logi Circle configurado com sucesso a partir de outro fluxo." }, "error": { - "auth_error": "Falha na autoriza\u00e7\u00e3o da API.", - "auth_timeout": "A autoriza\u00e7\u00e3o atingiu o tempo limite quando solicitou o token de acesso.", "follow_link": "Por favor, siga o link e autentique antes de pressionar Enviar." }, "step": { diff --git a/homeassistant/components/logi_circle/translations/ru.json b/homeassistant/components/logi_circle/translations/ru.json index 96699da2762..2a7ccc4f374 100644 --- a/homeassistant/components/logi_circle/translations/ru.json +++ b/homeassistant/components/logi_circle/translations/ru.json @@ -2,18 +2,11 @@ "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_setup": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "external_error": "\u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430.", "external_setup": "Logi Circle \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430.", - "missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438.", - "no_flows": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 Logi Circle \u043f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e." + "missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438." }, "error": { - "auth_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 API.", - "auth_timeout": "\u041f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.", "authorize_url_timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.", "follow_link": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0438 \u043f\u0440\u043e\u0439\u0434\u0438\u0442\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043d\u0430\u0436\u0430\u0442\u044c \"\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c\".", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." diff --git a/homeassistant/components/logi_circle/translations/sl.json b/homeassistant/components/logi_circle/translations/sl.json index e839d9864c2..21c1bd416bb 100644 --- a/homeassistant/components/logi_circle/translations/sl.json +++ b/homeassistant/components/logi_circle/translations/sl.json @@ -1,17 +1,10 @@ { "config": { "abort": { - "already_setup": "Nastavite lahko samo en ra\u010dun Logi Circle.", "external_error": "Izjema je pri\u0161la iz drugega toka.", - "external_setup": "Logi Circle uspe\u0161no konfiguriran iz drugega toka.", - "no_flows": "Preden lahko preverite pristnost, morate konfigurirati Logi Circle. [Preberite navodila](https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Uspe\u0161no overjen z Logi Circle-om." + "external_setup": "Logi Circle uspe\u0161no konfiguriran iz drugega toka." }, "error": { - "auth_error": "Odobritev API-ja ni uspela.", - "auth_timeout": "Pri zahtevi za dostopni \u017eeton je potekla \u010dasovna omejitev.", "follow_link": "Prosimo, sledite povezavi in preverite pristnost, preden pritisnete Po\u0161lji" }, "step": { diff --git a/homeassistant/components/logi_circle/translations/sv.json b/homeassistant/components/logi_circle/translations/sv.json index d0ea36f7bfc..0d4d01c062b 100644 --- a/homeassistant/components/logi_circle/translations/sv.json +++ b/homeassistant/components/logi_circle/translations/sv.json @@ -1,17 +1,10 @@ { "config": { "abort": { - "already_setup": "Du kan endast konfigurera ett Logi Circle-konto.", "external_error": "Undantag intr\u00e4ffade fr\u00e5n ett annat fl\u00f6de.", - "external_setup": "Logi Circle har konfigurerats fr\u00e5n ett annat fl\u00f6de.", - "no_flows": "Du m\u00e5ste konfigurera Logi Circle innan du kan autentisera med den. [V\u00e4nligen l\u00e4s instruktionerna] (https://www.home-assistant.io/components/logi_circle/)." - }, - "create_entry": { - "default": "Autentiserad med Logi Circle." + "external_setup": "Logi Circle har konfigurerats fr\u00e5n ett annat fl\u00f6de." }, "error": { - "auth_error": "API autentiseringen misslyckades.", - "auth_timeout": "Godk\u00e4nnandet tog f\u00f6r l\u00e5ng tid vid beg\u00e4ran om \u00e5tkomsttoken.", "follow_link": "V\u00e4nligen f\u00f6lj l\u00e4nken och autentisera innan du trycker p\u00e5 Skicka." }, "step": { diff --git a/homeassistant/components/logi_circle/translations/zh-Hans.json b/homeassistant/components/logi_circle/translations/zh-Hans.json index 2d9770e0a80..d8d1e7b72d0 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/logi_circle/translations/zh-Hant.json b/homeassistant/components/logi_circle/translations/zh-Hant.json index 5f2d37a8421..9905280f9cb 100644 --- a/homeassistant/components/logi_circle/translations/zh-Hant.json +++ b/homeassistant/components/logi_circle/translations/zh-Hant.json @@ -2,18 +2,11 @@ "config": { "abort": { "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "already_setup": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44 Logi Circle \u5e33\u865f\u3002", "external_error": "\u5176\u4ed6\u6d41\u7a0b\u767c\u751f\u7570\u5e38\u3002", "external_setup": "\u5df2\u7531\u5176\u4ed6\u6d41\u7a0b\u6210\u529f\u8a2d\u5b9a Logi Circle\u3002", - "missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002", - "no_flows": "\u5fc5\u9808\u5148\u8a2d\u5b9a Logi Circle \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15]\uff08https://www.home-assistant.io/components/logi_circle/\uff09\u3002" - }, - "create_entry": { - "default": "\u5df2\u6210\u529f\u8a8d\u8b49 Logi Circle \u8a2d\u5099\u3002" + "missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002" }, "error": { - "auth_error": "API \u8a8d\u8b49\u5931\u6557\u3002", - "auth_timeout": "\u8acb\u6c42\u5b58\u53d6\u5bc6\u9470\u8a8d\u8b49\u903e\u6642\u3002", "authorize_url_timeout": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u903e\u6642\u3002", "follow_link": "\u8acb\u65bc\u50b3\u9001\u524d\uff0c\u5148\u4f7f\u7528\u9023\u7d50\u4e26\u9032\u884c\u8a8d\u8b49\u3002", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" diff --git a/homeassistant/components/london_air/sensor.py b/homeassistant/components/london_air/sensor.py index c7104ac19ad..a8bebc20cf5 100644 --- a/homeassistant/components/london_air/sensor.py +++ b/homeassistant/components/london_air/sensor.py @@ -128,19 +128,21 @@ class AirSensor(Entity): """Return other details about the sensor state.""" attrs = {} attrs["updated"] = self._updated - attrs["sites"] = len(self._site_data) + attrs["sites"] = len(self._site_data) if self._site_data is not None else 0 attrs["data"] = self._site_data return attrs def update(self): """Update the sensor.""" - self._api_data.update() - self._site_data = self._api_data.data[self._name] - self._updated = self._site_data[0]["updated"] sites_status = [] - for site in self._site_data: - if site["pollutants_status"] != "no_species_data": - sites_status.append(site["pollutants_status"]) + self._api_data.update() + if self._api_data.data: + self._site_data = self._api_data.data[self._name] + self._updated = self._site_data[0]["updated"] + for site in self._site_data: + if site["pollutants_status"] != "no_species_data": + sites_status.append(site["pollutants_status"]) + if sites_status: self._state = max(set(sites_status), key=sites_status.count) else: diff --git a/homeassistant/components/lovelace/__init__.py b/homeassistant/components/lovelace/__init__.py index d67298e4a78..000c86567ca 100644 --- a/homeassistant/components/lovelace/__init__.py +++ b/homeassistant/components/lovelace/__init__.py @@ -140,8 +140,6 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType): websocket.websocket_lovelace_dashboards ) - hass.components.system_health.async_register_info(DOMAIN, system_health_info) - hass.data[DOMAIN] = { # We store a dictionary mapping url_path: config. None is the default. "dashboards": {None: default_config}, @@ -233,14 +231,6 @@ async def create_yaml_resource_col(hass, yaml_resources): return resources.ResourceYAMLCollection(yaml_resources or []) -async def system_health_info(hass): - """Get info for the info page.""" - health_info = {"dashboards": len(hass.data[DOMAIN]["dashboards"])} - health_info.update(await hass.data[DOMAIN]["dashboards"][None].async_get_info()) - health_info.update(await hass.data[DOMAIN]["resources"].async_get_info()) - return health_info - - @callback def _register_panel(hass, url_path, mode, config, update): """Register a panel.""" diff --git a/homeassistant/components/lovelace/strings.json b/homeassistant/components/lovelace/strings.json new file mode 100644 index 00000000000..87f8407d93c --- /dev/null +++ b/homeassistant/components/lovelace/strings.json @@ -0,0 +1,10 @@ +{ + "system_health": { + "info": { + "dashboards": "Dashboards", + "mode": "Mode", + "resources": "Resources", + "views": "Views" + } + } +} diff --git a/homeassistant/components/lovelace/system_health.py b/homeassistant/components/lovelace/system_health.py new file mode 100644 index 00000000000..e0d1152a049 --- /dev/null +++ b/homeassistant/components/lovelace/system_health.py @@ -0,0 +1,21 @@ +"""Provide info to system health.""" +from homeassistant.components import system_health +from homeassistant.core import HomeAssistant, callback + +from .const import DOMAIN + + +@callback +def async_register( + hass: HomeAssistant, register: system_health.SystemHealthRegistration +) -> None: + """Register system health callbacks.""" + register.async_register_info(system_health_info, "/config/lovelace") + + +async def system_health_info(hass): + """Get info for the info page.""" + health_info = {"dashboards": len(hass.data[DOMAIN]["dashboards"])} + health_info.update(await hass.data[DOMAIN]["dashboards"][None].async_get_info()) + health_info.update(await hass.data[DOMAIN]["resources"].async_get_info()) + return health_info diff --git a/homeassistant/components/lovelace/translations/af.json b/homeassistant/components/lovelace/translations/af.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/af.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/bg.json b/homeassistant/components/lovelace/translations/bg.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/bg.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/ca.json b/homeassistant/components/lovelace/translations/ca.json index 2fc0c81a46c..7d24e63c329 100644 --- a/homeassistant/components/lovelace/translations/ca.json +++ b/homeassistant/components/lovelace/translations/ca.json @@ -1,3 +1,10 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "Panells", + "mode": "Mode", + "resources": "Recursos", + "views": "Visualitzacions" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/cs.json b/homeassistant/components/lovelace/translations/cs.json index 2fc0c81a46c..5c4dc738c6c 100644 --- a/homeassistant/components/lovelace/translations/cs.json +++ b/homeassistant/components/lovelace/translations/cs.json @@ -1,3 +1,10 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "Dashboardy", + "mode": "Re\u017eim", + "resources": "Zdroje", + "views": "Zobrazen\u00ed" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/cy.json b/homeassistant/components/lovelace/translations/cy.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/cy.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/da.json b/homeassistant/components/lovelace/translations/da.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/da.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/de.json b/homeassistant/components/lovelace/translations/de.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/de.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/el.json b/homeassistant/components/lovelace/translations/el.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/el.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/en.json b/homeassistant/components/lovelace/translations/en.json index 2fc0c81a46c..53c919f51bc 100644 --- a/homeassistant/components/lovelace/translations/en.json +++ b/homeassistant/components/lovelace/translations/en.json @@ -1,3 +1,10 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "Dashboards", + "mode": "Mode", + "resources": "Resources", + "views": "Views" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/es-419.json b/homeassistant/components/lovelace/translations/es-419.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/es-419.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/es.json b/homeassistant/components/lovelace/translations/es.json index 2fc0c81a46c..575610c96e0 100644 --- a/homeassistant/components/lovelace/translations/es.json +++ b/homeassistant/components/lovelace/translations/es.json @@ -1,3 +1,10 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "Paneles de control", + "mode": "Modo", + "resources": "Recursos", + "views": "Vistas" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/et.json b/homeassistant/components/lovelace/translations/et.json index 2fc0c81a46c..15c253dd4d4 100644 --- a/homeassistant/components/lovelace/translations/et.json +++ b/homeassistant/components/lovelace/translations/et.json @@ -1,3 +1,10 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "Vaated", + "mode": "Re\u017eiim", + "resources": "Ressursid", + "views": "Vaated" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/eu.json b/homeassistant/components/lovelace/translations/eu.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/eu.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/fa.json b/homeassistant/components/lovelace/translations/fa.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/fa.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/fi.json b/homeassistant/components/lovelace/translations/fi.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/fi.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/fr.json b/homeassistant/components/lovelace/translations/fr.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/fr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/he.json b/homeassistant/components/lovelace/translations/he.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/he.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/hr.json b/homeassistant/components/lovelace/translations/hr.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/hr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/hu.json b/homeassistant/components/lovelace/translations/hu.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/hu.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/hy.json b/homeassistant/components/lovelace/translations/hy.json deleted file mode 100644 index cbdc153a582..00000000000 --- a/homeassistant/components/lovelace/translations/hy.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "\u057d\u056b\u0580\u0578" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/is.json b/homeassistant/components/lovelace/translations/is.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/is.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/it.json b/homeassistant/components/lovelace/translations/it.json index 2fc0c81a46c..918057460c0 100644 --- a/homeassistant/components/lovelace/translations/it.json +++ b/homeassistant/components/lovelace/translations/it.json @@ -1,3 +1,9 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "Plance", + "mode": "Modalit\u00e0", + "resources": "Risorse" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/ko.json b/homeassistant/components/lovelace/translations/ko.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/ko.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/lb.json b/homeassistant/components/lovelace/translations/lb.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/lb.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/lt.json b/homeassistant/components/lovelace/translations/lt.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/lt.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/lv.json b/homeassistant/components/lovelace/translations/lv.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/lv.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/nb.json b/homeassistant/components/lovelace/translations/nb.json deleted file mode 100644 index d8a4c453015..00000000000 --- a/homeassistant/components/lovelace/translations/nb.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/nl.json b/homeassistant/components/lovelace/translations/nl.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/nl.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/nn.json b/homeassistant/components/lovelace/translations/nn.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/nn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/no.json b/homeassistant/components/lovelace/translations/no.json index d8a4c453015..d4b6d939561 100644 --- a/homeassistant/components/lovelace/translations/no.json +++ b/homeassistant/components/lovelace/translations/no.json @@ -1,3 +1,10 @@ { - "title": "" + "system_health": { + "info": { + "dashboards": "Dashboards", + "mode": "Modus", + "resources": "Ressurser", + "views": "Visninger" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/pl.json b/homeassistant/components/lovelace/translations/pl.json index 2fc0c81a46c..3c87f145220 100644 --- a/homeassistant/components/lovelace/translations/pl.json +++ b/homeassistant/components/lovelace/translations/pl.json @@ -1,3 +1,10 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "Dashboardy", + "mode": "Tryb", + "resources": "Zasoby", + "views": "Widoki" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/pt-BR.json b/homeassistant/components/lovelace/translations/pt-BR.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/pt-BR.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/pt.json b/homeassistant/components/lovelace/translations/pt.json index 2fc0c81a46c..920f9447577 100644 --- a/homeassistant/components/lovelace/translations/pt.json +++ b/homeassistant/components/lovelace/translations/pt.json @@ -1,3 +1,9 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "Dashboards", + "mode": "Modo", + "resources": "Recursos" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/ro.json b/homeassistant/components/lovelace/translations/ro.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/ro.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/ru.json b/homeassistant/components/lovelace/translations/ru.json index 2fc0c81a46c..856237d9b1f 100644 --- a/homeassistant/components/lovelace/translations/ru.json +++ b/homeassistant/components/lovelace/translations/ru.json @@ -1,3 +1,10 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "\u041f\u0430\u043d\u0435\u043b\u0438", + "mode": "\u0420\u0435\u0436\u0438\u043c", + "resources": "\u0420\u0435\u0441\u0443\u0440\u0441\u044b", + "views": "\u0412\u043a\u043b\u0430\u0434\u043a\u0438" + } + } } \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/sk.json b/homeassistant/components/lovelace/translations/sk.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/sk.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/sl.json b/homeassistant/components/lovelace/translations/sl.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/sl.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/sv.json b/homeassistant/components/lovelace/translations/sv.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/sv.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/th.json b/homeassistant/components/lovelace/translations/th.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/th.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/tr.json b/homeassistant/components/lovelace/translations/tr.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/tr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/uk.json b/homeassistant/components/lovelace/translations/uk.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/uk.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/vi.json b/homeassistant/components/lovelace/translations/vi.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/vi.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/zh-Hans.json b/homeassistant/components/lovelace/translations/zh-Hans.json deleted file mode 100644 index 2fc0c81a46c..00000000000 --- a/homeassistant/components/lovelace/translations/zh-Hans.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Lovelace" -} \ No newline at end of file diff --git a/homeassistant/components/lovelace/translations/zh-Hant.json b/homeassistant/components/lovelace/translations/zh-Hant.json index 2fc0c81a46c..b1f4309bd42 100644 --- a/homeassistant/components/lovelace/translations/zh-Hant.json +++ b/homeassistant/components/lovelace/translations/zh-Hant.json @@ -1,3 +1,9 @@ { - "title": "Lovelace" + "system_health": { + "info": { + "dashboards": "\u4e3b\u9762\u677f", + "mode": "\u6a21\u5f0f", + "resources": "\u8cc7\u6e90" + } + } } \ No newline at end of file diff --git a/homeassistant/components/luftdaten/config_flow.py b/homeassistant/components/luftdaten/config_flow.py index 1613e8ea555..a77618f27f3 100644 --- a/homeassistant/components/luftdaten/config_flow.py +++ b/homeassistant/components/luftdaten/config_flow.py @@ -69,7 +69,7 @@ class LuftDatenFlowHandler(config_entries.ConfigFlow): sensor_id = user_input[CONF_SENSOR_ID] if sensor_id in configured_sensors(self.hass): - return self._show_form({CONF_SENSOR_ID: "sensor_exists"}) + return self._show_form({CONF_SENSOR_ID: "already_configured"}) session = aiohttp_client.async_get_clientsession(self.hass) luftdaten = Luftdaten(user_input[CONF_SENSOR_ID], self.hass.loop, session) @@ -77,7 +77,7 @@ class LuftDatenFlowHandler(config_entries.ConfigFlow): await luftdaten.get_data() valid = await luftdaten.validate_sensor() except LuftdatenConnectionError: - return self._show_form({CONF_SENSOR_ID: "communication_error"}) + return self._show_form({CONF_SENSOR_ID: "cannot_connect"}) if not valid: return self._show_form({CONF_SENSOR_ID: "invalid_sensor"}) diff --git a/homeassistant/components/luftdaten/strings.json b/homeassistant/components/luftdaten/strings.json index 2ac026d3001..d6b4602782e 100644 --- a/homeassistant/components/luftdaten/strings.json +++ b/homeassistant/components/luftdaten/strings.json @@ -10,9 +10,9 @@ } }, "error": { - "sensor_exists": "Sensor already registered", + "already_configured": "[%key:common::config_flow::abort::already_configured_service%]", "invalid_sensor": "Sensor not available or invalid", - "communication_error": "Unable to communicate with the Luftdaten API" + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" } } } diff --git a/homeassistant/components/luftdaten/translations/af.json b/homeassistant/components/luftdaten/translations/af.json new file mode 100644 index 00000000000..e4ed696c257 --- /dev/null +++ b/homeassistant/components/luftdaten/translations/af.json @@ -0,0 +1,8 @@ +{ + "config": { + "error": { + "already_configured": "Dienst ist bereits konfiguriert", + "cannot_connect": "Verbindung fehlgeschlagen" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/luftdaten/translations/bg.json b/homeassistant/components/luftdaten/translations/bg.json index 816d0519ecc..39787684871 100644 --- a/homeassistant/components/luftdaten/translations/bg.json +++ b/homeassistant/components/luftdaten/translations/bg.json @@ -1,9 +1,7 @@ { "config": { "error": { - "communication_error": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u043a\u043e\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u044f \u0441 Luftdaten", - "invalid_sensor": "\u0421\u0435\u043d\u0437\u043e\u0440\u044a\u0442 \u043d\u0435 \u0435 \u043d\u0430\u043b\u0438\u0447\u0435\u043d \u0438\u043b\u0438 \u0435 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d", - "sensor_exists": "\u0421\u0435\u043d\u0437\u043e\u0440\u044a\u0442 \u0432\u0435\u0447\u0435 \u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d" + "invalid_sensor": "\u0421\u0435\u043d\u0437\u043e\u0440\u044a\u0442 \u043d\u0435 \u0435 \u043d\u0430\u043b\u0438\u0447\u0435\u043d \u0438\u043b\u0438 \u0435 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/ca.json b/homeassistant/components/luftdaten/translations/ca.json index e1b5072b96e..f6325c522b6 100644 --- a/homeassistant/components/luftdaten/translations/ca.json +++ b/homeassistant/components/luftdaten/translations/ca.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "No s'ha pogut comunicar amb l'API de Luftdaten", - "invalid_sensor": "El sensor no est\u00e0 disponible o no \u00e9s v\u00e0lid", - "sensor_exists": "Sensor ja registrat" + "already_configured": "El servei ja est\u00e0 configurat", + "cannot_connect": "Ha fallat la connexi\u00f3", + "invalid_sensor": "El sensor no est\u00e0 disponible o no \u00e9s v\u00e0lid" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/cs.json b/homeassistant/components/luftdaten/translations/cs.json index 0a38e6200b9..2a9d786cf12 100644 --- a/homeassistant/components/luftdaten/translations/cs.json +++ b/homeassistant/components/luftdaten/translations/cs.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "Nelze komunikovat s Luftdaten API", - "invalid_sensor": "Senzor nen\u00ed k dispozici nebo je neplatn\u00fd", - "sensor_exists": "Senzor je ji\u017e zaregistrov\u00e1n" + "already_configured": "Slu\u017eba je ji\u017e nastavena", + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", + "invalid_sensor": "Senzor nen\u00ed k dispozici nebo je neplatn\u00fd" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/da.json b/homeassistant/components/luftdaten/translations/da.json index c44ee107618..fa32979112b 100644 --- a/homeassistant/components/luftdaten/translations/da.json +++ b/homeassistant/components/luftdaten/translations/da.json @@ -1,9 +1,7 @@ { "config": { "error": { - "communication_error": "Kan ikke oprette forbindelse til Luftdaten API", - "invalid_sensor": "Sensor ikke tilg\u00e6ngelig eller ugyldig", - "sensor_exists": "Sensor er allerede registreret" + "invalid_sensor": "Sensor ikke tilg\u00e6ngelig eller ugyldig" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/de.json b/homeassistant/components/luftdaten/translations/de.json index b2169dbc2ab..122dc611870 100644 --- a/homeassistant/components/luftdaten/translations/de.json +++ b/homeassistant/components/luftdaten/translations/de.json @@ -1,9 +1,8 @@ { "config": { "error": { - "communication_error": "Keine Kommunikation mit Luftdaten API m\u00f6glich", - "invalid_sensor": "Sensor nicht verf\u00fcgbar oder ung\u00fcltig", - "sensor_exists": "Sensor bereits registriert" + "cannot_connect": "Verbindung fehlgeschlagen", + "invalid_sensor": "Sensor nicht verf\u00fcgbar oder ung\u00fcltig" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/en.json b/homeassistant/components/luftdaten/translations/en.json index 0c325c70970..f784e360d5c 100644 --- a/homeassistant/components/luftdaten/translations/en.json +++ b/homeassistant/components/luftdaten/translations/en.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "Unable to communicate with the Luftdaten API", - "invalid_sensor": "Sensor not available or invalid", - "sensor_exists": "Sensor already registered" + "already_configured": "Service is already configured", + "cannot_connect": "Failed to connect", + "invalid_sensor": "Sensor not available or invalid" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/es-419.json b/homeassistant/components/luftdaten/translations/es-419.json index eddf31c91ab..e9e97ff034d 100644 --- a/homeassistant/components/luftdaten/translations/es-419.json +++ b/homeassistant/components/luftdaten/translations/es-419.json @@ -1,9 +1,7 @@ { "config": { "error": { - "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" + "invalid_sensor": "Sensor no disponible o no v\u00e1lido" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/es.json b/homeassistant/components/luftdaten/translations/es.json index 9f8276ff3b8..bc33a13d870 100644 --- a/homeassistant/components/luftdaten/translations/es.json +++ b/homeassistant/components/luftdaten/translations/es.json @@ -1,9 +1,9 @@ { "config": { "error": { - "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" + "already_configured": "El servicio ya est\u00e1 configurado", + "cannot_connect": "No se pudo conectar", + "invalid_sensor": "Sensor no disponible o no v\u00e1lido" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/et.json b/homeassistant/components/luftdaten/translations/et.json new file mode 100644 index 00000000000..e0af8580937 --- /dev/null +++ b/homeassistant/components/luftdaten/translations/et.json @@ -0,0 +1,18 @@ +{ + "config": { + "error": { + "already_configured": "Teenus on juba seadistatud", + "cannot_connect": "\u00dchendamine nurjus", + "invalid_sensor": "Andur pole saadaval v\u00f5i vigane" + }, + "step": { + "user": { + "data": { + "show_on_map": "Kuva kaardil", + "station_id": "" + }, + "title": "M\u00e4\u00e4ratle Luftdaten" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/luftdaten/translations/fr.json b/homeassistant/components/luftdaten/translations/fr.json index 8b3492a0427..e5b53d99ce7 100644 --- a/homeassistant/components/luftdaten/translations/fr.json +++ b/homeassistant/components/luftdaten/translations/fr.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "Impossible de communiquer avec l'API Luftdaten", - "invalid_sensor": "Capteur non disponible ou invalide", - "sensor_exists": "Capteur d\u00e9j\u00e0 enregistr\u00e9" + "already_configured": "Le service est d\u00e9j\u00e0 configur\u00e9", + "cannot_connect": "\u00c9chec de connexion", + "invalid_sensor": "Capteur non disponible ou invalide" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/hu.json b/homeassistant/components/luftdaten/translations/hu.json index 2d63c0f5852..4385c09d6ef 100644 --- a/homeassistant/components/luftdaten/translations/hu.json +++ b/homeassistant/components/luftdaten/translations/hu.json @@ -1,9 +1,7 @@ { "config": { "error": { - "communication_error": "Nem lehet kommunik\u00e1lni a Luftdaten API-val", - "invalid_sensor": "Az \u00e9rz\u00e9kel\u0151 nem el\u00e9rhet\u0151 vagy \u00e9rv\u00e9nytelen", - "sensor_exists": "Az \u00e9rz\u00e9kel\u0151 m\u00e1r regisztr\u00e1lt" + "invalid_sensor": "Az \u00e9rz\u00e9kel\u0151 nem el\u00e9rhet\u0151 vagy \u00e9rv\u00e9nytelen" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/it.json b/homeassistant/components/luftdaten/translations/it.json index f3673c2775d..506026efa1b 100644 --- a/homeassistant/components/luftdaten/translations/it.json +++ b/homeassistant/components/luftdaten/translations/it.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "Impossibile comunicare con l'API Luftdaten", - "invalid_sensor": "Sensore non disponibile o non valido", - "sensor_exists": "Sensore gi\u00e0 registrato" + "already_configured": "Il servizio \u00e8 gi\u00e0 configurato", + "cannot_connect": "Impossibile connettersi", + "invalid_sensor": "Sensore non disponibile o non valido" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/ko.json b/homeassistant/components/luftdaten/translations/ko.json index 42f3d80f880..eb69dfb64a2 100644 --- a/homeassistant/components/luftdaten/translations/ko.json +++ b/homeassistant/components/luftdaten/translations/ko.json @@ -1,9 +1,7 @@ { "config": { "error": { - "communication_error": "Luftdaten API \uc640 \ud1b5\uc2e0 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", - "invalid_sensor": "\uc13c\uc11c\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uac70\ub098 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4", - "sensor_exists": "\uc13c\uc11c\uac00 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4" + "invalid_sensor": "\uc13c\uc11c\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uac70\ub098 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/lb.json b/homeassistant/components/luftdaten/translations/lb.json index d7f17fb5220..83254e05c83 100644 --- a/homeassistant/components/luftdaten/translations/lb.json +++ b/homeassistant/components/luftdaten/translations/lb.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "Kann net mat der Luftdaten API kommuniz\u00e9ieren", - "invalid_sensor": "Sensor net disponibel oder ong\u00eblteg", - "sensor_exists": "Sensor ass scho registr\u00e9iert" + "already_configured": "Service ass scho konfigur\u00e9iert", + "cannot_connect": "Feeler beim verbannen", + "invalid_sensor": "Sensor net disponibel oder ong\u00eblteg" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/nl.json b/homeassistant/components/luftdaten/translations/nl.json index f7c93460fa7..b3bdf2442b8 100644 --- a/homeassistant/components/luftdaten/translations/nl.json +++ b/homeassistant/components/luftdaten/translations/nl.json @@ -1,9 +1,8 @@ { "config": { "error": { - "communication_error": "Kan niet communiceren met de Luftdaten API", - "invalid_sensor": "Sensor niet beschikbaar of ongeldig", - "sensor_exists": "Sensor bestaat al" + "already_configured": "Service is al geconfigureerd", + "invalid_sensor": "Sensor niet beschikbaar of ongeldig" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/no.json b/homeassistant/components/luftdaten/translations/no.json index 8c1b69bed07..853eb84296b 100644 --- a/homeassistant/components/luftdaten/translations/no.json +++ b/homeassistant/components/luftdaten/translations/no.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "Kan ikke kommunisere med Luftdaten API", - "invalid_sensor": "Sensor er ikke tilgjengelig eller ugyldig", - "sensor_exists": "Sensor er allerede registrert" + "already_configured": "Tjenesten er allerede konfigurert", + "cannot_connect": "Tilkobling mislyktes", + "invalid_sensor": "Sensor er ikke tilgjengelig eller ugyldig" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/pl.json b/homeassistant/components/luftdaten/translations/pl.json index 12a56344bba..60fc0714228 100644 --- a/homeassistant/components/luftdaten/translations/pl.json +++ b/homeassistant/components/luftdaten/translations/pl.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z API Luftdaten", - "invalid_sensor": "Sensor niedost\u0119pny lub nieprawid\u0142owy", - "sensor_exists": "Sensor zosta\u0142 ju\u017c zarejestrowany" + "already_configured": "Us\u0142uga jest ju\u017c skonfigurowana", + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", + "invalid_sensor": "Sensor niedost\u0119pny lub nieprawid\u0142owy" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/pt-BR.json b/homeassistant/components/luftdaten/translations/pt-BR.json index e2fce8f57c4..3884170c2e0 100644 --- a/homeassistant/components/luftdaten/translations/pt-BR.json +++ b/homeassistant/components/luftdaten/translations/pt-BR.json @@ -1,9 +1,7 @@ { "config": { "error": { - "communication_error": "N\u00e3o \u00e9 poss\u00edvel se comunicar com a API da Luftdaten", - "invalid_sensor": "Sensor n\u00e3o dispon\u00edvel ou inv\u00e1lido", - "sensor_exists": "Sensor j\u00e1 registado" + "invalid_sensor": "Sensor n\u00e3o dispon\u00edvel ou inv\u00e1lido" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/pt.json b/homeassistant/components/luftdaten/translations/pt.json index deb2de26fdc..1f8cb29ff0f 100644 --- a/homeassistant/components/luftdaten/translations/pt.json +++ b/homeassistant/components/luftdaten/translations/pt.json @@ -1,9 +1,7 @@ { "config": { "error": { - "communication_error": "N\u00e3o \u00e9 poss\u00edvel comunicar com a API da Luftdaten", - "invalid_sensor": "Sensor n\u00e3o dispon\u00edvel ou inv\u00e1lido", - "sensor_exists": "Sensor j\u00e1 registado" + "invalid_sensor": "Sensor n\u00e3o dispon\u00edvel ou inv\u00e1lido" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/ru.json b/homeassistant/components/luftdaten/translations/ru.json index 5123fa9438b..2277ca275f2 100644 --- a/homeassistant/components/luftdaten/translations/ru.json +++ b/homeassistant/components/luftdaten/translations/ru.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a API Luftdaten.", - "invalid_sensor": "\u0421\u0435\u043d\u0441\u043e\u0440 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u043b\u0438 \u043d\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d.", - "sensor_exists": "\u0421\u0435\u043d\u0441\u043e\u0440 \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d." + "already_configured": "\u042d\u0442\u0430 \u0441\u043b\u0443\u0436\u0431\u0430 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant.", + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", + "invalid_sensor": "\u0421\u0435\u043d\u0441\u043e\u0440 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u043b\u0438 \u043d\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d." }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/sl.json b/homeassistant/components/luftdaten/translations/sl.json index edf88f798f9..249a0258536 100644 --- a/homeassistant/components/luftdaten/translations/sl.json +++ b/homeassistant/components/luftdaten/translations/sl.json @@ -1,9 +1,7 @@ { "config": { "error": { - "communication_error": "Ne morem komunicirati z Luftdaten API-jem", - "invalid_sensor": "Senzor ni na voljo ali je neveljaven", - "sensor_exists": "Senzor je \u017ee registriran" + "invalid_sensor": "Senzor ni na voljo ali je neveljaven" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/sv.json b/homeassistant/components/luftdaten/translations/sv.json index 62d823c5fe9..52180093ba4 100644 --- a/homeassistant/components/luftdaten/translations/sv.json +++ b/homeassistant/components/luftdaten/translations/sv.json @@ -1,9 +1,7 @@ { "config": { "error": { - "communication_error": "Det g\u00e5r inte att kommunicera med Luftdaten API", - "invalid_sensor": "Sensor saknas eller \u00e4r ogiltig", - "sensor_exists": "Sensorn \u00e4r redan registrerad" + "invalid_sensor": "Sensor saknas eller \u00e4r ogiltig" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/zh-Hans.json b/homeassistant/components/luftdaten/translations/zh-Hans.json index 02024b18494..d66c44499df 100644 --- a/homeassistant/components/luftdaten/translations/zh-Hans.json +++ b/homeassistant/components/luftdaten/translations/zh-Hans.json @@ -1,9 +1,8 @@ { "config": { "error": { - "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" + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", + "invalid_sensor": "\u4f20\u611f\u5668\u4e0d\u53ef\u7528\u6216\u65e0\u6548" }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/translations/zh-Hant.json b/homeassistant/components/luftdaten/translations/zh-Hant.json index 2c0e06f8006..b1d9df3595a 100644 --- a/homeassistant/components/luftdaten/translations/zh-Hant.json +++ b/homeassistant/components/luftdaten/translations/zh-Hant.json @@ -1,9 +1,9 @@ { "config": { "error": { - "communication_error": "\u7121\u6cd5\u8207 Luftdaten API \u9032\u884c\u901a\u4fe1", - "invalid_sensor": "\u7121\u6cd5\u4f7f\u7528\u6216\u7121\u6548\u7684\u611f\u61c9\u5668", - "sensor_exists": "\u611f\u61c9\u5668\u5df2\u8a3b\u518a" + "already_configured": "\u670d\u52d9\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", + "cannot_connect": "\u9023\u7dda\u5931\u6557", + "invalid_sensor": "\u7121\u6cd5\u4f7f\u7528\u6216\u7121\u6548\u7684\u611f\u61c9\u5668" }, "step": { "user": { diff --git a/homeassistant/components/lutron_caseta/cover.py b/homeassistant/components/lutron_caseta/cover.py index 5eabfcd16fe..8db97e3fd0c 100644 --- a/homeassistant/components/lutron_caseta/cover.py +++ b/homeassistant/components/lutron_caseta/cover.py @@ -3,6 +3,7 @@ import logging from homeassistant.components.cover import ( ATTR_POSITION, + DEVICE_CLASS_SHADE, DOMAIN, SUPPORT_CLOSE, SUPPORT_OPEN, @@ -52,6 +53,11 @@ class LutronCasetaCover(LutronCasetaDevice, CoverEntity): """Return the current position of cover.""" return self._device["current_state"] + @property + def device_class(self): + """Return the device class.""" + return DEVICE_CLASS_SHADE + async def async_stop_cover(self, **kwargs): """Top the cover.""" await self._smartbridge.stop_cover(self.device_id) diff --git a/homeassistant/components/lutron_caseta/manifest.json b/homeassistant/components/lutron_caseta/manifest.json index 366c9cb7f14..b21cfed30c2 100644 --- a/homeassistant/components/lutron_caseta/manifest.json +++ b/homeassistant/components/lutron_caseta/manifest.json @@ -3,7 +3,7 @@ "name": "Lutron Caséta", "documentation": "https://www.home-assistant.io/integrations/lutron_caseta", "requirements": [ - "pylutron-caseta==0.7.1" + "pylutron-caseta==0.7.2" ], "codeowners": [ "@swails" diff --git a/homeassistant/components/lutron_caseta/translations/de.json b/homeassistant/components/lutron_caseta/translations/de.json new file mode 100644 index 00000000000..12f0a2859e8 --- /dev/null +++ b/homeassistant/components/lutron_caseta/translations/de.json @@ -0,0 +1,10 @@ +{ + "config": { + "abort": { + "cannot_connect": "Verbindung fehlgeschlagen" + }, + "error": { + "cannot_connect": "Verbindung fehlgeschlagen" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/lutron_caseta/translations/et.json b/homeassistant/components/lutron_caseta/translations/et.json index 48afb13b828..ed352c7bcc4 100644 --- a/homeassistant/components/lutron_caseta/translations/et.json +++ b/homeassistant/components/lutron_caseta/translations/et.json @@ -9,7 +9,8 @@ }, "step": { "import_failed": { - "description": "Silla (host: {host} ) seadistamine configuration.yaml kirje teabest nurjus." + "description": "Silla (host: {host} ) seadistamine configuration.yaml kirje teabest nurjus.", + "title": "Cas\u00e9ta Bridge seadete importimine nurjus." } } } diff --git a/homeassistant/components/lutron_caseta/translations/lb.json b/homeassistant/components/lutron_caseta/translations/lb.json index 8da7ed29d7f..e78f8839797 100644 --- a/homeassistant/components/lutron_caseta/translations/lb.json +++ b/homeassistant/components/lutron_caseta/translations/lb.json @@ -1,11 +1,11 @@ { "config": { "abort": { - "already_configured": "Cas\u00e9ta Bridge ass schon konfigur\u00e9iert.", - "cannot_connect": "Ariichten vun der Cas\u00e9ta Bridge ofgebrach w\u00e9inst engem Problem mat der Verbindung." + "already_configured": "Apparat ass scho konfigur\u00e9iert", + "cannot_connect": "Feeler beim verbannen" }, "error": { - "cannot_connect": "Feeler beim verbanne mat der Cas\u00e9ta Bridge; iwwerpr\u00e9if den Numm an Zertifikat" + "cannot_connect": "Feeler beim verbannen" }, "step": { "import_failed": { diff --git a/homeassistant/components/lutron_caseta/translations/nl.json b/homeassistant/components/lutron_caseta/translations/nl.json new file mode 100644 index 00000000000..8e48dea075d --- /dev/null +++ b/homeassistant/components/lutron_caseta/translations/nl.json @@ -0,0 +1,16 @@ +{ + "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd", + "cannot_connect": "Kon niet verbinden" + }, + "error": { + "cannot_connect": "Kon niet verbinden" + }, + "step": { + "import_failed": { + "description": "Kan bridge (host: {host} ) niet instellen, ge\u00efmporteerd uit configuration.yaml." + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/lutron_caseta/translations/pl.json b/homeassistant/components/lutron_caseta/translations/pl.json index d50293af89b..07417b0149e 100644 --- a/homeassistant/components/lutron_caseta/translations/pl.json +++ b/homeassistant/components/lutron_caseta/translations/pl.json @@ -9,7 +9,7 @@ }, "step": { "import_failed": { - "description": "Nie mo\u017cna skonfigurowa\u0107 mostka (host: {host} ) zaimportowanego z pliku configuration.yaml.", + "description": "Nie mo\u017cna skonfigurowa\u0107 mostka (host: {host}) zaimportowanego z pliku configuration.yaml.", "title": "Nie uda\u0142o si\u0119 zaimportowa\u0107 konfiguracji mostka Cas\u00e9ta." } } diff --git a/homeassistant/components/lw12wifi/light.py b/homeassistant/components/lw12wifi/light.py index 907e6b898d6..4b8fb2e9ee0 100644 --- a/homeassistant/components/lw12wifi/light.py +++ b/homeassistant/components/lw12wifi/light.py @@ -113,7 +113,7 @@ class LW12WiFi(LightEntity): return True @property - def shoud_poll(self) -> bool: + def should_poll(self) -> bool: """Return False to not poll the state of this entity.""" return False diff --git a/homeassistant/components/mailgun/__init__.py b/homeassistant/components/mailgun/__init__.py index 42b51c23c74..220b6a1abc1 100644 --- a/homeassistant/components/mailgun/__init__.py +++ b/homeassistant/components/mailgun/__init__.py @@ -51,7 +51,7 @@ async def handle_webhook(hass, webhook_id, request): except ValueError: return None - if isinstance(data, dict) and "signature" in data.keys(): + if isinstance(data, dict) and "signature" in data: if await verify_webhook(hass, **data["signature"]): data["webhook_id"] = webhook_id hass.bus.async_fire(MESSAGE_RECEIVED, data) diff --git a/homeassistant/components/mailgun/strings.json b/homeassistant/components/mailgun/strings.json index a948c6165e7..a26a908ff73 100644 --- a/homeassistant/components/mailgun/strings.json +++ b/homeassistant/components/mailgun/strings.json @@ -8,7 +8,7 @@ }, "abort": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive Mailgun messages." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup [Webhooks with Mailgun]({mailgun_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data." diff --git a/homeassistant/components/mailgun/translations/bg.json b/homeassistant/components/mailgun/translations/bg.json index 207dbe2b3ad..19eaa6facf3 100644 --- a/homeassistant/components/mailgun/translations/bg.json +++ b/homeassistant/components/mailgun/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 Mailgun.", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u0441\u044a\u0431\u0438\u0442\u0438\u044f \u0434\u043e Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 [Webhooks \u0441 Mailgun]({mailgun_url}). \n\n\u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: \n\n - URL: `{webhook_url}` \n - Method: POST \n - Content Type: application/json\n\n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u0442\u043e\u0432\u0430 \u043a\u0430\u043a \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438\u0442\u0435 \u0437\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0430 \u0432\u0445\u043e\u0434\u044f\u0449\u0438 \u0434\u0430\u043d\u043d\u0438." }, diff --git a/homeassistant/components/mailgun/translations/ca.json b/homeassistant/components/mailgun/translations/ca.json index 496894090a7..6584b15b3ad 100644 --- a/homeassistant/components/mailgun/translations/ca.json +++ b/homeassistant/components/mailgun/translations/ca.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de Mailgun.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar esdeveniments a Home Assistant, haur\u00e0s de configurar [Webhooks amb Mailgun]({mailgun_url}). \n\nCompleta la seg\u00fcent informaci\u00f3: \n\n- URL: `{webhook_url}` \n- M\u00e8tode: POST \n- Tipus de contingut: application/json\n\nConsulta la [documentaci\u00f3]({docs_url}) sobre com configurar les automatitzacions per gestionar dades entrants." diff --git a/homeassistant/components/mailgun/translations/cs.json b/homeassistant/components/mailgun/translations/cs.json index 810483ec4ae..a6060240a00 100644 --- a/homeassistant/components/mailgun/translations/cs.json +++ b/homeassistant/components/mailgun/translations/cs.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "not_internet_accessible": "V\u00e1\u0161 Home Asistent mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy od Mailgun.", - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "create_entry": { - "default": "Chcete-li odeslat ud\u00e1losti do aplikace Home Assistant, budete muset nastavit [Webhooks with Mailgun]({mailgun_url}). \n\n Vypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: `{webhook_url}`\n - Metoda: POST \n - Typ obsahu: application/json\n\n Viz [dokumentace]({docs_url}), jak konfigurovat automatizace pro zpracov\u00e1n\u00ed p\u0159\u00edchoz\u00edch dat." + "default": "Chcete-li odeslat ud\u00e1losti do Home Assistant, budete muset nastavit [Webhooks with Mailgun]({mailgun_url}). \n\nVypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: `{webhook_url}`\n - Metoda: POST \n - Typ obsahu: application/json\n\nViz [dokumentace]({docs_url}), jak konfigurovat automatizace pro zpracov\u00e1n\u00ed p\u0159\u00edchoz\u00edch dat." }, "step": { "user": { diff --git a/homeassistant/components/mailgun/translations/da.json b/homeassistant/components/mailgun/translations/da.json index b0aca0f8737..a785c0d62e3 100644 --- a/homeassistant/components/mailgun/translations/da.json +++ b/homeassistant/components/mailgun/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage Mailgun-meddelelser", - "one_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning." - }, "create_entry": { "default": "For at sende h\u00e6ndelser til Home Assistant skal du konfigurere [Webhooks med Mailgun]({mailgun_url}).\n\n Udfyld f\u00f8lgende oplysninger: \n\n - Webadresse: `{webhook_url}`\n - Metode: POST\n - Indholdstype: application/json\n\nSe [dokumentationen]({docs_url}) om hvordan du konfigurerer automatiseringer til at h\u00e5ndtere indg\u00e5ende data." }, diff --git a/homeassistant/components/mailgun/translations/de.json b/homeassistant/components/mailgun/translations/de.json index be795b2f8f5..f684f822fd5 100644 --- a/homeassistant/components/mailgun/translations/de.json +++ b/homeassistant/components/mailgun/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Ihre Home Assistant-Instanz muss \u00fcber das Internet erreichbar sein, um Mailgun-Nachrichten empfangen zu k\u00f6nnen.", - "one_instance_allowed": "Nur eine einzige Instanz ist notwendig." - }, "create_entry": { "default": "Um Ereignisse an den Home Assistant zu senden, musst [Webhooks mit Mailgun]({mailgun_url}) einrichten. \n\n F\u00fclle die folgenden Informationen aus: \n\n - URL: `{webhook_url}` \n - Methode: POST \n - Inhaltstyp: application/json \n\nLies in der [Dokumentation]({docs_url}) wie du Automationen f\u00fcr die Verarbeitung eingehender Daten konfigurierst." }, diff --git a/homeassistant/components/mailgun/translations/en.json b/homeassistant/components/mailgun/translations/en.json index bcb3556087d..ec6732304bd 100644 --- a/homeassistant/components/mailgun/translations/en.json +++ b/homeassistant/components/mailgun/translations/en.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive Mailgun messages.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup [Webhooks with Mailgun]({mailgun_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data." diff --git a/homeassistant/components/mailgun/translations/es-419.json b/homeassistant/components/mailgun/translations/es-419.json index 154e7873644..fdbd581c339 100644 --- a/homeassistant/components/mailgun/translations/es-419.json +++ b/homeassistant/components/mailgun/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Mailgun.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar eventos a Home Assistant, deber\u00e1 configurar [Webhooks with Mailgun]({mailgun_url}). \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: `{webhook_url}` \n - M\u00e9todo: POST \n - Tipo de contenido: application/json\n\n Consulte [la documentaci\u00f3n]({docs_url}) sobre c\u00f3mo configurar las automatizaciones para manejar los datos entrantes." }, diff --git a/homeassistant/components/mailgun/translations/es.json b/homeassistant/components/mailgun/translations/es.json index d7622a5c218..50290059f54 100644 --- a/homeassistant/components/mailgun/translations/es.json +++ b/homeassistant/components/mailgun/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Tu instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Mailgun.", - "one_instance_allowed": "Solo es necesaria una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar eventos a Home Assistant debes configurar los [Webhooks en Mailgun]({mailgun_url}). \n\n Completa la siguiente informaci\u00f3n: \n\n - URL: `{webhook_url}` \n - M\u00e9todo: POST \n - Tipo de contenido: application/json \n\n Consulta [la documentaci\u00f3n]({docs_url}) sobre c\u00f3mo configurar las automatizaciones para manejar los datos entrantes." diff --git a/homeassistant/components/mailgun/translations/et.json b/homeassistant/components/mailgun/translations/et.json index 077504e9d77..4f3469d1357 100644 --- a/homeassistant/components/mailgun/translations/et.json +++ b/homeassistant/components/mailgun/translations/et.json @@ -1,12 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Lubatud on ainult \u00fcks sidumine.", - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." + }, + "create_entry": { + "default": "S\u00fcndmuste saatmiseks Home Assistantile pead seadistama [Webhooks with Mailgun] ( {dialogflow_url} ). \n\n Sisesta j\u00e4rgmine teave: \n\n - URL: \" {webhook_url} \" \n - Meetod: POST \n - Sisu t\u00fc\u00fcp: application/json \n\n Lisateavet leiad [documentation] ( {docs_url} )." }, "step": { "user": { - "description": "Kas soovidi Mailguni seadistada?" + "description": "Kas soovidi Mailguni seadistada?", + "title": "Seadista Mailgun Webhook" } } } diff --git a/homeassistant/components/mailgun/translations/fr.json b/homeassistant/components/mailgun/translations/fr.json index edb9f01be3d..b822522af10 100644 --- a/homeassistant/components/mailgun/translations/fr.json +++ b/homeassistant/components/mailgun/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance Home Assistant doit \u00eatre accessible \u00e0 partir d'Internet pour recevoir les messages Mailgun.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez configurer [Webhooks avec Mailgun]({mailgun_url}). \n\n Remplissez les informations suivantes: \n\n - URL: `{webhook_url}` \n - M\u00e9thode: POST \n - Type de contenu: application/json \n\n Voir [la documentation]({docs_url}) pour savoir comment configurer les automatisations pour g\u00e9rer les donn\u00e9es entrantes." diff --git a/homeassistant/components/mailgun/translations/hu.json b/homeassistant/components/mailgun/translations/hu.json index 89cfcbf358e..2a3265e8c62 100644 --- a/homeassistant/components/mailgun/translations/hu.json +++ b/homeassistant/components/mailgun/translations/hu.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A Home Assistant rendszerednek el\u00e9rhet\u0151nek kell lennie az internetr\u0151l a Mailgun \u00fczenetek fogad\u00e1s\u00e1hoz.", - "one_instance_allowed": "Csak egyetlen konfigur\u00e1ci\u00f3 sz\u00fcks\u00e9ges." - }, "step": { "user": { "description": "Biztosan be szeretn\u00e9d \u00e1ll\u00edtani a Mailgunt?", diff --git a/homeassistant/components/mailgun/translations/it.json b/homeassistant/components/mailgun/translations/it.json index 0373d686744..31909cb44d2 100644 --- a/homeassistant/components/mailgun/translations/it.json +++ b/homeassistant/components/mailgun/translations/it.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi da Mailgun.", - "one_instance_allowed": "\u00c8 necessaria una sola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare eventi a Home Assistant, dovrai configurare [Webhooks con Mailgun]({mailgun_url})\n\n Compila le seguenti informazioni: \n\n - URL: `{webhook_url}` \n - Method: POST \n - Content Type: application/json\n\n Vedi [la documentazione]({docs_url}) su come configurare le automazioni per gestire i dati in arrivo." diff --git a/homeassistant/components/mailgun/translations/ko.json b/homeassistant/components/mailgun/translations/ko.json index b42dbbf9f2f..43b6586b14f 100644 --- a/homeassistant/components/mailgun/translations/ko.json +++ b/homeassistant/components/mailgun/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Mailgun \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c\ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\ub824\uba74 [Mailgun \uc6f9 \ud6c5]({mailgun_url}) \uc744 \uc124\uc815\ud574\uc57c\ud569\ub2c8\ub2e4. \n\n\ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694:\n\n - URL: `{webhook_url}`\n - Method: POST\n - Content Type: application/json\n \nHome Assistant \ub85c \ub4e4\uc5b4\uc624\ub294 \ub370\uc774\ud130\ub97c \ucc98\ub9ac\ud558\uae30 \uc704\ud55c \uc790\ub3d9\ud654\ub97c \uad6c\uc131\ud558\ub294 \ubc29\ubc95\uc740 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/mailgun/translations/lb.json b/homeassistant/components/mailgun/translations/lb.json index 42e3c98d837..43564297cd5 100644 --- a/homeassistant/components/mailgun/translations/lb.json +++ b/homeassistant/components/mailgun/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir Mailgun Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { diff --git a/homeassistant/components/mailgun/translations/nl.json b/homeassistant/components/mailgun/translations/nl.json index 7cfebddcdbd..772a67c118e 100644 --- a/homeassistant/components/mailgun/translations/nl.json +++ b/homeassistant/components/mailgun/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Uw Home Assistant instantie moet toegankelijk zijn vanaf het internet om Mailgun-berichten te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n enkele instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/mailgun/translations/no.json b/homeassistant/components/mailgun/translations/no.json index 557979f84c2..4cc080805ac 100644 --- a/homeassistant/components/mailgun/translations/no.json +++ b/homeassistant/components/mailgun/translations/no.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "not_internet_accessible": "Din Home Assistant forekomst m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 motta Mailgun-meldinger.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { - "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du sette opp [Webhooks with Mailgun]({mailgun_url}).\n\nFyll ut f\u00f8lgende informasjon:\n\n- URL: `{webhook_url}`\n- Metode: POST\n- Innholdstype: application/json\n\nSe [dokumentasjonen]({docs_url}) om hvordan du konfigurerer automatiseringer for \u00e5 h\u00e5ndtere innkommende data." + "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du sette opp [Webhooks with Mailgun]({mailgun_url}).\n\nFyll ut f\u00f8lgende informasjon:\n\n- URL: `{webhook_url}`\n- Metode: POST\n- Innholdstype: application/json\n\nSe [dokumentasjonen]({docs_url}) om hvordan du konfigurerer automasjoner for \u00e5 h\u00e5ndtere innkommende data." }, "step": { "user": { diff --git a/homeassistant/components/mailgun/translations/pl.json b/homeassistant/components/mailgun/translations/pl.json index 6d71f9d9880..fac09505ffa 100644 --- a/homeassistant/components/mailgun/translations/pl.json +++ b/homeassistant/components/mailgun/translations/pl.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty Mailgun", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant, musisz skonfigurowa\u0107 [Mailgun Webhook]({mailgun_url}). \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n - Typ zawarto\u015bci: application/json\n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}) na temat konfiguracji automatyzacji, by obs\u0142u\u017cy\u0107 przychodz\u0105ce dane." }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 Mailgun?", + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", "title": "Konfiguracja Mailgun Webhook" } } diff --git a/homeassistant/components/mailgun/translations/pt-BR.json b/homeassistant/components/mailgun/translations/pt-BR.json index 5fbdd643f07..36e14f97645 100644 --- a/homeassistant/components/mailgun/translations/pt-BR.json +++ b/homeassistant/components/mailgun/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia do Home Assistant precisa estar acess\u00edvel na Internet para receber mensagens de correspond\u00eancia.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, voc\u00ea precisar\u00e1 configurar [Webhooks com Mailgun]({mailgun_url}). \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: `{webhook_url}` \n - M\u00e9todo: POST \n - Tipo de Conte\u00fado: application/json \n\n Veja [a documenta\u00e7\u00e3o] ({docs_url}) sobre como configurar automa\u00e7\u00f5es para manipular dados de entrada." }, diff --git a/homeassistant/components/mailgun/translations/pt.json b/homeassistant/components/mailgun/translations/pt.json index a0aeedc62a4..2a193a19f96 100644 --- a/homeassistant/components/mailgun/translations/pt.json +++ b/homeassistant/components/mailgun/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A sua inst\u00e2ncia Home Assistant precisa de ser acess\u00edvel a partir da internet para receber mensagens Mailgun.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, \u00e9 necess\u00e1rio configurar [Webhooks with Mailgun]({mailgun_url}). \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: `{webhook_url}`\n - M\u00e9todo: POST \n - Tipo de Conte\u00fado: application/json\n\n Veja [a documenta\u00e7\u00e3o]({docs_url}) sobre como configurar automa\u00e7\u00f5es para manipular dados de entrada." }, diff --git a/homeassistant/components/mailgun/translations/ru.json b/homeassistant/components/mailgun/translations/ru.json index f8a7c451819..740f616da4c 100644 --- a/homeassistant/components/mailgun/translations/ru.json +++ b/homeassistant/components/mailgun/translations/ru.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 Mailgun.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Webhook \u0434\u043b\u044f [Mailgun]({mailgun_url}).\n\n\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\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 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0439 \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445." diff --git a/homeassistant/components/mailgun/translations/sl.json b/homeassistant/components/mailgun/translations/sl.json index b660cb871da..6ccb12b4750 100644 --- a/homeassistant/components/mailgun/translations/sl.json +++ b/homeassistant/components/mailgun/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u010ce \u017eelite prejemati sporo\u010dila Mailgun, mora biti Home Assistant dostopen prek interneta.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "Za po\u0161iljanje dogodkov Home Assistantu boste morali nastaviti [Webhooks z Mailgun]({mailgun_url}).\n\nIzpolnite naslednje informacije:\n\n- URL: `{webhook_url}`\n- Metoda: POST\n- Vrsta vsebine: application/json\n\nGlej [dokumentacijo]({docs_url}) o tem, kako nastavite automations za obravnavo dohodnih podatkov." }, diff --git a/homeassistant/components/mailgun/translations/sv.json b/homeassistant/components/mailgun/translations/sv.json index baed592049e..aec197c766a 100644 --- a/homeassistant/components/mailgun/translations/sv.json +++ b/homeassistant/components/mailgun/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant instans m\u00e5ste vara tillg\u00e4nglig fr\u00e5n internet f\u00f6r att ta emot Mailgun meddelanden.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du konfigurera [Webhooks med Mailgun]({mailgun_url}).\n\n Fyll i f\u00f6ljande information:\n \n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n Se [dokumentationen]({docs_url}) om hur du konfigurerar automatiseringar f\u00f6r att hantera inkommande data." }, diff --git a/homeassistant/components/mailgun/translations/zh-Hans.json b/homeassistant/components/mailgun/translations/zh-Hans.json index 1c6af1dc4c0..97a827f3d6b 100644 --- a/homeassistant/components/mailgun/translations/zh-Hans.json +++ b/homeassistant/components/mailgun/translations/zh-Hans.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u53ef\u4ece\u4e92\u8054\u7f51\u8bbf\u95ee\u4ee5\u63a5\u6536 Mailgun \u6d88\u606f\u3002", - "one_instance_allowed": "\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u662f\u5fc5\u9700\u7684\u3002" - }, "create_entry": { "default": "\u8981\u5411 Home Assistant \u53d1\u9001\u4e8b\u4ef6\uff0c\u60a8\u9700\u8981\u914d\u7f6e [Mailgun \u7684 Webhook]({mailgun_url})\u3002\n\n\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\u6709\u5173\u5982\u4f55\u914d\u7f6e\u81ea\u52a8\u5316\u4ee5\u5904\u7406\u4f20\u5165\u7684\u6570\u636e\uff0c\u8bf7\u53c2\u9605[\u6587\u6863]({docs_url})\u3002" }, diff --git a/homeassistant/components/mailgun/translations/zh-Hant.json b/homeassistant/components/mailgun/translations/zh-Hant.json index 51b859cb73f..19c41241a5e 100644 --- a/homeassistant/components/mailgun/translations/zh-Hant.json +++ b/homeassistant/components/mailgun/translations/zh-Hant.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u8a2d\u5099\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 Mailgun \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u7269\u4ef6\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u8a2d\u5b9a [Webhooks with Mailgun]({mailgun_url}) \u3002\n\n\u8acb\u586b\u5beb\u4e0b\u5217\u8cc7\u8a0a\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\u95dc\u65bc\u5982\u4f55\u50b3\u5165\u8cc7\u6599\u81ea\u52d5\u5316\u8a2d\u5b9a\uff0c\u8acb\u53c3\u95b1[\u6587\u4ef6]({docs_url})\u4ee5\u9032\u884c\u4e86\u89e3\u3002" diff --git a/homeassistant/components/media_extractor/manifest.json b/homeassistant/components/media_extractor/manifest.json index 1dbb642aee9..7d6e92ed274 100644 --- a/homeassistant/components/media_extractor/manifest.json +++ b/homeassistant/components/media_extractor/manifest.json @@ -2,7 +2,7 @@ "domain": "media_extractor", "name": "Media Extractor", "documentation": "https://www.home-assistant.io/integrations/media_extractor", - "requirements": ["youtube_dl==2020.09.20"], + "requirements": ["youtube_dl==2020.11.01.1"], "dependencies": ["media_player"], "codeowners": [], "quality_scale": "internal" diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 410d69c22c3..71db60baa2e 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -6,7 +6,7 @@ from datetime import timedelta import functools as ft import hashlib import logging -from random import SystemRandom +import secrets from typing import List, Optional from urllib.parse import urlparse @@ -15,6 +15,7 @@ from aiohttp.hdrs import CACHE_CONTROL, CONTENT_TYPE from aiohttp.typedefs import LooseHeaders import async_timeout import voluptuous as vol +from yarl import URL from homeassistant.components import websocket_api from homeassistant.components.http import KEY_AUTHENTICATED, HomeAssistantView @@ -119,7 +120,6 @@ from .errors import BrowseError # mypy: allow-untyped-defs, no-check-untyped-defs _LOGGER = logging.getLogger(__name__) -_RND = SystemRandom() ENTITY_ID_FORMAT = DOMAIN + ".{}" @@ -365,9 +365,7 @@ class MediaPlayerEntity(Entity): def access_token(self) -> str: """Access token for this media player.""" if self._access_token is None: - self._access_token = hashlib.sha256( - _RND.getrandbits(256).to_bytes(32, "little") - ).hexdigest() + self._access_token = secrets.token_hex(32) return self._access_token @property @@ -433,7 +431,17 @@ class MediaPlayerEntity(Entity): if url is None: return None, None - return await _async_fetch_image(self.hass, url) + return await self._async_fetch_image_from_cache(url) + + async def async_get_browse_image( + self, media_content_type, media_content_id, media_image_id=None + ): + """ + Optionally fetch internally accessible image for media browser. + + Must be implemented by integration. + """ + return None, None @property def media_title(self): @@ -848,27 +856,37 @@ class MediaPlayerEntity(Entity): """ raise NotImplementedError() + async def _async_fetch_image_from_cache(self, url): + """Fetch image. -async def _async_fetch_image(hass, url): - """Fetch image. + Images are cached in memory (the images are typically 10-100kB in size). + """ + cache_images = ENTITY_IMAGE_CACHE[CACHE_IMAGES] + cache_maxsize = ENTITY_IMAGE_CACHE[CACHE_MAXSIZE] - Images are cached in memory (the images are typically 10-100kB in size). - """ - cache_images = ENTITY_IMAGE_CACHE[CACHE_IMAGES] - cache_maxsize = ENTITY_IMAGE_CACHE[CACHE_MAXSIZE] + if urlparse(url).hostname is None: + url = f"{get_url(self.hass)}{url}" - if urlparse(url).hostname is None: - url = f"{get_url(hass)}{url}" + if url not in cache_images: + cache_images[url] = {CACHE_LOCK: asyncio.Lock()} - if url not in cache_images: - cache_images[url] = {CACHE_LOCK: asyncio.Lock()} + async with cache_images[url][CACHE_LOCK]: + if CACHE_CONTENT in cache_images[url]: + return cache_images[url][CACHE_CONTENT] - async with cache_images[url][CACHE_LOCK]: - if CACHE_CONTENT in cache_images[url]: - return cache_images[url][CACHE_CONTENT] + (content, content_type) = await self._async_fetch_image(url) + async with cache_images[url][CACHE_LOCK]: + cache_images[url][CACHE_CONTENT] = content, content_type + while len(cache_images) > cache_maxsize: + cache_images.popitem(last=False) + + return content, content_type + + async def _async_fetch_image(self, url): + """Retrieve an image.""" content, content_type = (None, None) - websession = async_get_clientsession(hass) + websession = async_get_clientsession(self.hass) try: with async_timeout.timeout(10): response = await websession.get(url) @@ -878,16 +896,30 @@ async def _async_fetch_image(hass, url): content_type = response.headers.get(CONTENT_TYPE) if content_type: content_type = content_type.split(";")[0] - cache_images[url][CACHE_CONTENT] = content, content_type except asyncio.TimeoutError: pass - while len(cache_images) > cache_maxsize: - cache_images.popitem(last=False) + if content is None: + _LOGGER.warning("Error retrieving proxied image from %s", url) return content, content_type + def get_browse_image_url( + self, media_content_type, media_content_id, media_image_id=None + ): + """Generate an url for a media browser image.""" + url_path = ( + f"/api/media_player_proxy/{self.entity_id}/browse_media" + f"/{media_content_type}/{media_content_id}" + ) + + url_query = {"token": self.access_token} + if media_image_id: + url_query["media_image_id"] = media_image_id + + return str(URL(url_path).with_query(url_query)) + class MediaPlayerImageView(HomeAssistantView): """Media player view to serve an image.""" @@ -895,12 +927,21 @@ class MediaPlayerImageView(HomeAssistantView): requires_auth = False url = "/api/media_player_proxy/{entity_id}" name = "api:media_player:image" + extra_urls = [ + url + "/browse_media/{media_content_type}/{media_content_id}", + ] def __init__(self, component): """Initialize a media player view.""" self.component = component - async def get(self, request: web.Request, entity_id: str) -> web.Response: + async def get( + self, + request: web.Request, + entity_id: str, + media_content_type: Optional[str] = None, + media_content_id: Optional[str] = None, + ) -> web.Response: """Start a get request.""" player = self.component.get_entity(entity_id) if player is None: @@ -915,7 +956,13 @@ class MediaPlayerImageView(HomeAssistantView): if not authenticated: return web.Response(status=HTTP_UNAUTHORIZED) - data, content_type = await player.async_get_media_image() + if media_content_type and media_content_id: + media_image_id = request.query.get("media_image_id") + data, content_type = await player.async_get_browse_image( + media_content_type, media_content_id, media_image_id + ) + else: + data, content_type = await player.async_get_media_image() if data is None: return web.Response(status=HTTP_INTERNAL_SERVER_ERROR) diff --git a/homeassistant/components/media_player/translations/pl.json b/homeassistant/components/media_player/translations/pl.json index 865d2e1df2c..23ba46f9339 100644 --- a/homeassistant/components/media_player/translations/pl.json +++ b/homeassistant/components/media_player/translations/pl.json @@ -1,9 +1,9 @@ { "device_automation": { "condition_type": { - "is_idle": "odtwarzacz medi\u00f3w {entity_name} jest nieaktywny", - "is_off": "odtwarzacz medi\u00f3w {entity_name} jest wy\u0142\u0105czony", - "is_on": "odtwarzacz medi\u00f3w {entity_name} jest w\u0142\u0105czony", + "is_idle": "odtwarzacz {entity_name} jest nieaktywny", + "is_off": "odtwarzacz {entity_name} jest wy\u0142\u0105czony", + "is_on": "odtwarzacz {entity_name} jest w\u0142\u0105czony", "is_paused": "odtwarzanie medi\u00f3w na {entity_name} jest wstrzymane", "is_playing": "{entity_name} odtwarza media" } diff --git a/homeassistant/components/media_player/translations/tr.json b/homeassistant/components/media_player/translations/tr.json index 2687a8ffb4e..0130b5fb94c 100644 --- a/homeassistant/components/media_player/translations/tr.json +++ b/homeassistant/components/media_player/translations/tr.json @@ -5,8 +5,8 @@ "off": "Kapal\u0131", "on": "A\u00e7\u0131k", "paused": "Durduruldu", - "playing": "Oynuyor", - "standby": "Bekleme modu" + "playing": "Oynat\u0131l\u0131yor", + "standby": "Beklemede" } }, "title": "Medya oynat\u0131c\u0131" diff --git a/homeassistant/components/melcloud/translations/et.json b/homeassistant/components/melcloud/translations/et.json index 8905edc111e..a1cc180fadc 100644 --- a/homeassistant/components/melcloud/translations/et.json +++ b/homeassistant/components/melcloud/translations/et.json @@ -13,7 +13,9 @@ "data": { "password": "Salas\u00f5na", "username": "E-post" - } + }, + "description": "\u00dchenda oma MELCloudi konto abil.", + "title": "\u00dchenda MELCloudiga" } } } diff --git a/homeassistant/components/melcloud/translations/lb.json b/homeassistant/components/melcloud/translations/lb.json index 0abdc2b9187..f4c44ab161a 100644 --- a/homeassistant/components/melcloud/translations/lb.json +++ b/homeassistant/components/melcloud/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "MELCloud Integratioun ass scho konfigur\u00e9iert fir d\u00ebs Email. Acc\u00e8s Jeton gouf erneiert." }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9iert w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, diff --git a/homeassistant/components/met/strings.json b/homeassistant/components/met/strings.json index c3e28d98eff..b9e94aba865 100644 --- a/homeassistant/components/met/strings.json +++ b/homeassistant/components/met/strings.json @@ -2,13 +2,13 @@ "config": { "step": { "user": { - "title": "Location", + "title": "[%key:common::config_flow::data::location%]", "description": "Meteorologisk institutt", "data": { "name": "[%key:common::config_flow::data::name%]", "latitude": "[%key:common::config_flow::data::latitude%]", "longitude": "[%key:common::config_flow::data::longitude%]", - "elevation": "Elevation" + "elevation": "[%key:common::config_flow::data::elevation%]" } } }, diff --git a/homeassistant/components/met/translations/bg.json b/homeassistant/components/met/translations/bg.json index 895bf9c5bf7..f6a10ce42ec 100644 --- a/homeassistant/components/met/translations/bg.json +++ b/homeassistant/components/met/translations/bg.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u0442\u043e \u0432\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/ca.json b/homeassistant/components/met/translations/ca.json index d33e905e721..11815222df5 100644 --- a/homeassistant/components/met/translations/ca.json +++ b/homeassistant/components/met/translations/ca.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "El servei ja est\u00e0 configurat", - "name_exists": "El nom ja existeix" + "already_configured": "El servei ja est\u00e0 configurat" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/cs.json b/homeassistant/components/met/translations/cs.json index 520a14ef9ab..6ee3d3c4dc1 100644 --- a/homeassistant/components/met/translations/cs.json +++ b/homeassistant/components/met/translations/cs.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "Slu\u017eba je ji\u017e nastavena", - "name_exists": "Um\u00edst\u011bn\u00ed ji\u017e existuje" + "already_configured": "Slu\u017eba je ji\u017e nastavena" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/da.json b/homeassistant/components/met/translations/da.json index 7a530e44fb3..b0c7e35da8b 100644 --- a/homeassistant/components/met/translations/da.json +++ b/homeassistant/components/met/translations/da.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "Navnet findes allerede" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/de.json b/homeassistant/components/met/translations/de.json index 61d4dc4660b..901b4fb97b5 100644 --- a/homeassistant/components/met/translations/de.json +++ b/homeassistant/components/met/translations/de.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "Ort existiert bereits" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/en.json b/homeassistant/components/met/translations/en.json index 012557d917a..590bf48e635 100644 --- a/homeassistant/components/met/translations/en.json +++ b/homeassistant/components/met/translations/en.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "Service is already configured", - "name_exists": "Location already exists" + "already_configured": "Service is already configured" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/es-419.json b/homeassistant/components/met/translations/es-419.json index fc3d4f64fc7..87c6fd91eca 100644 --- a/homeassistant/components/met/translations/es-419.json +++ b/homeassistant/components/met/translations/es-419.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "El nombre ya existe" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/es.json b/homeassistant/components/met/translations/es.json index 9306bd03022..4c6c4aa1991 100644 --- a/homeassistant/components/met/translations/es.json +++ b/homeassistant/components/met/translations/es.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "El servicio ya est\u00e1 configurado", - "name_exists": "La ubicaci\u00f3n ya existe" + "already_configured": "El servicio ya est\u00e1 configurado" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/et.json b/homeassistant/components/met/translations/et.json index df6a380a5e7..d25ca8df0a5 100644 --- a/homeassistant/components/met/translations/et.json +++ b/homeassistant/components/met/translations/et.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "Teenus on juba h\u00e4\u00e4lestatud", - "name_exists": "See asukoht on juba m\u00e4\u00e4ratud" + "already_configured": "Teenus on juba h\u00e4\u00e4lestatud" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/fr.json b/homeassistant/components/met/translations/fr.json index fc712cb6912..dbf72959799 100644 --- a/homeassistant/components/met/translations/fr.json +++ b/homeassistant/components/met/translations/fr.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "Le service est d\u00e9j\u00e0 configur\u00e9", - "name_exists": "Emplacement d\u00e9j\u00e0 existant" + "already_configured": "Le service est d\u00e9j\u00e0 configur\u00e9" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/hr.json b/homeassistant/components/met/translations/hr.json index 5b57e11ac6e..397f4764707 100644 --- a/homeassistant/components/met/translations/hr.json +++ b/homeassistant/components/met/translations/hr.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "Ime ve\u0107 postoji" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/hu.json b/homeassistant/components/met/translations/hu.json index 8196d4bffe9..4e3ccf87ab7 100644 --- a/homeassistant/components/met/translations/hu.json +++ b/homeassistant/components/met/translations/hu.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "A hely m\u00e1r l\u00e9tezik" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/it.json b/homeassistant/components/met/translations/it.json index 16d68553ab4..2a00b31eedb 100644 --- a/homeassistant/components/met/translations/it.json +++ b/homeassistant/components/met/translations/it.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "Il servizio \u00e8 gi\u00e0 configurato", - "name_exists": "La posizione esiste gi\u00e0" + "already_configured": "Il servizio \u00e8 gi\u00e0 configurato" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/ko.json b/homeassistant/components/met/translations/ko.json index 846aca7f4ea..e7263aba3d2 100644 --- a/homeassistant/components/met/translations/ko.json +++ b/homeassistant/components/met/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "\uc704\uce58\uac00 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/lb.json b/homeassistant/components/met/translations/lb.json index 88041b9abe0..50b8698d2b4 100644 --- a/homeassistant/components/met/translations/lb.json +++ b/homeassistant/components/met/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "error": { - "name_exists": "Standuert g\u00ebtt et schonn" + "already_configured": "Service ass scho konfigur\u00e9iert" }, "step": { "user": { @@ -12,7 +12,7 @@ "name": "Numm" }, "description": "Meterologeschen Institut", - "title": "Uertschaft" + "title": "Standuert" } } } diff --git a/homeassistant/components/met/translations/nl.json b/homeassistant/components/met/translations/nl.json index 3cb932e6095..108c2a44f66 100644 --- a/homeassistant/components/met/translations/nl.json +++ b/homeassistant/components/met/translations/nl.json @@ -1,7 +1,7 @@ { "config": { "error": { - "name_exists": "Locatie bestaat al." + "already_configured": "Service is al geconfigureerd" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/no.json b/homeassistant/components/met/translations/no.json index daab4665bca..05ba5b0c9d9 100644 --- a/homeassistant/components/met/translations/no.json +++ b/homeassistant/components/met/translations/no.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "Tjenesten er allerede konfigurert", - "name_exists": "Plasseringen finnes allerede" + "already_configured": "Tjenesten er allerede konfigurert" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/pl.json b/homeassistant/components/met/translations/pl.json index 8d7ca7d2bad..7b357f6b7eb 100644 --- a/homeassistant/components/met/translations/pl.json +++ b/homeassistant/components/met/translations/pl.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "Us\u0142uga jest ju\u017c skonfigurowana", - "name_exists": "Lokalizacja ju\u017c istnieje" + "already_configured": "Us\u0142uga jest ju\u017c skonfigurowana" }, "step": { "user": { diff --git a/homeassistant/components/met/translations/pt-BR.json b/homeassistant/components/met/translations/pt-BR.json index f16aac2174d..ac85a893c21 100644 --- a/homeassistant/components/met/translations/pt-BR.json +++ b/homeassistant/components/met/translations/pt-BR.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "O nome j\u00e1 existe" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/pt.json b/homeassistant/components/met/translations/pt.json index 1afabe51e79..6641658bd48 100644 --- a/homeassistant/components/met/translations/pt.json +++ b/homeassistant/components/met/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "A localiza\u00e7\u00e3o j\u00e1 existe" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/ru.json b/homeassistant/components/met/translations/ru.json index 149e085057b..f28ce7f2813 100644 --- a/homeassistant/components/met/translations/ru.json +++ b/homeassistant/components/met/translations/ru.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "\u042d\u0442\u0430 \u0441\u043b\u0443\u0436\u0431\u0430 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant.", - "name_exists": "\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e." + "already_configured": "\u042d\u0442\u0430 \u0441\u043b\u0443\u0436\u0431\u0430 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant." }, "step": { "user": { diff --git a/homeassistant/components/met/translations/sl.json b/homeassistant/components/met/translations/sl.json index d424f196997..09e48c1238e 100644 --- a/homeassistant/components/met/translations/sl.json +++ b/homeassistant/components/met/translations/sl.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "Lokacija \u017ee obstaja" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/sv.json b/homeassistant/components/met/translations/sv.json index 9475a0b2915..fbea0183395 100644 --- a/homeassistant/components/met/translations/sv.json +++ b/homeassistant/components/met/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "Plats finns redan" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/zh-Hans.json b/homeassistant/components/met/translations/zh-Hans.json index 9027347174d..965bca23164 100644 --- a/homeassistant/components/met/translations/zh-Hans.json +++ b/homeassistant/components/met/translations/zh-Hans.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "name_exists": "\u4f4d\u7f6e\u5df2\u5b58\u5728" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/met/translations/zh-Hant.json b/homeassistant/components/met/translations/zh-Hant.json index bb5d2df412a..d5cba312536 100644 --- a/homeassistant/components/met/translations/zh-Hant.json +++ b/homeassistant/components/met/translations/zh-Hant.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "\u670d\u52d9\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "name_exists": "\u8a72\u5ea7\u6a19\u5df2\u5b58\u5728" + "already_configured": "\u670d\u52d9\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "step": { "user": { diff --git a/homeassistant/components/meteo_france/translations/et.json b/homeassistant/components/meteo_france/translations/et.json index 2579507ab00..c23d2107f54 100644 --- a/homeassistant/components/meteo_france/translations/et.json +++ b/homeassistant/components/meteo_france/translations/et.json @@ -4,9 +4,32 @@ "already_configured": "Asukoht on juba m\u00e4\u00e4ratud", "unknown": "Tundmatu viga" }, + "error": { + "empty": "Otsingus tulemusi pole: kontrolli linna nime" + }, "step": { - "user": { + "cities": { + "data": { + "city": "Linn" + }, + "description": "Vali loendist oma linn", "title": "" + }, + "user": { + "data": { + "city": "Linn" + }, + "description": "Sisesta sihtnumber (ainult Prantsusmaa, soovitatav) v\u00f5i linna nimi", + "title": "" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "mode": "Ilmateate re\u017eiim" + } } } } diff --git a/homeassistant/components/meteo_france/translations/lb.json b/homeassistant/components/meteo_france/translations/lb.json index 435eadd57fe..310d53b1d8f 100644 --- a/homeassistant/components/meteo_france/translations/lb.json +++ b/homeassistant/components/meteo_france/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "already_configured": "Stad ass scho konfigur\u00e9iert", - "unknown": "Onbekannte Feeler: prob\u00e9iert sp\u00e9ider nach emol" + "already_configured": "Standuert ass scho konfigur\u00e9iert", + "unknown": "Onerwaarte Feeler" }, "error": { "empty": "Kee Resultat an der Stad Sich: kuckt w.e.g. d'Stad feld" diff --git a/homeassistant/components/metoffice/translations/cs.json b/homeassistant/components/metoffice/translations/cs.json index e88b4b40667..4dc9bcb8a8d 100644 --- a/homeassistant/components/metoffice/translations/cs.json +++ b/homeassistant/components/metoffice/translations/cs.json @@ -14,6 +14,7 @@ "latitude": "Zem\u011bpisn\u00e1 \u0161\u00ed\u0159ka", "longitude": "Zem\u011bpisn\u00e1 d\u00e9lka" }, + "description": "Zem\u011bpisn\u00e1 \u0161\u00ed\u0159ka a d\u00e9lka budou pou\u017eity k vyhled\u00e1n\u00ed nejbli\u017e\u0161\u00ed meteorologick\u00e9 stanice.", "title": "P\u0159ipojen\u00ed k UK Met Office" } } diff --git a/homeassistant/components/metoffice/translations/de.json b/homeassistant/components/metoffice/translations/de.json index 55896dc4901..0db5c5a422e 100644 --- a/homeassistant/components/metoffice/translations/de.json +++ b/homeassistant/components/metoffice/translations/de.json @@ -1,8 +1,12 @@ { "config": { + "abort": { + "already_configured": "Service ist bereits konfiguriert" + }, "step": { "user": { "data": { + "api_key": "API Key", "latitude": "Breitengrad", "longitude": "L\u00e4ngengrad" } diff --git a/homeassistant/components/metoffice/translations/et.json b/homeassistant/components/metoffice/translations/et.json index 48d9e11150d..307a4290bd2 100644 --- a/homeassistant/components/metoffice/translations/et.json +++ b/homeassistant/components/metoffice/translations/et.json @@ -10,10 +10,12 @@ "step": { "user": { "data": { + "api_key": "API v\u00f5ti", "latitude": "Laiuskraad", "longitude": "Pikkuskraad" }, - "description": "Laius- ja pikkuskraadi kasutatakse l\u00e4hima ilmajaama leidmiseks." + "description": "Laius- ja pikkuskraadi kasutatakse l\u00e4hima ilmajaama leidmiseks.", + "title": "\u00dchendu UKMet Office'iga" } } } diff --git a/homeassistant/components/metoffice/translations/nl.json b/homeassistant/components/metoffice/translations/nl.json index ca0c4269579..1b3063459c4 100644 --- a/homeassistant/components/metoffice/translations/nl.json +++ b/homeassistant/components/metoffice/translations/nl.json @@ -1,11 +1,20 @@ { "config": { + "abort": { + "already_configured": "Service is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "api_key": "API-sleutel", "latitude": "Breedtegraad", "longitude": "Lengtegraad" - } + }, + "title": "Maak verbinding met het UK Met Office" } } } diff --git a/homeassistant/components/microsoft/manifest.json b/homeassistant/components/microsoft/manifest.json index 0e371199a18..5b936bc7ded 100644 --- a/homeassistant/components/microsoft/manifest.json +++ b/homeassistant/components/microsoft/manifest.json @@ -2,6 +2,6 @@ "domain": "microsoft", "name": "Microsoft Text-to-Speech (TTS)", "documentation": "https://www.home-assistant.io/integrations/microsoft", - "requirements": ["pycsspeechtts==1.0.3"], + "requirements": ["pycsspeechtts==1.0.4"], "codeowners": [] } diff --git a/homeassistant/components/miflora/manifest.json b/homeassistant/components/miflora/manifest.json index 7795e8fb6f8..eb8a9c1c38f 100644 --- a/homeassistant/components/miflora/manifest.json +++ b/homeassistant/components/miflora/manifest.json @@ -3,5 +3,5 @@ "name": "Mi Flora", "documentation": "https://www.home-assistant.io/integrations/miflora", "requirements": ["bluepy==1.3.0", "miflora==0.7.0"], - "codeowners": ["@danielhiversen", "@ChristianKuehnel", "@basnijholt"] + "codeowners": ["@danielhiversen", "@basnijholt"] } diff --git a/homeassistant/components/mikrotik/translations/ca.json b/homeassistant/components/mikrotik/translations/ca.json index 8556a3c7765..f7adef2f885 100644 --- a/homeassistant/components/mikrotik/translations/ca.json +++ b/homeassistant/components/mikrotik/translations/ca.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "El dispositiu ja est\u00e0 configurat", - "already_configured_device": "El dispositiu ja est\u00e0 configurat" + "already_configured": "El dispositiu ja est\u00e0 configurat" }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "name_exists": "El nom existeix", - "wrong_credentials": "Credencials incorrectes" + "name_exists": "El nom existeix" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/cs.json b/homeassistant/components/mikrotik/translations/cs.json index c6bf8f26181..ffde1d35a1f 100644 --- a/homeassistant/components/mikrotik/translations/cs.json +++ b/homeassistant/components/mikrotik/translations/cs.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "already_configured_device": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" + "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "name_exists": "Jm\u00e9no ji\u017e existuje", - "wrong_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje" + "name_exists": "Jm\u00e9no ji\u017e existuje" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/da.json b/homeassistant/components/mikrotik/translations/da.json index d31465ac399..ffc0a1d430e 100644 --- a/homeassistant/components/mikrotik/translations/da.json +++ b/homeassistant/components/mikrotik/translations/da.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Forbindelsen mislykkedes", - "name_exists": "Navnet findes allerede", - "wrong_credentials": "Forkerte legitimationsoplysninger" + "name_exists": "Navnet findes allerede" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/de.json b/homeassistant/components/mikrotik/translations/de.json index 0eb7c99a91a..4211077c82c 100644 --- a/homeassistant/components/mikrotik/translations/de.json +++ b/homeassistant/components/mikrotik/translations/de.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Verbindung fehlgeschlagen", - "name_exists": "Name vorhanden", - "wrong_credentials": "Falsche Zugangsdaten" + "name_exists": "Name vorhanden" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/en.json b/homeassistant/components/mikrotik/translations/en.json index cad279a7afa..d60a7064e3a 100644 --- a/homeassistant/components/mikrotik/translations/en.json +++ b/homeassistant/components/mikrotik/translations/en.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "Device is already configured", - "already_configured_device": "Device is already configured" + "already_configured": "Device is already configured" }, "error": { "cannot_connect": "Failed to connect", "invalid_auth": "Invalid authentication", - "name_exists": "Name exists", - "wrong_credentials": "Wrong Credentials" + "name_exists": "Name exists" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/es-419.json b/homeassistant/components/mikrotik/translations/es-419.json index 1b464bed393..0fcdb28d216 100644 --- a/homeassistant/components/mikrotik/translations/es-419.json +++ b/homeassistant/components/mikrotik/translations/es-419.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Conexi\u00f3n fallida", - "name_exists": "El nombre existe", - "wrong_credentials": "Credenciales incorrectas" + "name_exists": "El nombre existe" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/es.json b/homeassistant/components/mikrotik/translations/es.json index d1b8a208a41..e252c492c47 100644 --- a/homeassistant/components/mikrotik/translations/es.json +++ b/homeassistant/components/mikrotik/translations/es.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "El dispositivo ya est\u00e1 configurado", - "already_configured_device": "El dispositivo ya est\u00e1 configurado" + "already_configured": "El dispositivo ya est\u00e1 configurado" }, "error": { "cannot_connect": "Conexi\u00f3n fallida", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "name_exists": "El nombre ya existe", - "wrong_credentials": "Credenciales incorrectas" + "name_exists": "El nombre ya existe" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/et.json b/homeassistant/components/mikrotik/translations/et.json index b79cc13da27..bdd6c393b0c 100644 --- a/homeassistant/components/mikrotik/translations/et.json +++ b/homeassistant/components/mikrotik/translations/et.json @@ -1,20 +1,34 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "already_configured_device": "Seade on juba h\u00e4\u00e4lestatud" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud" }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "invalid_auth": "Tuvastamise viga" + "invalid_auth": "Tuvastamise viga", + "name_exists": "Nimi on juba olemas" }, "step": { "user": { "data": { "host": "", + "name": "Nimi", "password": "Salas\u00f5na", "port": "", - "username": "Kasutajanimi" + "username": "Kasutajanimi", + "verify_ssl": "Kasuta ssl-i" + }, + "title": "Seadista Mikrotik ruuter" + } + } + }, + "options": { + "step": { + "device_tracker": { + "data": { + "arp_ping": "Luba ARP ping", + "detection_time": "M\u00e4\u00e4ra n\u00e4htavuse aeg", + "force_dhcp": "Sundskannimine DHCP abil" } } } diff --git a/homeassistant/components/mikrotik/translations/fr.json b/homeassistant/components/mikrotik/translations/fr.json index 9b773d3f336..1d328a843cc 100644 --- a/homeassistant/components/mikrotik/translations/fr.json +++ b/homeassistant/components/mikrotik/translations/fr.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "Mikrotik est d\u00e9j\u00e0 configur\u00e9", - "already_configured_device": "L'appareil est d\u00e9j\u00e0 configur\u00e9" + "already_configured": "Mikrotik est d\u00e9j\u00e0 configur\u00e9" }, "error": { "cannot_connect": "\u00c9chec de la connexion", "invalid_auth": "Authentification invalide", - "name_exists": "Le nom existe", - "wrong_credentials": "Identifiants erron\u00e9s" + "name_exists": "Le nom existe" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/hu.json b/homeassistant/components/mikrotik/translations/hu.json index e68e0ceb414..67a2e8d8fc3 100644 --- a/homeassistant/components/mikrotik/translations/hu.json +++ b/homeassistant/components/mikrotik/translations/hu.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "A kapcsolat sikertelen", - "name_exists": "A n\u00e9v m\u00e1r l\u00e9tezik", - "wrong_credentials": "\u00c9rv\u00e9nytelen hiteles\u00edt\u0151 adatok" + "name_exists": "A n\u00e9v m\u00e1r l\u00e9tezik" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/it.json b/homeassistant/components/mikrotik/translations/it.json index a1bf16d643d..e4cafa914d4 100644 --- a/homeassistant/components/mikrotik/translations/it.json +++ b/homeassistant/components/mikrotik/translations/it.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "already_configured_device": "Il dispositivo \u00e8 gi\u00e0 configurato" + "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato" }, "error": { "cannot_connect": "Impossibile connettersi", "invalid_auth": "Autenticazione non valida", - "name_exists": "Il Nome esiste gi\u00e0", - "wrong_credentials": "Credenziali Errate" + "name_exists": "Il Nome esiste gi\u00e0" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/ko.json b/homeassistant/components/mikrotik/translations/ko.json index 04efde51ad4..f32e2260501 100644 --- a/homeassistant/components/mikrotik/translations/ko.json +++ b/homeassistant/components/mikrotik/translations/ko.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "\uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", - "name_exists": "\uc774\ub984\uc774 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4", - "wrong_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ud639\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" + "name_exists": "\uc774\ub984\uc774 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/lb.json b/homeassistant/components/mikrotik/translations/lb.json index affd538d517..e1e2c921dd1 100644 --- a/homeassistant/components/mikrotik/translations/lb.json +++ b/homeassistant/components/mikrotik/translations/lb.json @@ -1,13 +1,12 @@ { "config": { "abort": { - "already_configured": "Mikrotik ass scho konfigur\u00e9iert" + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Verbindung net erfollegr\u00e4ich", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "name_exists": "Numm g\u00ebtt et schonn", - "wrong_credentials": "Falsch Login Informatiounen" + "name_exists": "Numm g\u00ebtt et schonn" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/nl.json b/homeassistant/components/mikrotik/translations/nl.json index a3c86dda34b..53e05b5cf5f 100644 --- a/homeassistant/components/mikrotik/translations/nl.json +++ b/homeassistant/components/mikrotik/translations/nl.json @@ -5,8 +5,8 @@ }, "error": { "cannot_connect": "Verbinding niet geslaagd", - "name_exists": "Naam bestaat al", - "wrong_credentials": "Ongeldige inloggegevens" + "invalid_auth": "Ongeldige authenticatie", + "name_exists": "Naam bestaat al" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/no.json b/homeassistant/components/mikrotik/translations/no.json index 3b1a7dcd7b7..73efde429fe 100644 --- a/homeassistant/components/mikrotik/translations/no.json +++ b/homeassistant/components/mikrotik/translations/no.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "Enheten er allerede konfigurert", - "already_configured_device": "Enheten er allerede konfigurert" + "already_configured": "Enheten er allerede konfigurert" }, "error": { "cannot_connect": "Tilkobling mislyktes", "invalid_auth": "Ugyldig godkjenning", - "name_exists": "Navnet eksisterer", - "wrong_credentials": "Feil legitimasjon" + "name_exists": "Navnet eksisterer" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/pl.json b/homeassistant/components/mikrotik/translations/pl.json index 37682fdaf8a..8f056e29de6 100644 --- a/homeassistant/components/mikrotik/translations/pl.json +++ b/homeassistant/components/mikrotik/translations/pl.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "already_configured_device": "Urz\u0105dzenie jest ju\u017c skonfigurowane" + "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "invalid_auth": "Niepoprawne uwierzytelnienie", - "name_exists": "Nazwa ju\u017c istnieje", - "wrong_credentials": "B\u0142\u0119dne dane uwierzytelniaj\u0105ce" + "name_exists": "Nazwa ju\u017c istnieje" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/pt-BR.json b/homeassistant/components/mikrotik/translations/pt-BR.json index 48663023cf3..2a013ba4772 100644 --- a/homeassistant/components/mikrotik/translations/pt-BR.json +++ b/homeassistant/components/mikrotik/translations/pt-BR.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Conex\u00e3o malsucedida", - "name_exists": "O nome j\u00e1 existe", - "wrong_credentials": "Credenciais erradas" + "name_exists": "O nome j\u00e1 existe" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/ru.json b/homeassistant/components/mikrotik/translations/ru.json index a4596cc70d9..868ed49b5c4 100644 --- a/homeassistant/components/mikrotik/translations/ru.json +++ b/homeassistant/components/mikrotik/translations/ru.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "already_configured_device": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." + "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", - "name_exists": "\u042d\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f.", - "wrong_credentials": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435." + "name_exists": "\u042d\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f." }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/sl.json b/homeassistant/components/mikrotik/translations/sl.json index 10030cba559..095aa45f901 100644 --- a/homeassistant/components/mikrotik/translations/sl.json +++ b/homeassistant/components/mikrotik/translations/sl.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Povezava ni uspela", - "name_exists": "Ime obstaja", - "wrong_credentials": "Napa\u010dne poverilnice" + "name_exists": "Ime obstaja" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/sv.json b/homeassistant/components/mikrotik/translations/sv.json index 22cb8590c3b..39e645a4c03 100644 --- a/homeassistant/components/mikrotik/translations/sv.json +++ b/homeassistant/components/mikrotik/translations/sv.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Anslutningen misslyckades", - "name_exists": "Namnet finns", - "wrong_credentials": "Fel autentiseringsuppgifter" + "name_exists": "Namnet finns" }, "step": { "user": { diff --git a/homeassistant/components/mikrotik/translations/zh-Hant.json b/homeassistant/components/mikrotik/translations/zh-Hant.json index 5285d089fc6..0675ede61bd 100644 --- a/homeassistant/components/mikrotik/translations/zh-Hant.json +++ b/homeassistant/components/mikrotik/translations/zh-Hant.json @@ -1,14 +1,12 @@ { "config": { "abort": { - "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "already_configured_device": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "name_exists": "\u8a72\u540d\u7a31\u5df2\u5b58\u5728", - "wrong_credentials": "\u6191\u8b49\u932f\u8aa4" + "name_exists": "\u8a72\u540d\u7a31\u5df2\u5b58\u5728" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/ca.json b/homeassistant/components/mill/translations/ca.json index 8bffe056c7e..13ce41cec91 100644 --- a/homeassistant/components/mill/translations/ca.json +++ b/homeassistant/components/mill/translations/ca.json @@ -4,8 +4,7 @@ "already_configured": "El compte ja ha estat configurat" }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "Ha fallat la connexi\u00f3" + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/cs.json b/homeassistant/components/mill/translations/cs.json index 8c03d31bb60..fcbdf3fb428 100644 --- a/homeassistant/components/mill/translations/cs.json +++ b/homeassistant/components/mill/translations/cs.json @@ -4,8 +4,7 @@ "already_configured": "\u00da\u010det je ji\u017e nastaven" }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit" + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/de.json b/homeassistant/components/mill/translations/de.json index ad183cc2b8b..886e7e3c458 100644 --- a/homeassistant/components/mill/translations/de.json +++ b/homeassistant/components/mill/translations/de.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Account ist bereits konfiguriert" }, - "error": { - "connection_error": "Verbindung fehlgeschlagen" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/mill/translations/en.json b/homeassistant/components/mill/translations/en.json index 05bdd11cbd9..bb7d67f03b4 100644 --- a/homeassistant/components/mill/translations/en.json +++ b/homeassistant/components/mill/translations/en.json @@ -4,8 +4,7 @@ "already_configured": "Account is already configured" }, "error": { - "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect" + "cannot_connect": "Failed to connect" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/es.json b/homeassistant/components/mill/translations/es.json index 38f5a65ce86..2e664b38ff9 100644 --- a/homeassistant/components/mill/translations/es.json +++ b/homeassistant/components/mill/translations/es.json @@ -4,8 +4,7 @@ "already_configured": "La cuenta ya ha sido configurada" }, "error": { - "cannot_connect": "No se pudo conectar", - "connection_error": "No se pudo conectar" + "cannot_connect": "No se pudo conectar" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/et.json b/homeassistant/components/mill/translations/et.json index 777f234f6c3..c9f9d5dbd98 100644 --- a/homeassistant/components/mill/translations/et.json +++ b/homeassistant/components/mill/translations/et.json @@ -4,8 +4,7 @@ "already_configured": "Konto on juba seadistatud" }, "error": { - "cannot_connect": "\u00dchendus nurjus", - "connection_error": "\u00dchendamine nurjus" + "cannot_connect": "\u00dchendus nurjus" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/fr.json b/homeassistant/components/mill/translations/fr.json index 9fa7c48bb68..e171086a084 100644 --- a/homeassistant/components/mill/translations/fr.json +++ b/homeassistant/components/mill/translations/fr.json @@ -4,7 +4,7 @@ "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9" }, "error": { - "connection_error": "\u00c9chec de connexion" + "cannot_connect": "\u00c9chec de connexion" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/hu.json b/homeassistant/components/mill/translations/hu.json index c8dec2dcb2d..387a73041d9 100644 --- a/homeassistant/components/mill/translations/hu.json +++ b/homeassistant/components/mill/translations/hu.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "A fi\u00f3k m\u00e1r konfigur\u00e1lva van" }, - "error": { - "connection_error": "Sikertelen csatlakoz\u00e1s" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/mill/translations/it.json b/homeassistant/components/mill/translations/it.json index 7e3f909e048..5dc8b6ec2f1 100644 --- a/homeassistant/components/mill/translations/it.json +++ b/homeassistant/components/mill/translations/it.json @@ -4,7 +4,7 @@ "already_configured": "L'account \u00e8 gi\u00e0 configurato" }, "error": { - "connection_error": "Impossibile connettersi" + "cannot_connect": "Impossibile connettersi" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/ko.json b/homeassistant/components/mill/translations/ko.json index c604519ca79..d2c6fd74284 100644 --- a/homeassistant/components/mill/translations/ko.json +++ b/homeassistant/components/mill/translations/ko.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, - "error": { - "connection_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/mill/translations/lb.json b/homeassistant/components/mill/translations/lb.json index 186e53931b6..84aeac8bd97 100644 --- a/homeassistant/components/mill/translations/lb.json +++ b/homeassistant/components/mill/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "Kont ass scho registr\u00e9iert" }, "error": { - "connection_error": "Feeler beim verbannen" + "cannot_connect": "Feeler beim verbannen" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/nl.json b/homeassistant/components/mill/translations/nl.json index 4d00f0bfc74..4699b6fb733 100644 --- a/homeassistant/components/mill/translations/nl.json +++ b/homeassistant/components/mill/translations/nl.json @@ -1,8 +1,12 @@ { "config": { + "abort": { + "already_configured": "Account is al geconfigureerd" + }, "step": { "user": { "data": { + "password": "Password", "username": "Gebruikersnaam" } } diff --git a/homeassistant/components/mill/translations/no.json b/homeassistant/components/mill/translations/no.json index e87ab803fb3..ef481a449ae 100644 --- a/homeassistant/components/mill/translations/no.json +++ b/homeassistant/components/mill/translations/no.json @@ -4,8 +4,7 @@ "already_configured": "Kontoen er allerede konfigurert" }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes" + "cannot_connect": "Tilkobling mislyktes" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/pl.json b/homeassistant/components/mill/translations/pl.json index a7f80d4046d..a9ec418ddb3 100644 --- a/homeassistant/components/mill/translations/pl.json +++ b/homeassistant/components/mill/translations/pl.json @@ -4,8 +4,7 @@ "already_configured": "Konto jest ju\u017c skonfigurowane" }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/ru.json b/homeassistant/components/mill/translations/ru.json index e2c01e293ab..db2d4651c2d 100644 --- a/homeassistant/components/mill/translations/ru.json +++ b/homeassistant/components/mill/translations/ru.json @@ -4,8 +4,7 @@ "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." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "user": { diff --git a/homeassistant/components/mill/translations/zh-Hans.json b/homeassistant/components/mill/translations/zh-Hans.json index a5f4ff11f09..79079e6c408 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/mill/translations/zh-Hant.json b/homeassistant/components/mill/translations/zh-Hant.json index 37d766700bd..179100726da 100644 --- a/homeassistant/components/mill/translations/zh-Hant.json +++ b/homeassistant/components/mill/translations/zh-Hant.json @@ -4,8 +4,7 @@ "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "user": { diff --git a/homeassistant/components/minecraft_server/translations/et.json b/homeassistant/components/minecraft_server/translations/et.json index f8bdff71bb3..a92449b0512 100644 --- a/homeassistant/components/minecraft_server/translations/et.json +++ b/homeassistant/components/minecraft_server/translations/et.json @@ -4,13 +4,18 @@ "already_configured": "Teenus on juba seadistatud" }, "error": { - "cannot_connect": "Serveriga \u00fchenduse loomine nurjus. Kontrollige hosti ja porti ning proovige uuesti. Samuti veenduge, et kasutate oma serveris v\u00e4hemalt Minecrafti versiooni 1.7." + "cannot_connect": "Serveriga \u00fchenduse loomine nurjus. Kontrollige hosti ja porti ning proovige uuesti. Samuti veenduge, et kasutate oma serveris v\u00e4hemalt Minecrafti versiooni 1.7.", + "invalid_ip": "IP-aadress on vale (MAC-aadressi ei \u00f5nnestunud tuvastada). Paranda ja proovi uuesti.", + "invalid_port": "Lubatud pordivahemik on 1024\u201365535. Paranda ja proovi uuesti." }, "step": { "user": { "data": { - "host": "" - } + "host": "", + "name": "Nimi" + }, + "description": "Seadista oma Minecraft Server, et lubada j\u00e4lgimist.", + "title": "Lingi oma Minecrafti server" } } } diff --git a/homeassistant/components/minecraft_server/translations/lb.json b/homeassistant/components/minecraft_server/translations/lb.json index 8b08af7b10f..0a571abf323 100644 --- a/homeassistant/components/minecraft_server/translations/lb.json +++ b/homeassistant/components/minecraft_server/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Apparat ass scho konfigur\u00e9iert" + "already_configured": "Service ass scho konfigur\u00e9iert" }, "error": { "cannot_connect": "Feeler beim verbannen mam Server. Iwwerpr\u00e9if den Numm a Port a prob\u00e9ier nach emol. G\u00e9i och s\u00e9cher dass op d'mannst Minecraft Versioun 1.7 um Server leeft.", diff --git a/homeassistant/components/minecraft_server/translations/pl.json b/homeassistant/components/minecraft_server/translations/pl.json index eeba0ed860d..fed8d250a90 100644 --- a/homeassistant/components/minecraft_server/translations/pl.json +++ b/homeassistant/components/minecraft_server/translations/pl.json @@ -4,7 +4,7 @@ "already_configured": "Us\u0142uga jest ju\u017c skonfigurowana" }, "error": { - "cannot_connect": "B\u0142\u0105d po\u0142\u0105czenia z serwerem. Sprawd\u017a adres hosta i port i spr\u00f3buj ponownie. Upewnij si\u0119 tak\u017ce, \u017ce na serwerze dzia\u0142a Minecraft w wersji przynajmniej 1.7.", + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z serwerem. Sprawd\u017a adres hosta i port i spr\u00f3buj ponownie. Upewnij si\u0119 tak\u017ce, \u017ce na serwerze dzia\u0142a Minecraft w wersji przynajmniej 1.7.", "invalid_ip": "Adres IP jest nieprawid\u0142owy (nie mo\u017cna ustali\u0107 adresu MAC). Popraw to i spr\u00f3buj ponownie.", "invalid_port": "Port musi znajdowa\u0107 si\u0119 w zakresie od 1024 do 65535. Popraw go i spr\u00f3buj ponownie." }, diff --git a/homeassistant/components/mobile_app/translations/pl.json b/homeassistant/components/mobile_app/translations/pl.json index e5440984b37..15574f6d757 100644 --- a/homeassistant/components/mobile_app/translations/pl.json +++ b/homeassistant/components/mobile_app/translations/pl.json @@ -5,7 +5,7 @@ }, "step": { "confirm": { - "description": "Czy chcesz skonfigurowa\u0107 komponent aplikacji mobilnej?" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } } diff --git a/homeassistant/components/monoprice/translations/et.json b/homeassistant/components/monoprice/translations/et.json index 4f67d402c52..8f3f3ef3990 100644 --- a/homeassistant/components/monoprice/translations/et.json +++ b/homeassistant/components/monoprice/translations/et.json @@ -10,8 +10,30 @@ "step": { "user": { "data": { - "port": "" - } + "port": "", + "source_1": "Sisendi nr 1 nimi", + "source_2": "Sisendi nr 2 nimi", + "source_3": "Sisendi nr 3 nimi", + "source_4": "Sisendi nr 4 nimi", + "source_5": "Sisendi nr 5 nimi", + "source_6": "Sisendi nr 6 nimi" + }, + "title": "\u00dchendu seadmega" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "source_1": "Sisendi nr 1 nimi", + "source_2": "Sisendi nr 2 nimi", + "source_3": "Sisendi nr 3 nimi", + "source_4": "Sisendi nr 4 nimi", + "source_5": "Sisendi nr 5 nimi", + "source_6": "Sisendi nr 6 nimi" + }, + "title": "Sisendite seadistamine" } } } diff --git a/homeassistant/components/monoprice/translations/lb.json b/homeassistant/components/monoprice/translations/lb.json index 3482610e0b4..f3e1d41026c 100644 --- a/homeassistant/components/monoprice/translations/lb.json +++ b/homeassistant/components/monoprice/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "unknown": "Onerwaarte Feeler" }, "step": { diff --git a/homeassistant/components/monoprice/translations/pl.json b/homeassistant/components/monoprice/translations/pl.json index db2b1633ddd..60b5c986e97 100644 --- a/homeassistant/components/monoprice/translations/pl.json +++ b/homeassistant/components/monoprice/translations/pl.json @@ -33,7 +33,7 @@ "source_5": "Nazwa \u017ar\u00f3d\u0142a #5", "source_6": "Nazwa \u017ar\u00f3d\u0142a #6" }, - "title": "Konfiguruj \u017ar\u00f3d\u0142a" + "title": "Konfiguracja \u017ar\u00f3de\u0142" } } } diff --git a/homeassistant/components/mpd/media_player.py b/homeassistant/components/mpd/media_player.py index 845b0ae506b..69ab0a3421a 100644 --- a/homeassistant/components/mpd/media_player.py +++ b/homeassistant/components/mpd/media_player.py @@ -10,12 +10,16 @@ from homeassistant.components.media_player import PLATFORM_SCHEMA, MediaPlayerEn from homeassistant.components.media_player.const import ( MEDIA_TYPE_MUSIC, MEDIA_TYPE_PLAYLIST, + REPEAT_MODE_ALL, + REPEAT_MODE_OFF, + REPEAT_MODE_ONE, SUPPORT_CLEAR_PLAYLIST, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, + SUPPORT_REPEAT_SET, SUPPORT_SEEK, SUPPORT_SELECT_SOURCE, SUPPORT_SHUFFLE_SET, @@ -53,6 +57,7 @@ SUPPORT_MPD = ( | SUPPORT_PLAY_MEDIA | SUPPORT_PLAY | SUPPORT_CLEAR_PLAYLIST + | SUPPORT_REPEAT_SET | SUPPORT_SHUFFLE_SET | SUPPORT_SEEK | SUPPORT_STOP @@ -363,6 +368,27 @@ class MpdDevice(MediaPlayerEntity): self._client.add(media_id) self._client.play() + @property + def repeat(self): + """Return current repeat mode.""" + if self._status["repeat"] == "1": + if self._status["single"] == "1": + return REPEAT_MODE_ONE + return REPEAT_MODE_ALL + return REPEAT_MODE_OFF + + def set_repeat(self, repeat): + """Set repeat mode.""" + if repeat == REPEAT_MODE_OFF: + self._client.repeat(0) + self._client.single(0) + else: + self._client.repeat(1) + if repeat == REPEAT_MODE_ONE: + self._client.single(1) + else: + self._client.single(0) + @property def shuffle(self): """Boolean if shuffle is enabled.""" diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 09655ababda..5898b1918a2 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -10,6 +10,7 @@ import os import ssl import time from typing import Any, Callable, List, Optional, Union +import uuid import attr import certifi @@ -711,9 +712,10 @@ class MQTT: client_id = self.conf.get(CONF_CLIENT_ID) if client_id is None: - self._mqttc = mqtt.Client(protocol=proto) - else: - self._mqttc = mqtt.Client(client_id, protocol=proto) + # PAHO MQTT relies on the MQTT server to generate random client IDs. + # However, that feature is not mandatory so we generate our own. + client_id = mqtt.base62(uuid.uuid4().int, padding=22) + self._mqttc = mqtt.Client(client_id, protocol=proto) # Enable logging self._mqttc.enable_logger() diff --git a/homeassistant/components/mqtt/discovery.py b/homeassistant/components/mqtt/discovery.py index 7a478733826..7f9a6730285 100644 --- a/homeassistant/components/mqtt/discovery.py +++ b/homeassistant/components/mqtt/discovery.py @@ -102,14 +102,14 @@ async def async_start( 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/mqtt/light/schema_basic.py b/homeassistant/components/mqtt/light/schema_basic.py index 6fa6d70a665..4796652f57e 100644 --- a/homeassistant/components/mqtt/light/schema_basic.py +++ b/homeassistant/components/mqtt/light/schema_basic.py @@ -546,12 +546,21 @@ class MqttLight( @property def hs_color(self): """Return the hs color value.""" + if self._white_value: + return None return self._hs @property def color_temp(self): """Return the color temperature in mired.""" - return self._color_temp + supports_color = ( + self._topic[CONF_RGB_COMMAND_TOPIC] + or self._topic[CONF_HS_COMMAND_TOPIC] + or self._topic[CONF_XY_COMMAND_TOPIC] + ) + if self._white_value or not supports_color: + return self._color_temp + return None @property def min_mireds(self): @@ -569,7 +578,8 @@ class MqttLight( white_value = self._white_value if white_value: white_value = min(round(white_value), 255) - return white_value + return white_value + return None @property def should_poll(self): diff --git a/homeassistant/components/mqtt/manifest.json b/homeassistant/components/mqtt/manifest.json index 8b293eb06f6..4d44090a4e3 100644 --- a/homeassistant/components/mqtt/manifest.json +++ b/homeassistant/components/mqtt/manifest.json @@ -3,7 +3,7 @@ "name": "MQTT", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/mqtt", - "requirements": ["paho-mqtt==1.5.0"], + "requirements": ["paho-mqtt==1.5.1"], "dependencies": ["http"], "codeowners": ["@home-assistant/core", "@emontnemery"] } diff --git a/homeassistant/components/mqtt/subscription.py b/homeassistant/components/mqtt/subscription.py index feccdc33bc2..24c1c6ff3a1 100644 --- a/homeassistant/components/mqtt/subscription.py +++ b/homeassistant/components/mqtt/subscription.py @@ -29,6 +29,7 @@ class EntitySubscription: async def resubscribe_if_necessary(self, hass, other): """Re-subscribe to the new topic if necessary.""" if not self._should_resubscribe(other): + self.unsubscribe_callback = other.unsubscribe_callback return if other is not None and other.unsubscribe_callback is not None: diff --git a/homeassistant/components/mqtt/translations/de.json b/homeassistant/components/mqtt/translations/de.json index 7f34e10fa89..a92886eb0c6 100644 --- a/homeassistant/components/mqtt/translations/de.json +++ b/homeassistant/components/mqtt/translations/de.json @@ -49,6 +49,9 @@ } }, "options": { + "error": { + "cannot_connect": "Verbindung fehlgeschlagen" + }, "step": { "broker": { "data": { @@ -57,6 +60,11 @@ "port": "Port", "username": "Benutzername" } + }, + "options": { + "data": { + "will_enable": "Letzten Willen aktivieren" + } } } } diff --git a/homeassistant/components/mqtt/translations/lb.json b/homeassistant/components/mqtt/translations/lb.json index 955dda7ff9c..88a2664cd37 100644 --- a/homeassistant/components/mqtt/translations/lb.json +++ b/homeassistant/components/mqtt/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vum MQTT ass erlaabt" + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { - "cannot_connect": "Kann sech net mam Broker verbannen." + "cannot_connect": "Feeler beim verbannen" }, "step": { "broker": { @@ -72,7 +72,7 @@ "birth_retain": "Birth message retain", "birth_topic": "Birth message topic", "discovery": "Entdeckung aktiv\u00e9ieren", - "will_enable": "Gebuert Message aktiv\u00e9ieren", + "will_enable": "Will Message aktiv\u00e9ieren", "will_payload": "Will message payload", "will_qos": "Will message QoS", "will_retain": "Will message retain", diff --git a/homeassistant/components/mqtt/translations/nl.json b/homeassistant/components/mqtt/translations/nl.json index cedab89e3e2..a0ab0e497da 100644 --- a/homeassistant/components/mqtt/translations/nl.json +++ b/homeassistant/components/mqtt/translations/nl.json @@ -49,13 +49,17 @@ } }, "options": { + "error": { + "cannot_connect": "Kon niet verbinden" + }, "step": { "broker": { "data": { "password": "Wachtwoord", "port": "Poort", "username": "Gebruikersnaam" - } + }, + "description": "Voer de verbindingsgegevens van uw MQTT-broker in." }, "options": { "data": { diff --git a/homeassistant/components/mqtt/translations/pl.json b/homeassistant/components/mqtt/translations/pl.json index 7d0e0361edc..2c11afd52e9 100644 --- a/homeassistant/components/mqtt/translations/pl.json +++ b/homeassistant/components/mqtt/translations/pl.json @@ -34,8 +34,8 @@ "button_4": "czwarty", "button_5": "pi\u0105ty", "button_6": "sz\u00f3sty", - "turn_off": "nast\u0105pi wy\u0142\u0105czenie", - "turn_on": "nast\u0105pi w\u0142\u0105czenie" + "turn_off": "wy\u0142\u0105cznik", + "turn_on": "w\u0142\u0105cznik" }, "trigger_type": { "button_double_press": "\"{subtype}\" zostanie podw\u00f3jnie naci\u015bni\u0119ty", diff --git a/homeassistant/components/mqtt/translations/ru.json b/homeassistant/components/mqtt/translations/ru.json index bfac4cadecc..0079481d6f2 100644 --- a/homeassistant/components/mqtt/translations/ru.json +++ b/homeassistant/components/mqtt/translations/ru.json @@ -21,8 +21,8 @@ "data": { "discovery": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432" }, - "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 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0431\u0440\u043e\u043a\u0435\u0440\u0443 MQTT (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", - "title": "\u0411\u0440\u043e\u043a\u0435\u0440 MQTT (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io)" + "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 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0431\u0440\u043e\u043a\u0435\u0440\u0443 MQTT (\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", + "title": "\u0411\u0440\u043e\u043a\u0435\u0440 MQTT (\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io)" } } }, @@ -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/mqtt/translations/sl.json b/homeassistant/components/mqtt/translations/sl.json index 691fdcf058a..afd2f3b8000 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/myq/translations/et.json b/homeassistant/components/myq/translations/et.json index 9f5acce2c14..b51044a9e6e 100644 --- a/homeassistant/components/myq/translations/et.json +++ b/homeassistant/components/myq/translations/et.json @@ -13,7 +13,8 @@ "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "Loo \u00fchendus MyQ Gatewayga" } } } diff --git a/homeassistant/components/myq/translations/lb.json b/homeassistant/components/myq/translations/lb.json index 9e9ef66d1d6..32f73368f35 100644 --- a/homeassistant/components/myq/translations/lb.json +++ b/homeassistant/components/myq/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "MyQ ass scho konfigur\u00e9iert" + "already_configured": "Service ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, diff --git a/homeassistant/components/nad/media_player.py b/homeassistant/components/nad/media_player.py index 7d8537db6c6..782b8735e3a 100644 --- a/homeassistant/components/nad/media_player.py +++ b/homeassistant/components/nad/media_player.py @@ -163,7 +163,7 @@ class NAD(MediaPlayerEntity): @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/neato/translations/bg.json b/homeassistant/components/neato/translations/bg.json index c2ebfb92f94..f652830217a 100644 --- a/homeassistant/components/neato/translations/bg.json +++ b/homeassistant/components/neato/translations/bg.json @@ -1,16 +1,11 @@ { "config": { "abort": { - "already_configured": "\u0412\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d", - "invalid_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438" + "already_configured": "\u0412\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d" }, "create_entry": { "default": "\u0412\u0438\u0436\u0442\u0435 [Neato \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f]({docs_url})." }, - "error": { - "invalid_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438", - "unexpected_error": "\u041d\u0435\u043e\u0447\u0430\u043a\u0432\u0430\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/ca.json b/homeassistant/components/neato/translations/ca.json index c3d3426eb99..601af3a68e9 100644 --- a/homeassistant/components/neato/translations/ca.json +++ b/homeassistant/components/neato/translations/ca.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Credencials inv\u00e0lides" + "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "create_entry": { "default": "Consulta la [documentaci\u00f3 de Neato]({docs_url})." }, "error": { "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Credencials inv\u00e0lides", - "unexpected_error": "Error inesperat", "unknown": "Error inesperat" }, "step": { diff --git a/homeassistant/components/neato/translations/cs.json b/homeassistant/components/neato/translations/cs.json index d1669791991..bc53bc93f7a 100644 --- a/homeassistant/components/neato/translations/cs.json +++ b/homeassistant/components/neato/translations/cs.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje" + "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "create_entry": { "default": "Viz [dokumentace Neato]({docs_url})." }, "error": { "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje", - "unexpected_error": "Neo\u010dek\u00e1van\u00e1 chyba", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { diff --git a/homeassistant/components/neato/translations/da.json b/homeassistant/components/neato/translations/da.json index 33b3200927b..785bf4aca9d 100644 --- a/homeassistant/components/neato/translations/da.json +++ b/homeassistant/components/neato/translations/da.json @@ -1,16 +1,11 @@ { "config": { "abort": { - "already_configured": "Allerede konfigureret", - "invalid_credentials": "Ugyldige legitimationsoplysninger" + "already_configured": "Allerede konfigureret" }, "create_entry": { "default": "Se [Neato-dokumentation]({docs_url})." }, - "error": { - "invalid_credentials": "Ugyldige legitimationsoplysninger", - "unexpected_error": "Uventet fejl" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/de.json b/homeassistant/components/neato/translations/de.json index 7316275f37b..c41d4e6d93a 100644 --- a/homeassistant/components/neato/translations/de.json +++ b/homeassistant/components/neato/translations/de.json @@ -1,16 +1,11 @@ { "config": { "abort": { - "already_configured": "Bereits konfiguriert", - "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen" + "already_configured": "Bereits konfiguriert" }, "create_entry": { "default": "Siehe [Neato-Dokumentation]({docs_url})." }, - "error": { - "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen", - "unexpected_error": "Unerwarteter Fehler" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/en.json b/homeassistant/components/neato/translations/en.json index 5cc832f39b7..61b6ad44dfd 100644 --- a/homeassistant/components/neato/translations/en.json +++ b/homeassistant/components/neato/translations/en.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "Device is already configured", - "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid credentials" + "invalid_auth": "Invalid authentication" }, "create_entry": { "default": "See [Neato documentation]({docs_url})." }, "error": { "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid credentials", - "unexpected_error": "Unexpected error", "unknown": "Unexpected error" }, "step": { diff --git a/homeassistant/components/neato/translations/es-419.json b/homeassistant/components/neato/translations/es-419.json index a6a684597f6..46ae7ba2f86 100644 --- a/homeassistant/components/neato/translations/es-419.json +++ b/homeassistant/components/neato/translations/es-419.json @@ -1,16 +1,11 @@ { "config": { "abort": { - "already_configured": "Ya est\u00e1 configurado", - "invalid_credentials": "Credenciales no v\u00e1lidas" + "already_configured": "Ya est\u00e1 configurado" }, "create_entry": { "default": "Consulte [Documentaci\u00f3n de Neato] ({docs_url})." }, - "error": { - "invalid_credentials": "Credenciales no v\u00e1lidas", - "unexpected_error": "Error inesperado" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/es.json b/homeassistant/components/neato/translations/es.json index f4eddbd5800..abe1d21c90a 100644 --- a/homeassistant/components/neato/translations/es.json +++ b/homeassistant/components/neato/translations/es.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado", - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_credentials": "Credenciales no v\u00e1lidas" + "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "create_entry": { "default": "Ver [documentaci\u00f3n Neato]({docs_url})." }, "error": { "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_credentials": "Credenciales no v\u00e1lidas", - "unexpected_error": "Error inesperado", "unknown": "Error inesperado" }, "step": { diff --git a/homeassistant/components/neato/translations/et.json b/homeassistant/components/neato/translations/et.json index 8eed7850b4b..72ce208db3c 100644 --- a/homeassistant/components/neato/translations/et.json +++ b/homeassistant/components/neato/translations/et.json @@ -2,13 +2,13 @@ "config": { "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "invalid_auth": "Tuvastamise viga", - "invalid_credentials": "Sobimatu mandaat" + "invalid_auth": "Tuvastamise viga" + }, + "create_entry": { + "default": "Vaata [Neato documentation] ( {docs_url} )." }, "error": { "invalid_auth": "Tuvastamise viga", - "invalid_credentials": "Sobimatu mandaat", - "unexpected_error": "Ootamatu t\u00f5rge", "unknown": "Ootamatu t\u00f5rge" }, "step": { @@ -17,7 +17,9 @@ "password": "Salas\u00f5na", "username": "Kasutajanimi", "vendor": "Tootja" - } + }, + "description": "Vaata [Neato documentation] ( {docs_url} ).", + "title": "Neato konto teave" } } } diff --git a/homeassistant/components/neato/translations/fr.json b/homeassistant/components/neato/translations/fr.json index 11c06cd1c97..69f2186c54c 100644 --- a/homeassistant/components/neato/translations/fr.json +++ b/homeassistant/components/neato/translations/fr.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "D\u00e9j\u00e0 configur\u00e9", - "invalid_auth": "Authentification invalide", - "invalid_credentials": "Informations d'identification invalides" + "invalid_auth": "Authentification invalide" }, "create_entry": { "default": "Voir [Documentation Neato]({docs_url})." }, "error": { "invalid_auth": "Authentification invalide", - "invalid_credentials": "Informations d'identification invalides", - "unexpected_error": "Erreur inattendue", "unknown": "Erreur inattendue" }, "step": { diff --git a/homeassistant/components/neato/translations/hu.json b/homeassistant/components/neato/translations/hu.json index 329776ed228..1d88e45b2ca 100644 --- a/homeassistant/components/neato/translations/hu.json +++ b/homeassistant/components/neato/translations/hu.json @@ -1,16 +1,11 @@ { "config": { "abort": { - "already_configured": "M\u00e1r konfigur\u00e1lva van", - "invalid_credentials": "\u00c9rv\u00e9nytelen hiteles\u00edt\u0151 adatok" + "already_configured": "M\u00e1r konfigur\u00e1lva van" }, "create_entry": { "default": "L\u00e1sd: [Neato dokument\u00e1ci\u00f3] ( {docs_url} )." }, - "error": { - "invalid_credentials": "\u00c9rv\u00e9nytelen hiteles\u00edt\u0151 adatok", - "unexpected_error": "V\u00e1ratlan hiba" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/it.json b/homeassistant/components/neato/translations/it.json index 654862f0259..989bf9ce137 100644 --- a/homeassistant/components/neato/translations/it.json +++ b/homeassistant/components/neato/translations/it.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "invalid_auth": "Autenticazione non valida", - "invalid_credentials": "Credenziali non valide" + "invalid_auth": "Autenticazione non valida" }, "create_entry": { "default": "Vedere la [Documentazione di Neato]({docs_url})." }, "error": { "invalid_auth": "Autenticazione non valida", - "invalid_credentials": "Credenziali non valide", - "unexpected_error": "Errore inaspettato", "unknown": "Errore imprevisto" }, "step": { diff --git a/homeassistant/components/neato/translations/ko.json b/homeassistant/components/neato/translations/ko.json index 806bf54d35d..00d1ae3b467 100644 --- a/homeassistant/components/neato/translations/ko.json +++ b/homeassistant/components/neato/translations/ko.json @@ -1,16 +1,11 @@ { "config": { "abort": { - "already_configured": "\uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "invalid_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ud639\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" + "already_configured": "\uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "create_entry": { "default": "[Neato \uc124\uba85\uc11c]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, - "error": { - "invalid_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ud639\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "unexpected_error": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/lb.json b/homeassistant/components/neato/translations/lb.json index a2c2343f5ac..44d8e4f6811 100644 --- a/homeassistant/components/neato/translations/lb.json +++ b/homeassistant/components/neato/translations/lb.json @@ -1,17 +1,15 @@ { "config": { "abort": { - "already_configured": "Scho konfigur\u00e9iert", - "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_credentials": "Ong\u00eblteg Login Informatioune" + "already_configured": "Apparat ass scho konfigur\u00e9iert", + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "create_entry": { "default": "Kuckt [Neato Dokumentatioun]({docs_url})." }, "error": { "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_credentials": "Ong\u00eblteg Login Informatioune", - "unexpected_error": "Onerwaarte Feeler" + "unknown": "Onerwaarte Feeler" }, "step": { "user": { diff --git a/homeassistant/components/neato/translations/nl.json b/homeassistant/components/neato/translations/nl.json index 5e828a82668..26e5a647b1d 100644 --- a/homeassistant/components/neato/translations/nl.json +++ b/homeassistant/components/neato/translations/nl.json @@ -2,14 +2,14 @@ "config": { "abort": { "already_configured": "Al geconfigureerd", - "invalid_credentials": "Ongeldige gebruikersgegevens" + "invalid_auth": "Ongeldige authenticatie" }, "create_entry": { "default": "Zie [Neato-documentatie] ({docs_url})." }, "error": { - "invalid_credentials": "Ongeldige inloggegevens", - "unexpected_error": "Onverwachte fout" + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" }, "step": { "user": { diff --git a/homeassistant/components/neato/translations/no.json b/homeassistant/components/neato/translations/no.json index 57116666454..fcbc0361c24 100644 --- a/homeassistant/components/neato/translations/no.json +++ b/homeassistant/components/neato/translations/no.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "Enheten er allerede konfigurert", - "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig legitimasjon" + "invalid_auth": "Ugyldig godkjenning" }, "create_entry": { "default": "Se [Neato dokumentasjon]({docs_url})." }, "error": { "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig legitimasjon", - "unexpected_error": "Uventet feil", "unknown": "Uventet feil" }, "step": { diff --git a/homeassistant/components/neato/translations/pl.json b/homeassistant/components/neato/translations/pl.json index f857f1c3370..3b7054ea661 100644 --- a/homeassistant/components/neato/translations/pl.json +++ b/homeassistant/components/neato/translations/pl.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce" + "invalid_auth": "Niepoprawne uwierzytelnienie" }, "create_entry": { "default": "Zapoznaj si\u0119 z [dokumentacj\u0105 Neato]({docs_url})." }, "error": { "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce", - "unexpected_error": "Nieoczekiwany b\u0142\u0105d", "unknown": "Nieoczekiwany b\u0142\u0105d" }, "step": { diff --git a/homeassistant/components/neato/translations/pt.json b/homeassistant/components/neato/translations/pt.json index f0019df646a..b4642359973 100644 --- a/homeassistant/components/neato/translations/pt.json +++ b/homeassistant/components/neato/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "unexpected_error": "Erro inesperado" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/ru.json b/homeassistant/components/neato/translations/ru.json index cb899e4614a..e4a30539673 100644 --- a/homeassistant/components/neato/translations/ru.json +++ b/homeassistant/components/neato/translations/ru.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \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_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "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": { "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.", - "unexpected_error": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "step": { diff --git a/homeassistant/components/neato/translations/sl.json b/homeassistant/components/neato/translations/sl.json index ed20b5a904e..3ab2d0fd09d 100644 --- a/homeassistant/components/neato/translations/sl.json +++ b/homeassistant/components/neato/translations/sl.json @@ -1,16 +1,11 @@ { "config": { "abort": { - "already_configured": "\u017de konfigurirano", - "invalid_credentials": "Neveljavne poverilnice" + "already_configured": "\u017de konfigurirano" }, "create_entry": { "default": "Glejte [neato dokumentacija] ({docs_url})." }, - "error": { - "invalid_credentials": "Neveljavne poverilnice", - "unexpected_error": "Nepri\u010dakovana napaka" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/sv.json b/homeassistant/components/neato/translations/sv.json index eb0fa0ec6c8..544b6d2b292 100644 --- a/homeassistant/components/neato/translations/sv.json +++ b/homeassistant/components/neato/translations/sv.json @@ -1,16 +1,11 @@ { "config": { "abort": { - "already_configured": "Redan konfigurerad", - "invalid_credentials": "Ogiltiga autentiseringsuppgifter" + "already_configured": "Redan konfigurerad" }, "create_entry": { "default": "Se [Neato-dokumentation]({docs_url})." }, - "error": { - "invalid_credentials": "Ogiltiga autentiseringsuppgifter", - "unexpected_error": "Ov\u00e4ntat fel" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/zh-Hans.json b/homeassistant/components/neato/translations/zh-Hans.json index a5f4ff11f09..b0b26b02261 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/neato/translations/zh-Hant.json b/homeassistant/components/neato/translations/zh-Hant.json index 84d31b35e6d..2c5c8c61fef 100644 --- a/homeassistant/components/neato/translations/zh-Hant.json +++ b/homeassistant/components/neato/translations/zh-Hant.json @@ -2,16 +2,13 @@ "config": { "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u6191\u8b49\u7121\u6548" + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "create_entry": { "default": "\u8acb\u53c3\u95b1 [Neato \u6587\u4ef6]({docs_url})\u3002" }, "error": { "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u6191\u8b49\u7121\u6548", - "unexpected_error": "\u672a\u9810\u671f\u932f\u8aa4", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "step": { diff --git a/homeassistant/components/nest/__init__.py b/homeassistant/components/nest/__init__.py index 16ff05f9091..ea2bd549c4b 100644 --- a/homeassistant/components/nest/__init__.py +++ b/homeassistant/components/nest/__init__.py @@ -96,7 +96,8 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -PLATFORMS = ["sensor"] +# Platforms for SDM API +PLATFORMS = ["sensor", "camera", "climate"] # Services for the legacy API diff --git a/homeassistant/components/nest/camera.py b/homeassistant/components/nest/camera.py index 28188d11e2f..dfa365a36c3 100644 --- a/homeassistant/components/nest/camera.py +++ b/homeassistant/components/nest/camera.py @@ -1,150 +1,18 @@ -"""Support for Nest Cameras.""" -from datetime import timedelta -import logging +"""Support for Nest cameras that dispatches between API versions.""" -import requests +from homeassistant.config_entries import ConfigEntry +from homeassistant.helpers.typing import HomeAssistantType -from homeassistant.components import nest -from homeassistant.components.camera import PLATFORM_SCHEMA, SUPPORT_ON_OFF, Camera -from homeassistant.util.dt import utcnow - -_LOGGER = logging.getLogger(__name__) - -NEST_BRAND = "Nest" - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({}) +from .camera_legacy import async_setup_legacy_entry +from .camera_sdm import async_setup_sdm_entry +from .const import DATA_SDM -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up a Nest Cam. - - No longer in use. - """ - - -async def async_setup_entry(hass, entry, async_add_entities): - """Set up a Nest sensor based on a config entry.""" - camera_devices = await hass.async_add_executor_job( - hass.data[nest.DATA_NEST].cameras - ) - cameras = [NestCamera(structure, device) for structure, device in camera_devices] - async_add_entities(cameras, True) - - -class NestCamera(Camera): - """Representation of a Nest Camera.""" - - def __init__(self, structure, device): - """Initialize a Nest Camera.""" - super().__init__() - self.structure = structure - self.device = device - self._location = None - self._name = None - self._online = None - self._is_streaming = None - self._is_video_history_enabled = False - # Default to non-NestAware subscribed, but will be fixed during update - self._time_between_snapshots = timedelta(seconds=30) - self._last_image = None - self._next_snapshot_at = None - - @property - def name(self): - """Return the name of the nest, if any.""" - return self._name - - @property - def unique_id(self): - """Return the serial number.""" - return self.device.device_id - - @property - def device_info(self): - """Return information about the device.""" - return { - "identifiers": {(nest.DOMAIN, self.device.device_id)}, - "name": self.device.name_long, - "manufacturer": "Nest Labs", - "model": "Camera", - } - - @property - def should_poll(self): - """Nest camera should poll periodically.""" - return True - - @property - def is_recording(self): - """Return true if the device is recording.""" - return self._is_streaming - - @property - def brand(self): - """Return the brand of the camera.""" - return NEST_BRAND - - @property - def supported_features(self): - """Nest Cam support turn on and off.""" - return SUPPORT_ON_OFF - - @property - def is_on(self): - """Return true if on.""" - return self._online and self._is_streaming - - def turn_off(self): - """Turn off camera.""" - _LOGGER.debug("Turn off camera %s", self._name) - # Calling Nest API in is_streaming setter. - # device.is_streaming would not immediately change until the process - # finished in Nest Cam. - self.device.is_streaming = False - - def turn_on(self): - """Turn on camera.""" - if not self._online: - _LOGGER.error("Camera %s is offline", self._name) - return - - _LOGGER.debug("Turn on camera %s", self._name) - # Calling Nest API in is_streaming setter. - # device.is_streaming would not immediately change until the process - # finished in Nest Cam. - self.device.is_streaming = True - - def update(self): - """Cache value from Python-nest.""" - self._location = self.device.where - self._name = self.device.name - self._online = self.device.online - self._is_streaming = self.device.is_streaming - self._is_video_history_enabled = self.device.is_video_history_enabled - - if self._is_video_history_enabled: - # NestAware allowed 10/min - self._time_between_snapshots = timedelta(seconds=6) - else: - # Otherwise, 2/min - self._time_between_snapshots = timedelta(seconds=30) - - def _ready_for_snapshot(self, now): - return self._next_snapshot_at is None or now > self._next_snapshot_at - - def camera_image(self): - """Return a still image response from the camera.""" - now = utcnow() - if self._ready_for_snapshot(now): - url = self.device.snapshot_url - - try: - response = requests.get(url) - except requests.exceptions.RequestException as error: - _LOGGER.error("Error getting camera image: %s", error) - return None - - self._next_snapshot_at = now + self._time_between_snapshots - self._last_image = response.content - - return self._last_image +async def async_setup_entry( + hass: HomeAssistantType, entry: ConfigEntry, async_add_entities +) -> None: + """Set up the cameras.""" + if DATA_SDM not in entry.data: + await async_setup_legacy_entry(hass, entry, async_add_entities) + return + await async_setup_sdm_entry(hass, entry, async_add_entities) diff --git a/homeassistant/components/nest/camera_legacy.py b/homeassistant/components/nest/camera_legacy.py new file mode 100644 index 00000000000..48d9cb00783 --- /dev/null +++ b/homeassistant/components/nest/camera_legacy.py @@ -0,0 +1,150 @@ +"""Support for Nest Cameras.""" +from datetime import timedelta +import logging + +import requests + +from homeassistant.components import nest +from homeassistant.components.camera import PLATFORM_SCHEMA, SUPPORT_ON_OFF, Camera +from homeassistant.util.dt import utcnow + +_LOGGER = logging.getLogger(__name__) + +NEST_BRAND = "Nest" + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({}) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up a Nest Cam. + + No longer in use. + """ + + +async def async_setup_legacy_entry(hass, entry, async_add_entities): + """Set up a Nest sensor based on a config entry.""" + camera_devices = await hass.async_add_executor_job( + hass.data[nest.DATA_NEST].cameras + ) + cameras = [NestCamera(structure, device) for structure, device in camera_devices] + async_add_entities(cameras, True) + + +class NestCamera(Camera): + """Representation of a Nest Camera.""" + + def __init__(self, structure, device): + """Initialize a Nest Camera.""" + super().__init__() + self.structure = structure + self.device = device + self._location = None + self._name = None + self._online = None + self._is_streaming = None + self._is_video_history_enabled = False + # Default to non-NestAware subscribed, but will be fixed during update + self._time_between_snapshots = timedelta(seconds=30) + self._last_image = None + self._next_snapshot_at = None + + @property + def name(self): + """Return the name of the nest, if any.""" + return self._name + + @property + def unique_id(self): + """Return the serial number.""" + return self.device.device_id + + @property + def device_info(self): + """Return information about the device.""" + return { + "identifiers": {(nest.DOMAIN, self.device.device_id)}, + "name": self.device.name_long, + "manufacturer": "Nest Labs", + "model": "Camera", + } + + @property + def should_poll(self): + """Nest camera should poll periodically.""" + return True + + @property + def is_recording(self): + """Return true if the device is recording.""" + return self._is_streaming + + @property + def brand(self): + """Return the brand of the camera.""" + return NEST_BRAND + + @property + def supported_features(self): + """Nest Cam support turn on and off.""" + return SUPPORT_ON_OFF + + @property + def is_on(self): + """Return true if on.""" + return self._online and self._is_streaming + + def turn_off(self): + """Turn off camera.""" + _LOGGER.debug("Turn off camera %s", self._name) + # Calling Nest API in is_streaming setter. + # device.is_streaming would not immediately change until the process + # finished in Nest Cam. + self.device.is_streaming = False + + def turn_on(self): + """Turn on camera.""" + if not self._online: + _LOGGER.error("Camera %s is offline", self._name) + return + + _LOGGER.debug("Turn on camera %s", self._name) + # Calling Nest API in is_streaming setter. + # device.is_streaming would not immediately change until the process + # finished in Nest Cam. + self.device.is_streaming = True + + def update(self): + """Cache value from Python-nest.""" + self._location = self.device.where + self._name = self.device.name + self._online = self.device.online + self._is_streaming = self.device.is_streaming + self._is_video_history_enabled = self.device.is_video_history_enabled + + if self._is_video_history_enabled: + # NestAware allowed 10/min + self._time_between_snapshots = timedelta(seconds=6) + else: + # Otherwise, 2/min + self._time_between_snapshots = timedelta(seconds=30) + + def _ready_for_snapshot(self, now): + return self._next_snapshot_at is None or now > self._next_snapshot_at + + def camera_image(self): + """Return a still image response from the camera.""" + now = utcnow() + if self._ready_for_snapshot(now): + url = self.device.snapshot_url + + try: + response = requests.get(url) + except requests.exceptions.RequestException as error: + _LOGGER.error("Error getting camera image: %s", error) + return None + + self._next_snapshot_at = now + self._time_between_snapshots + self._last_image = response.content + + return self._last_image diff --git a/homeassistant/components/nest/camera_sdm.py b/homeassistant/components/nest/camera_sdm.py new file mode 100644 index 00000000000..a8c5c86c4e8 --- /dev/null +++ b/homeassistant/components/nest/camera_sdm.py @@ -0,0 +1,164 @@ +"""Support for Google Nest SDM Cameras.""" + +import datetime +import logging +from typing import Optional + +from aiohttp.client_exceptions import ClientError +from google_nest_sdm.camera_traits import CameraImageTrait, CameraLiveStreamTrait +from google_nest_sdm.device import Device +from haffmpeg.tools import IMAGE_JPEG + +from homeassistant.components.camera import SUPPORT_STREAM, Camera +from homeassistant.components.ffmpeg import async_get_image +from homeassistant.config_entries import ConfigEntry +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.event import async_track_point_in_utc_time +from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.util.dt import utcnow + +from .const import DOMAIN, SIGNAL_NEST_UPDATE +from .device_info import DeviceInfo + +_LOGGER = logging.getLogger(__name__) + +# Used to schedule an alarm to refresh the stream before expiration +STREAM_EXPIRATION_BUFFER = datetime.timedelta(seconds=30) + + +async def async_setup_sdm_entry( + hass: HomeAssistantType, entry: ConfigEntry, async_add_entities +) -> None: + """Set up the cameras.""" + + subscriber = hass.data[DOMAIN][entry.entry_id] + device_manager = await subscriber.async_get_device_manager() + + # Fetch initial data so we have data when entities subscribe. + + entities = [] + for device in device_manager.devices.values(): + if ( + CameraImageTrait.NAME in device.traits + or CameraLiveStreamTrait.NAME in device.traits + ): + entities.append(NestCamera(device)) + async_add_entities(entities) + + +class NestCamera(Camera): + """Devices that support cameras.""" + + def __init__(self, device: Device): + """Initialize the camera.""" + super().__init__() + self._device = device + self._device_info = DeviceInfo(device) + self._stream = None + self._stream_refresh_unsub = None + + @property + def should_poll(self) -> bool: + """Disable polling since entities have state pushed via pubsub.""" + return False + + @property + def unique_id(self) -> Optional[str]: + """Return a unique ID.""" + # The API "name" field is a unique device identifier. + return f"{self._device.name}-camera" + + @property + def name(self): + """Return the name of the camera.""" + return self._device_info.device_name + + @property + def device_info(self): + """Return device specific attributes.""" + return self._device_info.device_info + + @property + def brand(self): + """Return the camera brand.""" + return self._device_info.device_brand + + @property + def model(self): + """Return the camera model.""" + return self._device_info.device_model + + @property + def supported_features(self): + """Flag supported features.""" + if CameraLiveStreamTrait.NAME in self._device.traits: + return SUPPORT_STREAM + return 0 + + async def stream_source(self): + """Return the source of the stream.""" + if CameraLiveStreamTrait.NAME not in self._device.traits: + return None + trait = self._device.traits[CameraLiveStreamTrait.NAME] + if not self._stream: + _LOGGER.debug("Fetching stream url") + self._stream = await trait.generate_rtsp_stream() + self._schedule_stream_refresh() + if self._stream.expires_at < utcnow(): + _LOGGER.warning("Stream already expired") + return self._stream.rtsp_stream_url + + def _schedule_stream_refresh(self): + """Schedules an alarm to refresh the stream url before expiration.""" + _LOGGER.debug("New stream url expires at %s", self._stream.expires_at) + refresh_time = self._stream.expires_at - STREAM_EXPIRATION_BUFFER + # Schedule an alarm to extend the stream + if self._stream_refresh_unsub is not None: + self._stream_refresh_unsub() + + self._stream_refresh_unsub = async_track_point_in_utc_time( + self.hass, + self._handle_stream_refresh, + refresh_time, + ) + + async def _handle_stream_refresh(self, now): + """Alarm that fires to check if the stream should be refreshed.""" + if not self._stream: + return + _LOGGER.debug("Extending stream url") + self._stream_refresh_unsub = None + try: + self._stream = await self._stream.extend_rtsp_stream() + except ClientError as err: + _LOGGER.debug("Failed to extend stream: %s", err) + # Next attempt to catch a url will get a new one + self._stream = None + return + self._schedule_stream_refresh() + + async def async_will_remove_from_hass(self): + """Invalidates the RTSP token when unloaded.""" + if self._stream: + _LOGGER.debug("Invalidating stream") + await self._stream.stop_rtsp_stream() + if self._stream_refresh_unsub: + self._stream_refresh_unsub() + + async def async_added_to_hass(self): + """Run when entity is added to register update signal handler.""" + # Event messages trigger the SIGNAL_NEST_UPDATE, which is intercepted + # here to re-fresh the signals from _device. Unregister this callback + # when the entity is removed. + self.async_on_remove( + async_dispatcher_connect( + self.hass, SIGNAL_NEST_UPDATE, self.async_write_ha_state + ) + ) + + async def async_camera_image(self): + """Return bytes of camera image.""" + stream_url = await self.stream_source() + if not stream_url: + return None + return await async_get_image(self.hass, stream_url, output_format=IMAGE_JPEG) diff --git a/homeassistant/components/nest/climate.py b/homeassistant/components/nest/climate.py index 7571845e66e..6e457da039c 100644 --- a/homeassistant/components/nest/climate.py +++ b/homeassistant/components/nest/climate.py @@ -1,355 +1,18 @@ -"""Support for Nest thermostats.""" -import logging +"""Support for Nest climate that dispatches between API versions.""" -from nest.nest import APIError -import voluptuous as vol +from homeassistant.config_entries import ConfigEntry +from homeassistant.helpers.typing import HomeAssistantType -from homeassistant.components.climate import PLATFORM_SCHEMA, ClimateEntity -from homeassistant.components.climate.const import ( - ATTR_TARGET_TEMP_HIGH, - ATTR_TARGET_TEMP_LOW, - CURRENT_HVAC_COOL, - CURRENT_HVAC_HEAT, - CURRENT_HVAC_IDLE, - FAN_AUTO, - FAN_ON, - HVAC_MODE_AUTO, - HVAC_MODE_COOL, - HVAC_MODE_HEAT, - HVAC_MODE_OFF, - PRESET_AWAY, - PRESET_ECO, - PRESET_NONE, - SUPPORT_FAN_MODE, - SUPPORT_PRESET_MODE, - SUPPORT_TARGET_TEMPERATURE, - SUPPORT_TARGET_TEMPERATURE_RANGE, -) -from homeassistant.const import ( - ATTR_TEMPERATURE, - CONF_SCAN_INTERVAL, - TEMP_CELSIUS, - TEMP_FAHRENHEIT, -) -from homeassistant.helpers.dispatcher import async_dispatcher_connect +from .climate_legacy import async_setup_legacy_entry +from .climate_sdm import async_setup_sdm_entry +from .const import DATA_SDM -from . import DATA_NEST, DOMAIN as NEST_DOMAIN -from .const import SIGNAL_NEST_UPDATE -_LOGGER = logging.getLogger(__name__) - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( - {vol.Optional(CONF_SCAN_INTERVAL): vol.All(vol.Coerce(int), vol.Range(min=1))} -) - -NEST_MODE_HEAT_COOL = "heat-cool" -NEST_MODE_ECO = "eco" -NEST_MODE_HEAT = "heat" -NEST_MODE_COOL = "cool" -NEST_MODE_OFF = "off" - -MODE_HASS_TO_NEST = { - HVAC_MODE_AUTO: NEST_MODE_HEAT_COOL, - HVAC_MODE_HEAT: NEST_MODE_HEAT, - HVAC_MODE_COOL: NEST_MODE_COOL, - HVAC_MODE_OFF: NEST_MODE_OFF, -} - -MODE_NEST_TO_HASS = {v: k for k, v in MODE_HASS_TO_NEST.items()} - -ACTION_NEST_TO_HASS = { - "off": CURRENT_HVAC_IDLE, - "heating": CURRENT_HVAC_HEAT, - "cooling": CURRENT_HVAC_COOL, -} - -PRESET_AWAY_AND_ECO = "Away and Eco" - -PRESET_MODES = [PRESET_NONE, PRESET_AWAY, PRESET_ECO, PRESET_AWAY_AND_ECO] - - -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up the Nest thermostat. - - No longer in use. - """ - - -async def async_setup_entry(hass, entry, async_add_entities): - """Set up the Nest climate device based on a config entry.""" - temp_unit = hass.config.units.temperature_unit - - thermostats = await hass.async_add_executor_job(hass.data[DATA_NEST].thermostats) - - all_devices = [ - NestThermostat(structure, device, temp_unit) - for structure, device in thermostats - ] - - async_add_entities(all_devices, True) - - -class NestThermostat(ClimateEntity): - """Representation of a Nest thermostat.""" - - def __init__(self, structure, device, temp_unit): - """Initialize the thermostat.""" - self._unit = temp_unit - self.structure = structure - self.device = device - self._fan_modes = [FAN_ON, FAN_AUTO] - - # Set the default supported features - self._support_flags = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE - - # Not all nest devices support cooling and heating remove unused - self._operation_list = [] - - if self.device.can_heat and self.device.can_cool: - self._operation_list.append(HVAC_MODE_AUTO) - self._support_flags = self._support_flags | SUPPORT_TARGET_TEMPERATURE_RANGE - - # Add supported nest thermostat features - if self.device.can_heat: - self._operation_list.append(HVAC_MODE_HEAT) - - if self.device.can_cool: - self._operation_list.append(HVAC_MODE_COOL) - - self._operation_list.append(HVAC_MODE_OFF) - - # feature of device - self._has_fan = self.device.has_fan - if self._has_fan: - self._support_flags = self._support_flags | SUPPORT_FAN_MODE - - # data attributes - self._away = None - self._location = None - self._name = None - self._humidity = None - self._target_temperature = None - self._temperature = None - self._temperature_scale = None - self._mode = None - self._action = None - self._fan = None - self._eco_temperature = None - self._is_locked = None - self._locked_temperature = None - self._min_temperature = None - self._max_temperature = None - - @property - def should_poll(self): - """Do not need poll thanks using Nest streaming API.""" - return False - - async def async_added_to_hass(self): - """Register update signal handler.""" - - async def async_update_state(): - """Update device state.""" - await self.async_update_ha_state(True) - - self.async_on_remove( - async_dispatcher_connect(self.hass, SIGNAL_NEST_UPDATE, async_update_state) - ) - - @property - def supported_features(self): - """Return the list of supported features.""" - return self._support_flags - - @property - def unique_id(self): - """Return unique ID for this device.""" - return self.device.serial - - @property - def device_info(self): - """Return information about the device.""" - return { - "identifiers": {(NEST_DOMAIN, self.device.device_id)}, - "name": self.device.name_long, - "manufacturer": "Nest Labs", - "model": "Thermostat", - "sw_version": self.device.software_version, - } - - @property - def name(self): - """Return the name of the nest, if any.""" - return self._name - - @property - def temperature_unit(self): - """Return the unit of measurement.""" - return self._temperature_scale - - @property - def current_temperature(self): - """Return the current temperature.""" - return self._temperature - - @property - def hvac_mode(self): - """Return current operation ie. heat, cool, idle.""" - if self._mode == NEST_MODE_ECO: - if self.device.previous_mode in MODE_NEST_TO_HASS: - return MODE_NEST_TO_HASS[self.device.previous_mode] - - # previous_mode not supported so return the first compatible mode - return self._operation_list[0] - - return MODE_NEST_TO_HASS[self._mode] - - @property - def hvac_action(self): - """Return the current hvac action.""" - return ACTION_NEST_TO_HASS[self._action] - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - if self._mode not in (NEST_MODE_HEAT_COOL, NEST_MODE_ECO): - return self._target_temperature - return None - - @property - def target_temperature_low(self): - """Return the lower bound temperature we try to reach.""" - if self._mode == NEST_MODE_ECO: - return self._eco_temperature[0] - if self._mode == NEST_MODE_HEAT_COOL: - return self._target_temperature[0] - return None - - @property - def target_temperature_high(self): - """Return the upper bound temperature we try to reach.""" - if self._mode == NEST_MODE_ECO: - return self._eco_temperature[1] - if self._mode == NEST_MODE_HEAT_COOL: - return self._target_temperature[1] - return None - - def set_temperature(self, **kwargs): - """Set new target temperature.""" - - temp = None - target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW) - target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH) - if self._mode == NEST_MODE_HEAT_COOL: - if target_temp_low is not None and target_temp_high is not None: - temp = (target_temp_low, target_temp_high) - _LOGGER.debug("Nest set_temperature-output-value=%s", temp) - else: - temp = kwargs.get(ATTR_TEMPERATURE) - _LOGGER.debug("Nest set_temperature-output-value=%s", temp) - try: - if temp is not None: - self.device.target = temp - except APIError as api_error: - _LOGGER.error("An error occurred while setting temperature: %s", api_error) - # restore target temperature - self.schedule_update_ha_state(True) - - def set_hvac_mode(self, hvac_mode): - """Set operation mode.""" - self.device.mode = MODE_HASS_TO_NEST[hvac_mode] - - @property - def hvac_modes(self): - """List of available operation modes.""" - return self._operation_list - - @property - def preset_mode(self): - """Return current preset mode.""" - if self._away and self._mode == NEST_MODE_ECO: - return PRESET_AWAY_AND_ECO - - if self._away: - return PRESET_AWAY - - if self._mode == NEST_MODE_ECO: - return PRESET_ECO - - return PRESET_NONE - - @property - def preset_modes(self): - """Return preset modes.""" - return PRESET_MODES - - def set_preset_mode(self, preset_mode): - """Set preset mode.""" - if preset_mode == self.preset_mode: - return - - need_away = preset_mode in (PRESET_AWAY, PRESET_AWAY_AND_ECO) - need_eco = preset_mode in (PRESET_ECO, PRESET_AWAY_AND_ECO) - is_away = self._away - is_eco = self._mode == NEST_MODE_ECO - - if is_away != need_away: - self.structure.away = need_away - - if is_eco != need_eco: - if need_eco: - self.device.mode = NEST_MODE_ECO - else: - self.device.mode = self.device.previous_mode - - @property - def fan_mode(self): - """Return whether the fan is on.""" - if self._has_fan: - # Return whether the fan is on - return FAN_ON if self._fan else FAN_AUTO - # No Fan available so disable slider - return None - - @property - def fan_modes(self): - """List of available fan modes.""" - if self._has_fan: - return self._fan_modes - return None - - def set_fan_mode(self, fan_mode): - """Turn fan on/off.""" - if self._has_fan: - self.device.fan = fan_mode.lower() - - @property - def min_temp(self): - """Identify min_temp in Nest API or defaults if not available.""" - return self._min_temperature - - @property - def max_temp(self): - """Identify max_temp in Nest API or defaults if not available.""" - return self._max_temperature - - def update(self): - """Cache value from Python-nest.""" - self._location = self.device.where - self._name = self.device.name - self._humidity = self.device.humidity - self._temperature = self.device.temperature - self._mode = self.device.mode - self._action = self.device.hvac_state - self._target_temperature = self.device.target - self._fan = self.device.fan - self._away = self.structure.away == "away" - self._eco_temperature = self.device.eco_temperature - self._locked_temperature = self.device.locked_temperature - self._min_temperature = self.device.min_temperature - self._max_temperature = self.device.max_temperature - self._is_locked = self.device.is_locked - if self.device.temperature_scale == "C": - self._temperature_scale = TEMP_CELSIUS - else: - self._temperature_scale = TEMP_FAHRENHEIT +async def async_setup_entry( + hass: HomeAssistantType, entry: ConfigEntry, async_add_entities +) -> None: + """Set up the climate platform.""" + if DATA_SDM not in entry.data: + await async_setup_legacy_entry(hass, entry, async_add_entities) + return + await async_setup_sdm_entry(hass, entry, async_add_entities) diff --git a/homeassistant/components/nest/climate_legacy.py b/homeassistant/components/nest/climate_legacy.py new file mode 100644 index 00000000000..ee28a0905c3 --- /dev/null +++ b/homeassistant/components/nest/climate_legacy.py @@ -0,0 +1,355 @@ +"""Support for Nest thermostats.""" +import logging + +from nest.nest import APIError +import voluptuous as vol + +from homeassistant.components.climate import PLATFORM_SCHEMA, ClimateEntity +from homeassistant.components.climate.const import ( + ATTR_TARGET_TEMP_HIGH, + ATTR_TARGET_TEMP_LOW, + CURRENT_HVAC_COOL, + CURRENT_HVAC_HEAT, + CURRENT_HVAC_IDLE, + FAN_AUTO, + FAN_ON, + HVAC_MODE_AUTO, + HVAC_MODE_COOL, + HVAC_MODE_HEAT, + HVAC_MODE_OFF, + PRESET_AWAY, + PRESET_ECO, + PRESET_NONE, + SUPPORT_FAN_MODE, + SUPPORT_PRESET_MODE, + SUPPORT_TARGET_TEMPERATURE, + SUPPORT_TARGET_TEMPERATURE_RANGE, +) +from homeassistant.const import ( + ATTR_TEMPERATURE, + CONF_SCAN_INTERVAL, + TEMP_CELSIUS, + TEMP_FAHRENHEIT, +) +from homeassistant.helpers.dispatcher import async_dispatcher_connect + +from . import DATA_NEST, DOMAIN as NEST_DOMAIN +from .const import SIGNAL_NEST_UPDATE + +_LOGGER = logging.getLogger(__name__) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + {vol.Optional(CONF_SCAN_INTERVAL): vol.All(vol.Coerce(int), vol.Range(min=1))} +) + +NEST_MODE_HEAT_COOL = "heat-cool" +NEST_MODE_ECO = "eco" +NEST_MODE_HEAT = "heat" +NEST_MODE_COOL = "cool" +NEST_MODE_OFF = "off" + +MODE_HASS_TO_NEST = { + HVAC_MODE_AUTO: NEST_MODE_HEAT_COOL, + HVAC_MODE_HEAT: NEST_MODE_HEAT, + HVAC_MODE_COOL: NEST_MODE_COOL, + HVAC_MODE_OFF: NEST_MODE_OFF, +} + +MODE_NEST_TO_HASS = {v: k for k, v in MODE_HASS_TO_NEST.items()} + +ACTION_NEST_TO_HASS = { + "off": CURRENT_HVAC_IDLE, + "heating": CURRENT_HVAC_HEAT, + "cooling": CURRENT_HVAC_COOL, +} + +PRESET_AWAY_AND_ECO = "Away and Eco" + +PRESET_MODES = [PRESET_NONE, PRESET_AWAY, PRESET_ECO, PRESET_AWAY_AND_ECO] + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the Nest thermostat. + + No longer in use. + """ + + +async def async_setup_legacy_entry(hass, entry, async_add_entities): + """Set up the Nest climate device based on a config entry.""" + temp_unit = hass.config.units.temperature_unit + + thermostats = await hass.async_add_executor_job(hass.data[DATA_NEST].thermostats) + + all_devices = [ + NestThermostat(structure, device, temp_unit) + for structure, device in thermostats + ] + + async_add_entities(all_devices, True) + + +class NestThermostat(ClimateEntity): + """Representation of a Nest thermostat.""" + + def __init__(self, structure, device, temp_unit): + """Initialize the thermostat.""" + self._unit = temp_unit + self.structure = structure + self.device = device + self._fan_modes = [FAN_ON, FAN_AUTO] + + # Set the default supported features + self._support_flags = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE + + # Not all nest devices support cooling and heating remove unused + self._operation_list = [] + + if self.device.can_heat and self.device.can_cool: + self._operation_list.append(HVAC_MODE_AUTO) + self._support_flags |= SUPPORT_TARGET_TEMPERATURE_RANGE + + # Add supported nest thermostat features + if self.device.can_heat: + self._operation_list.append(HVAC_MODE_HEAT) + + if self.device.can_cool: + self._operation_list.append(HVAC_MODE_COOL) + + self._operation_list.append(HVAC_MODE_OFF) + + # feature of device + self._has_fan = self.device.has_fan + if self._has_fan: + self._support_flags |= SUPPORT_FAN_MODE + + # data attributes + self._away = None + self._location = None + self._name = None + self._humidity = None + self._target_temperature = None + self._temperature = None + self._temperature_scale = None + self._mode = None + self._action = None + self._fan = None + self._eco_temperature = None + self._is_locked = None + self._locked_temperature = None + self._min_temperature = None + self._max_temperature = None + + @property + def should_poll(self): + """Do not need poll thanks using Nest streaming API.""" + return False + + async def async_added_to_hass(self): + """Register update signal handler.""" + + async def async_update_state(): + """Update device state.""" + await self.async_update_ha_state(True) + + self.async_on_remove( + async_dispatcher_connect(self.hass, SIGNAL_NEST_UPDATE, async_update_state) + ) + + @property + def supported_features(self): + """Return the list of supported features.""" + return self._support_flags + + @property + def unique_id(self): + """Return unique ID for this device.""" + return self.device.serial + + @property + def device_info(self): + """Return information about the device.""" + return { + "identifiers": {(NEST_DOMAIN, self.device.device_id)}, + "name": self.device.name_long, + "manufacturer": "Nest Labs", + "model": "Thermostat", + "sw_version": self.device.software_version, + } + + @property + def name(self): + """Return the name of the nest, if any.""" + return self._name + + @property + def temperature_unit(self): + """Return the unit of measurement.""" + return self._temperature_scale + + @property + def current_temperature(self): + """Return the current temperature.""" + return self._temperature + + @property + def hvac_mode(self): + """Return current operation ie. heat, cool, idle.""" + if self._mode == NEST_MODE_ECO: + if self.device.previous_mode in MODE_NEST_TO_HASS: + return MODE_NEST_TO_HASS[self.device.previous_mode] + + # previous_mode not supported so return the first compatible mode + return self._operation_list[0] + + return MODE_NEST_TO_HASS[self._mode] + + @property + def hvac_action(self): + """Return the current hvac action.""" + return ACTION_NEST_TO_HASS[self._action] + + @property + def target_temperature(self): + """Return the temperature we try to reach.""" + if self._mode not in (NEST_MODE_HEAT_COOL, NEST_MODE_ECO): + return self._target_temperature + return None + + @property + def target_temperature_low(self): + """Return the lower bound temperature we try to reach.""" + if self._mode == NEST_MODE_ECO: + return self._eco_temperature[0] + if self._mode == NEST_MODE_HEAT_COOL: + return self._target_temperature[0] + return None + + @property + def target_temperature_high(self): + """Return the upper bound temperature we try to reach.""" + if self._mode == NEST_MODE_ECO: + return self._eco_temperature[1] + if self._mode == NEST_MODE_HEAT_COOL: + return self._target_temperature[1] + return None + + def set_temperature(self, **kwargs): + """Set new target temperature.""" + + temp = None + target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW) + target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH) + if self._mode == NEST_MODE_HEAT_COOL: + if target_temp_low is not None and target_temp_high is not None: + temp = (target_temp_low, target_temp_high) + _LOGGER.debug("Nest set_temperature-output-value=%s", temp) + else: + temp = kwargs.get(ATTR_TEMPERATURE) + _LOGGER.debug("Nest set_temperature-output-value=%s", temp) + try: + if temp is not None: + self.device.target = temp + except APIError as api_error: + _LOGGER.error("An error occurred while setting temperature: %s", api_error) + # restore target temperature + self.schedule_update_ha_state(True) + + def set_hvac_mode(self, hvac_mode): + """Set operation mode.""" + self.device.mode = MODE_HASS_TO_NEST[hvac_mode] + + @property + def hvac_modes(self): + """List of available operation modes.""" + return self._operation_list + + @property + def preset_mode(self): + """Return current preset mode.""" + if self._away and self._mode == NEST_MODE_ECO: + return PRESET_AWAY_AND_ECO + + if self._away: + return PRESET_AWAY + + if self._mode == NEST_MODE_ECO: + return PRESET_ECO + + return PRESET_NONE + + @property + def preset_modes(self): + """Return preset modes.""" + return PRESET_MODES + + def set_preset_mode(self, preset_mode): + """Set preset mode.""" + if preset_mode == self.preset_mode: + return + + need_away = preset_mode in (PRESET_AWAY, PRESET_AWAY_AND_ECO) + need_eco = preset_mode in (PRESET_ECO, PRESET_AWAY_AND_ECO) + is_away = self._away + is_eco = self._mode == NEST_MODE_ECO + + if is_away != need_away: + self.structure.away = need_away + + if is_eco != need_eco: + if need_eco: + self.device.mode = NEST_MODE_ECO + else: + self.device.mode = self.device.previous_mode + + @property + def fan_mode(self): + """Return whether the fan is on.""" + if self._has_fan: + # Return whether the fan is on + return FAN_ON if self._fan else FAN_AUTO + # No Fan available so disable slider + return None + + @property + def fan_modes(self): + """List of available fan modes.""" + if self._has_fan: + return self._fan_modes + return None + + def set_fan_mode(self, fan_mode): + """Turn fan on/off.""" + if self._has_fan: + self.device.fan = fan_mode.lower() + + @property + def min_temp(self): + """Identify min_temp in Nest API or defaults if not available.""" + return self._min_temperature + + @property + def max_temp(self): + """Identify max_temp in Nest API or defaults if not available.""" + return self._max_temperature + + def update(self): + """Cache value from Python-nest.""" + self._location = self.device.where + self._name = self.device.name + self._humidity = self.device.humidity + self._temperature = self.device.temperature + self._mode = self.device.mode + self._action = self.device.hvac_state + self._target_temperature = self.device.target + self._fan = self.device.fan + self._away = self.structure.away == "away" + self._eco_temperature = self.device.eco_temperature + self._locked_temperature = self.device.locked_temperature + self._min_temperature = self.device.min_temperature + self._max_temperature = self.device.max_temperature + self._is_locked = self.device.is_locked + if self.device.temperature_scale == "C": + self._temperature_scale = TEMP_CELSIUS + else: + self._temperature_scale = TEMP_FAHRENHEIT diff --git a/homeassistant/components/nest/climate_sdm.py b/homeassistant/components/nest/climate_sdm.py new file mode 100644 index 00000000000..57598e36ec9 --- /dev/null +++ b/homeassistant/components/nest/climate_sdm.py @@ -0,0 +1,329 @@ +"""Support for Google Nest SDM climate devices.""" + +from typing import Optional + +from google_nest_sdm.device import Device +from google_nest_sdm.device_traits import FanTrait, TemperatureTrait +from google_nest_sdm.thermostat_traits import ( + ThermostatEcoTrait, + ThermostatHvacTrait, + ThermostatModeTrait, + ThermostatTemperatureSetpointTrait, +) + +from homeassistant.components.climate import ClimateEntity +from homeassistant.components.climate.const import ( + ATTR_TARGET_TEMP_HIGH, + ATTR_TARGET_TEMP_LOW, + CURRENT_HVAC_COOL, + CURRENT_HVAC_HEAT, + CURRENT_HVAC_OFF, + FAN_OFF, + FAN_ON, + HVAC_MODE_AUTO, + HVAC_MODE_COOL, + HVAC_MODE_HEAT, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + PRESET_ECO, + PRESET_NONE, + SUPPORT_FAN_MODE, + SUPPORT_PRESET_MODE, + SUPPORT_TARGET_TEMPERATURE, + SUPPORT_TARGET_TEMPERATURE_RANGE, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.typing import HomeAssistantType + +from .const import DOMAIN, SIGNAL_NEST_UPDATE +from .device_info import DeviceInfo + +# Mapping for sdm.devices.traits.ThermostatMode mode field +THERMOSTAT_MODE_MAP = { + "OFF": HVAC_MODE_OFF, + "HEAT": HVAC_MODE_HEAT, + "COOL": HVAC_MODE_COOL, + "HEATCOOL": HVAC_MODE_HEAT_COOL, +} +THERMOSTAT_INV_MODE_MAP = {v: k for k, v in THERMOSTAT_MODE_MAP.items()} + +# Mode for sdm.devices.traits.ThermostatEco +THERMOSTAT_ECO_MODE = "MANUAL_ECO" + +# Mapping for sdm.devices.traits.ThermostatHvac status field +THERMOSTAT_HVAC_STATUS_MAP = { + "OFF": CURRENT_HVAC_OFF, + "HEATING": CURRENT_HVAC_HEAT, + "COOLING": CURRENT_HVAC_COOL, +} + +THERMOSTAT_RANGE_MODES = [HVAC_MODE_HEAT_COOL, HVAC_MODE_AUTO] + +PRESET_MODE_MAP = { + "MANUAL_ECO": PRESET_ECO, + "OFF": PRESET_NONE, +} +PRESET_INV_MODE_MAP = {v: k for k, v in PRESET_MODE_MAP.items()} + +FAN_MODE_MAP = { + "ON": FAN_ON, + "OFF": FAN_OFF, +} +FAN_INV_MODE_MAP = {v: k for k, v in FAN_MODE_MAP.items()} + + +async def async_setup_sdm_entry( + hass: HomeAssistantType, entry: ConfigEntry, async_add_entities +) -> None: + """Set up the client entities.""" + + subscriber = hass.data[DOMAIN][entry.entry_id] + device_manager = await subscriber.async_get_device_manager() + + entities = [] + for device in device_manager.devices.values(): + if ThermostatHvacTrait.NAME in device.traits: + entities.append(ThermostatEntity(device)) + async_add_entities(entities) + + +class ThermostatEntity(ClimateEntity): + """A nest thermostat climate entity.""" + + def __init__(self, device: Device): + """Initialize ThermostatEntity.""" + self._device = device + self._device_info = DeviceInfo(device) + self._supported_features = 0 + + @property + def should_poll(self) -> bool: + """Disable polling since entities have state pushed via pubsub.""" + return False + + @property + def unique_id(self) -> Optional[str]: + """Return a unique ID.""" + # The API "name" field is a unique device identifier. + return self._device.name + + @property + def name(self): + """Return the name of the entity.""" + return self._device_info.device_name + + @property + def device_info(self): + """Return device specific attributes.""" + return self._device_info.device_info + + async def async_added_to_hass(self): + """Run when entity is added to register update signal handler.""" + # Event messages trigger the SIGNAL_NEST_UPDATE, which is intercepted + # here to re-fresh the signals from _device. Unregister this callback + # when the entity is removed. + self._supported_features = self._get_supported_features() + self.async_on_remove( + async_dispatcher_connect( + self.hass, + SIGNAL_NEST_UPDATE, + self.async_write_ha_state, + ) + ) + + @property + def temperature_unit(self): + """Return the unit of temperature measurement for the system.""" + return TEMP_CELSIUS + + @property + def current_temperature(self): + """Return the current temperature.""" + if TemperatureTrait.NAME not in self._device.traits: + return None + trait = self._device.traits[TemperatureTrait.NAME] + return trait.ambient_temperature_celsius + + @property + def target_temperature(self): + """Return the temperature currently set to be reached.""" + trait = self._target_temperature_trait + if not trait: + return None + if self.hvac_mode == HVAC_MODE_HEAT: + return trait.heat_celsius + if self.hvac_mode == HVAC_MODE_COOL: + return trait.cool_celsius + return None + + @property + def target_temperature_high(self): + """Return the upper bound target temperature.""" + if self.hvac_mode != HVAC_MODE_HEAT_COOL: + return None + trait = self._target_temperature_trait + if not trait: + return None + return trait.cool_celsius + + @property + def target_temperature_low(self): + """Return the lower bound target temperature.""" + if self.hvac_mode != HVAC_MODE_HEAT_COOL: + return None + trait = self._target_temperature_trait + if not trait: + return None + return trait.heat_celsius + + @property + def _target_temperature_trait(self): + """Return the correct trait with a target temp depending on mode.""" + if not self.hvac_mode: + return None + if self.preset_mode == PRESET_ECO: + if ThermostatEcoTrait.NAME in self._device.traits: + return self._device.traits[ThermostatEcoTrait.NAME] + if ThermostatTemperatureSetpointTrait.NAME in self._device.traits: + return self._device.traits[ThermostatTemperatureSetpointTrait.NAME] + return None + + @property + def hvac_mode(self): + """Return the current operation (e.g. heat, cool, idle).""" + if ThermostatModeTrait.NAME in self._device.traits: + trait = self._device.traits[ThermostatModeTrait.NAME] + if trait.mode in THERMOSTAT_MODE_MAP: + return THERMOSTAT_MODE_MAP[trait.mode] + return HVAC_MODE_OFF + + @property + def hvac_modes(self): + """List of available operation modes.""" + supported_modes = [] + for mode in self._get_device_hvac_modes: + if mode in THERMOSTAT_MODE_MAP: + supported_modes.append(THERMOSTAT_MODE_MAP[mode]) + return supported_modes + + @property + def _get_device_hvac_modes(self): + """Return the set of SDM API hvac modes supported by the device.""" + modes = [] + if ThermostatModeTrait.NAME in self._device.traits: + trait = self._device.traits[ThermostatModeTrait.NAME] + modes.extend(trait.available_modes) + return set(modes) + + @property + def hvac_action(self): + """Return the current HVAC action (heating, cooling).""" + if ThermostatHvacTrait.NAME not in self._device.traits: + return None + trait = self._device.traits[ThermostatHvacTrait.NAME] + if trait.status in THERMOSTAT_HVAC_STATUS_MAP: + return THERMOSTAT_HVAC_STATUS_MAP[trait.status] + return None + + @property + def preset_mode(self): + """Return the current active preset.""" + if ThermostatEcoTrait.NAME in self._device.traits: + trait = self._device.traits[ThermostatEcoTrait.NAME] + return PRESET_MODE_MAP.get(trait.mode, PRESET_NONE) + return PRESET_NONE + + @property + def preset_modes(self): + """Return the available presets.""" + modes = [] + if ThermostatEcoTrait.NAME in self._device.traits: + trait = self._device.traits[ThermostatEcoTrait.NAME] + for mode in trait.available_modes: + if mode in PRESET_MODE_MAP: + modes.append(PRESET_MODE_MAP[mode]) + return modes + + @property + def fan_mode(self): + """Return the current fan mode.""" + if FanTrait.NAME in self._device.traits: + trait = self._device.traits[FanTrait.NAME] + return FAN_MODE_MAP.get(trait.timer_mode, FAN_OFF) + return FAN_OFF + + @property + def fan_modes(self): + """Return the list of available fan modes.""" + if FanTrait.NAME in self._device.traits: + return list(FAN_INV_MODE_MAP) + return [] + + @property + def supported_features(self): + """Bitmap of supported features.""" + return self._supported_features + + def _get_supported_features(self): + """Compute the bitmap of supported features from the current state.""" + features = 0 + if HVAC_MODE_HEAT_COOL in self.hvac_modes: + features |= SUPPORT_TARGET_TEMPERATURE_RANGE + if HVAC_MODE_HEAT in self.hvac_modes or HVAC_MODE_COOL in self.hvac_modes: + features |= SUPPORT_TARGET_TEMPERATURE + if ThermostatEcoTrait.NAME in self._device.traits: + features |= SUPPORT_PRESET_MODE + if FanTrait.NAME in self._device.traits: + # Fan trait may be present without actually support fan mode + fan_trait = self._device.traits[FanTrait.NAME] + if fan_trait.timer_mode is not None: + features |= SUPPORT_FAN_MODE + return features + + async def async_set_hvac_mode(self, hvac_mode): + """Set new target hvac mode.""" + if hvac_mode not in self.hvac_modes: + return + if hvac_mode not in THERMOSTAT_INV_MODE_MAP: + return + api_mode = THERMOSTAT_INV_MODE_MAP[hvac_mode] + if ThermostatModeTrait.NAME not in self._device.traits: + return + trait = self._device.traits[ThermostatModeTrait.NAME] + await trait.set_mode(api_mode) + + async def async_set_temperature(self, **kwargs): + """Set new target temperature.""" + low_temp = kwargs.get(ATTR_TARGET_TEMP_LOW) + high_temp = kwargs.get(ATTR_TARGET_TEMP_HIGH) + temp = kwargs.get(ATTR_TEMPERATURE) + if ThermostatTemperatureSetpointTrait.NAME not in self._device.traits: + return + trait = self._device.traits[ThermostatTemperatureSetpointTrait.NAME] + if self.preset_mode == PRESET_ECO or self.hvac_mode == HVAC_MODE_HEAT_COOL: + if low_temp and high_temp: + await trait.set_range(low_temp, high_temp) + elif self.hvac_mode == HVAC_MODE_COOL and temp: + await trait.set_cool(temp) + elif self.hvac_mode == HVAC_MODE_HEAT and temp: + await trait.set_heat(temp) + + async def async_set_preset_mode(self, preset_mode): + """Set new target preset mode.""" + if preset_mode not in self.preset_modes: + return + if ThermostatEcoTrait.NAME not in self._device.traits: + return + trait = self._device.traits[ThermostatEcoTrait.NAME] + await trait.set_mode(PRESET_INV_MODE_MAP[preset_mode]) + + async def async_set_fan_mode(self, fan_mode): + """Set new target fan mode.""" + if fan_mode not in self.fan_modes: + return + if FanTrait.NAME not in self._device.traits: + return + trait = self._device.traits[FanTrait.NAME] + await trait.set_timer(FAN_INV_MODE_MAP[fan_mode]) diff --git a/homeassistant/components/nest/device_info.py b/homeassistant/components/nest/device_info.py new file mode 100644 index 00000000000..36419d0dd6b --- /dev/null +++ b/homeassistant/components/nest/device_info.py @@ -0,0 +1,58 @@ +"""Library for extracting device specific information common to entities.""" + +from google_nest_sdm.device import Device +from google_nest_sdm.device_traits import InfoTrait + +from .const import DOMAIN + +DEVICE_TYPE_MAP = { + "sdm.devices.types.CAMERA": "Camera", + "sdm.devices.types.DISPLAY": "Display", + "sdm.devices.types.DOORBELL": "Doorbell", + "sdm.devices.types.THERMOSTAT": "Thermostat", +} + + +class DeviceInfo: + """Provide device info from the SDM device, shared across platforms.""" + + device_brand = "Google Nest" + + def __init__(self, device: Device): + """Initialize the DeviceInfo.""" + self._device = device + + @property + def device_info(self): + """Return device specific attributes.""" + return { + # The API "name" field is a unique device identifier. + "identifiers": {(DOMAIN, self._device.name)}, + "name": self.device_name, + "manufacturer": self.device_brand, + "model": self.device_model, + } + + @property + def device_name(self): + """Return the name of the physical device that includes the sensor.""" + if InfoTrait.NAME in self._device.traits: + trait = self._device.traits[InfoTrait.NAME] + if trait.custom_name: + return trait.custom_name + # Build a name from the room/structure. Note: This room/structure name + # is not associated with a home assistant Area. + parent_relations = self._device.parent_relations + if parent_relations: + items = sorted(parent_relations.items()) + names = [name for id, name in items] + return " ".join(names) + return self.device_model + + @property + def device_model(self): + """Return device model information.""" + # The API intentionally returns minimal information about specific + # devices, instead relying on traits, but we can infer a generic model + # name based on the type + return DEVICE_TYPE_MAP.get(self._device.type) diff --git a/homeassistant/components/nest/manifest.json b/homeassistant/components/nest/manifest.json index 0686b5add1d..9e8a48fa95f 100644 --- a/homeassistant/components/nest/manifest.json +++ b/homeassistant/components/nest/manifest.json @@ -2,11 +2,11 @@ "domain": "nest", "name": "Nest", "config_flow": true, - "dependencies": ["http"], + "dependencies": ["ffmpeg", "http"], "documentation": "https://www.home-assistant.io/integrations/nest", "requirements": [ "python-nest==4.1.0", - "google-nest-sdm==0.1.6" + "google-nest-sdm==0.1.14" ], "codeowners": [ "@awarecan", diff --git a/homeassistant/components/nest/sensor_sdm.py b/homeassistant/components/nest/sensor_sdm.py index 6c4e37e57b3..68c33529831 100644 --- a/homeassistant/components/nest/sensor_sdm.py +++ b/homeassistant/components/nest/sensor_sdm.py @@ -3,7 +3,7 @@ from typing import Optional from google_nest_sdm.device import Device -from google_nest_sdm.device_traits import HumidityTrait, InfoTrait, TemperatureTrait +from google_nest_sdm.device_traits import HumidityTrait, TemperatureTrait from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( @@ -17,6 +17,7 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import HomeAssistantType from .const import DOMAIN, SIGNAL_NEST_UPDATE +from .device_info import DeviceInfo DEVICE_TYPE_MAP = { "sdm.devices.types.CAMERA": "Camera", @@ -32,7 +33,7 @@ async def async_setup_sdm_entry( """Set up the sensors.""" subscriber = hass.data[DOMAIN][entry.entry_id] - device_manager = await subscriber.async_device_manager + device_manager = await subscriber.async_get_device_manager() # Fetch initial data so we have data when entities subscribe. @@ -51,6 +52,7 @@ class SensorBase(Entity): def __init__(self, device: Device): """Initialize the sensor.""" self._device = device + self._device_info = DeviceInfo(device) @property def should_poll(self) -> bool: @@ -63,40 +65,10 @@ class SensorBase(Entity): # The API "name" field is a unique device identifier. return f"{self._device.name}-{self.device_class}" - @property - def device_name(self): - """Return the name of the physical device that includes the sensor.""" - if InfoTrait.NAME in self._device.traits: - trait = self._device.traits[InfoTrait.NAME] - if trait.custom_name: - return trait.custom_name - # Build a name from the room/structure. Note: This room/structure name - # is not associated with a home assistant Area. - parent_relations = self._device.parent_relations - if parent_relations: - items = sorted(parent_relations.items()) - names = [name for id, name in items] - return " ".join(names) - return self.unique_id - @property def device_info(self): """Return device specific attributes.""" - return { - # The API "name" field is a unique device identifier. - "identifiers": {(DOMAIN, self._device.name)}, - "name": self.device_name, - "manufacturer": "Google Nest", - "model": self.device_model, - } - - @property - def device_model(self): - """Return device model information.""" - # The API intentionally returns minimal information about specific - # devices, instead relying on traits, but we can infer a generic model - # name based on the type - return DEVICE_TYPE_MAP.get(self._device.type) + return self._device_info.device_info async def async_added_to_hass(self): """Run when entity is added to register update signal handler.""" @@ -118,7 +90,7 @@ class TemperatureSensor(SensorBase): @property def name(self): """Return the name of the sensor.""" - return f"{self.device_name} Temperature" + return f"{self._device_info.device_name} Temperature" @property def state(self): @@ -149,7 +121,7 @@ class HumiditySensor(SensorBase): @property def name(self): """Return the name of the sensor.""" - return f"{self.device_name} Humidity" + return f"{self._device_info.device_name} Humidity" @property def state(self): diff --git a/homeassistant/components/nest/translations/bg.json b/homeassistant/components/nest/translations/bg.json index c5b303e9cdd..b45171d2817 100644 --- a/homeassistant/components/nest/translations/bg.json +++ b/homeassistant/components/nest/translations/bg.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "\u041c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u0438\u043d Nest \u0430\u043a\u0430\u0443\u043d\u0442.", "authorize_url_fail": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u0437\u0430 \u043e\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f.", - "authorize_url_timeout": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u0437\u0430 \u043e\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0432 \u0441\u0440\u043e\u043a.", - "no_flows": "\u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 Nest, \u043f\u0440\u0435\u0434\u0438 \u0434\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0441\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0438\u0440\u0430\u0442\u0435. [\u041c\u043e\u043b\u044f, \u043f\u0440\u043e\u0447\u0435\u0442\u0435\u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438\u0442\u0435](https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u0437\u0430 \u043e\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0432 \u0441\u0440\u043e\u043a." }, "error": { "internal_error": "\u0412\u044a\u0437\u043d\u0438\u043a\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0434\u0430", - "invalid_code": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d \u043a\u043e\u0434", "timeout": "\u0412\u0440\u0435\u043c\u0435\u0442\u043e \u0437\u0430 \u043f\u043e\u0442\u0432\u044a\u0440\u0436\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0434\u0430 \u0438\u0437\u0442\u0435\u0447\u0435", "unknown": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0434\u0430." }, diff --git a/homeassistant/components/nest/translations/ca.json b/homeassistant/components/nest/translations/ca.json index ecb15329348..e65e264e3f7 100644 --- a/homeassistant/components/nest/translations/ca.json +++ b/homeassistant/components/nest/translations/ca.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "Nom\u00e9s pots configurar un \u00fanic compte Nest.", "authorize_url_fail": "S'ha produ\u00eft un error desconegut al generar l'URL d'autoritzaci\u00f3.", "authorize_url_timeout": "Temps d'espera esgotat durant la generaci\u00f3 de l'URL d'autoritzaci\u00f3.", "missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3.", - "no_flows": "Necessites configurar Nest abans de poder autenticar-t'hi. Llegeix les [instruccions](https://www.home-assistant.io/components/nest/).", + "no_url_available": "No hi ha cap URL disponible. Per a m\u00e9s informaci\u00f3 sobre aquest error, [consulta la secci\u00f3 d'ajuda]({docs_url})", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "create_entry": { @@ -13,7 +12,6 @@ }, "error": { "internal_error": "Error intern al validar el codi", - "invalid_code": "Codi inv\u00e0lid", "invalid_pin": "Codi PIN inv\u00e0lid", "timeout": "S'ha acabat el temps d'espera durant la validaci\u00f3 del codi.", "unknown": "Error inesperat" diff --git a/homeassistant/components/nest/translations/cs.json b/homeassistant/components/nest/translations/cs.json index dd9240270a1..28268d9bab8 100644 --- a/homeassistant/components/nest/translations/cs.json +++ b/homeassistant/components/nest/translations/cs.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "M\u016f\u017eete nastavit pouze jeden Nest \u00fa\u010det.", "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_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." }, "create_entry": { @@ -13,7 +12,6 @@ }, "error": { "internal_error": "Intern\u00ed chyba ov\u011b\u0159en\u00ed k\u00f3du", - "invalid_code": "Neplatn\u00fd k\u00f3d", "invalid_pin": "Neplatn\u00fd PIN k\u00f3d", "timeout": "\u010casov\u00fd limit ov\u011b\u0159ov\u00e1n\u00ed k\u00f3du vypr\u0161el", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" diff --git a/homeassistant/components/nest/translations/da.json b/homeassistant/components/nest/translations/da.json index 2666696f8d6..234c9ba97f4 100644 --- a/homeassistant/components/nest/translations/da.json +++ b/homeassistant/components/nest/translations/da.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Du kan kun konfigurere en enkelt Nest konto.", "authorize_url_fail": "Ukendt fejl ved generering af en autoriseret url.", - "authorize_url_timeout": "Timeout ved generering af autoriseret url.", - "no_flows": "Du skal konfigurere Nest f\u00f8r du kan autentificere med det. [L\u00e6s venligst vejledningen](https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "Timeout ved generering af autoriseret url." }, "error": { "internal_error": "Intern fejl ved validering af kode", - "invalid_code": "Ugyldig kode", "timeout": "Timeout ved validering af kode", "unknown": "Ukendt fejl ved validering af kode" }, diff --git a/homeassistant/components/nest/translations/de.json b/homeassistant/components/nest/translations/de.json index ccad67ea97c..3f55b19b255 100644 --- a/homeassistant/components/nest/translations/de.json +++ b/homeassistant/components/nest/translations/de.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Du kannst nur ein einziges Nest-Konto konfigurieren.", "authorize_url_fail": "Unbekannter Fehler beim Erstellen der Authorisierungs-URL", - "authorize_url_timeout": "Zeit\u00fcberschreitung beim Erstellen der Authorisierungs-URL", - "no_flows": "Du musst Nest konfigurieren, bevor du dich authentifizieren kannst. [Bitte lese die Anweisungen] (https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "Zeit\u00fcberschreitung beim Erstellen der Authorisierungs-URL" }, "error": { "internal_error": "Ein interner Fehler ist aufgetreten", - "invalid_code": "Ung\u00fcltiger Code", "invalid_pin": "Ung\u00fcltiger PIN-Code", "timeout": "Ein zeit\u00fcberschreitungs Fehler ist aufgetreten", "unknown": "Ein unbekannter Fehler ist aufgetreten" diff --git a/homeassistant/components/nest/translations/en.json b/homeassistant/components/nest/translations/en.json index 4243926a55e..8839f24e30a 100644 --- a/homeassistant/components/nest/translations/en.json +++ b/homeassistant/components/nest/translations/en.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "You can only configure a single Nest account.", "authorize_url_fail": "Unknown error generating an authorize url.", "authorize_url_timeout": "Timeout generating authorize URL.", "missing_configuration": "The component is not configured. Please follow the documentation.", - "no_flows": "You need to configure Nest before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/components/nest/).", + "no_url_available": "No URL available. For information about this error, [check the help section]({docs_url})", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "create_entry": { @@ -13,7 +12,6 @@ }, "error": { "internal_error": "Internal error validating code", - "invalid_code": "Invalid code", "invalid_pin": "Invalid PIN Code", "timeout": "Timeout validating code", "unknown": "Unexpected error" diff --git a/homeassistant/components/nest/translations/es-419.json b/homeassistant/components/nest/translations/es-419.json index f7e19809f6b..94c1d95e4d7 100644 --- a/homeassistant/components/nest/translations/es-419.json +++ b/homeassistant/components/nest/translations/es-419.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Solo puedes configurar una sola cuenta Nest.", "authorize_url_fail": "Error desconocido al generar una URL de autorizaci\u00f3n.", - "authorize_url_timeout": "Tiempo de espera agotado para generar la URL de autorizaci\u00f3n.", - "no_flows": "Debe configurar Nest antes de poder autenticarse con \u00e9l. [Lea las instrucciones] (https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "Tiempo de espera agotado para generar la URL de autorizaci\u00f3n." }, "error": { "internal_error": "C\u00f3digo de validaci\u00f3n de error interno", - "invalid_code": "Codigo invalido", "timeout": "Tiempo de espera agotado para validar el c\u00f3digo", "unknown": "Error desconocido al validar el c\u00f3digo" }, diff --git a/homeassistant/components/nest/translations/es.json b/homeassistant/components/nest/translations/es.json index 8003c3e98f7..0c902ff89be 100644 --- a/homeassistant/components/nest/translations/es.json +++ b/homeassistant/components/nest/translations/es.json @@ -1,16 +1,17 @@ { "config": { "abort": { - "already_setup": "S\u00f3lo puedes configurar una \u00fanica cuenta de Nest.", "authorize_url_fail": "Error desconocido generando la url de autorizaci\u00f3n", "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": { + "default": "Autenticado con \u00e9xito" + }, "error": { "internal_error": "Error interno validando el c\u00f3digo", - "invalid_code": "C\u00f3digo inv\u00e1lido", "invalid_pin": "C\u00f3digo PIN no v\u00e1lido", "timeout": "Tiempo de espera agotado validando el c\u00f3digo", "unknown": "Error desconocido validando el c\u00f3digo" @@ -29,6 +30,9 @@ }, "description": "Para vincular tu cuenta de Nest, [autoriza tu cuenta]({url}).\n\nDespu\u00e9s de la autorizaci\u00f3n, copia y pega el c\u00f3digo pin a continuaci\u00f3n.", "title": "Vincular cuenta de Nest" + }, + "pick_implementation": { + "title": "Elija el m\u00e9todo de autenticaci\u00f3n" } } } diff --git a/homeassistant/components/nest/translations/et.json b/homeassistant/components/nest/translations/et.json index 1389bbb5c14..37f7e26a885 100644 --- a/homeassistant/components/nest/translations/et.json +++ b/homeassistant/components/nest/translations/et.json @@ -1,16 +1,17 @@ { "config": { "abort": { - "already_setup": "Saate konfigureerida ainult \u00fche Nest-i konto.", "authorize_url_fail": "Tundmatu viga tuvastamise URL-i loomisel.", - "authorize_url_timeout": "Tuvastamise URL- i loomise ajal\u00f5pp.", + "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": { + "default": "Tuvastamine \u00f5nnestus" + }, "error": { "internal_error": "Sisemine viga tuvastuskoodi kinnitamisel", - "invalid_code": "Kehtetu kood", "invalid_pin": "Vale PIN kood", "timeout": "Tuvastuskoodi ajal\u00f5pp", "unknown": "Tundmatu viga tuvastuskoodi kinnitamisel" @@ -25,7 +26,7 @@ }, "link": { "data": { - "code": "PIN-kood" + "code": "PIN kood" }, "description": "Nest-i konto linkimiseks [authorize your account] ({url}).\n\nP\u00e4rast autoriseerimist kopeeri allolev PIN kood.", "title": "Lingi Nesti konto" diff --git a/homeassistant/components/nest/translations/fi.json b/homeassistant/components/nest/translations/fi.json index d810bd0657e..d81891d89b4 100644 --- a/homeassistant/components/nest/translations/fi.json +++ b/homeassistant/components/nest/translations/fi.json @@ -1,12 +1,8 @@ { "config": { "abort": { - "already_setup": "Voit m\u00e4\u00e4ritt\u00e4\u00e4 vain yhden Nest-tilin.", "authorize_url_fail": "Tuntematon virhe luotaessa valtuutuksen URL-osoitetta." }, - "error": { - "invalid_code": "Virheellinen koodi" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/nest/translations/fr.json b/homeassistant/components/nest/translations/fr.json index 6308098b9c1..be006913f65 100644 --- a/homeassistant/components/nest/translations/fr.json +++ b/homeassistant/components/nest/translations/fr.json @@ -1,14 +1,18 @@ { "config": { "abort": { - "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_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 +30,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/nest/translations/he.json b/homeassistant/components/nest/translations/he.json index a0ed6659865..9d0974128dd 100644 --- a/homeassistant/components/nest/translations/he.json +++ b/homeassistant/components/nest/translations/he.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "\u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05d2\u05d3\u05d9\u05e8 \u05d7\u05e9\u05d1\u05d5\u05df Nest \u05d9\u05d7\u05d9\u05d3.", "authorize_url_fail": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05dc\u05d0 \u05d9\u05d3\u05d5\u05e2\u05d4 \u05d1\u05d9\u05e6\u05d9\u05e8\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8 \u05d0\u05d9\u05de\u05d5\u05ea.", - "authorize_url_timeout": "\u05e2\u05d1\u05e8 \u05d4\u05d6\u05de\u05df \u05d4\u05e7\u05e6\u05d5\u05d1 \u05e2\u05d1\u05d5\u05e8 \u05d9\u05e6\u05d9\u05e8\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8 \u05d0\u05d9\u05de\u05d5\u05ea", - "no_flows": "\u05e2\u05dc\u05d9\u05da \u05dc\u05d4\u05d2\u05d3\u05d9\u05e8 \u05d0\u05ea Nest \u05dc\u05e4\u05e0\u05d9 \u05e9\u05ea\u05d5\u05db\u05dc \u05dc\u05d0\u05de\u05ea \u05d0\u05ea\u05d5. [\u05d0\u05e0\u05d0 \u05e7\u05e8\u05d0 \u05d0\u05ea \u05d4\u05d4\u05d5\u05e8\u05d0\u05d5\u05ea] (https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "\u05e2\u05d1\u05e8 \u05d4\u05d6\u05de\u05df \u05d4\u05e7\u05e6\u05d5\u05d1 \u05e2\u05d1\u05d5\u05e8 \u05d9\u05e6\u05d9\u05e8\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8 \u05d0\u05d9\u05de\u05d5\u05ea" }, "error": { "internal_error": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05e4\u05e0\u05d9\u05de\u05d9\u05ea \u05d1\u05d0\u05d9\u05de\u05d5\u05ea \u05d4\u05e7\u05d5\u05d3", - "invalid_code": "\u05e7\u05d5\u05d3 \u05dc\u05d0 \u05ea\u05e7\u05d9\u05df", "timeout": "\u05e2\u05d1\u05e8 \u05d4\u05d6\u05de\u05df \u05d4\u05e7\u05e6\u05d5\u05d1 \u05dc\u05d0\u05d9\u05de\u05d5\u05ea \u05d4\u05e7\u05d5\u05d3", "unknown": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05dc\u05d0 \u05d9\u05d3\u05d5\u05e2\u05d4 \u05d1\u05d0\u05d9\u05de\u05d5\u05ea \u05d4\u05e7\u05d5\u05d3" }, diff --git a/homeassistant/components/nest/translations/hr.json b/homeassistant/components/nest/translations/hr.json index d2418b00726..d12df4db83b 100644 --- a/homeassistant/components/nest/translations/hr.json +++ b/homeassistant/components/nest/translations/hr.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_code": "Neispravan kod" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/nest/translations/hu.json b/homeassistant/components/nest/translations/hu.json index 8ed8bcc843c..8bbf6ebc955 100644 --- a/homeassistant/components/nest/translations/hu.json +++ b/homeassistant/components/nest/translations/hu.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_setup": "Csak egy Nest-fi\u00f3kot konfigur\u00e1lhat.", "authorize_url_fail": "Ismeretlen hiba t\u00f6rt\u00e9nt a hiteles\u00edt\u00e9si link gener\u00e1l\u00e1sa sor\u00e1n.", "authorize_url_timeout": "Id\u0151t\u00fall\u00e9p\u00e9s az \u00e9rv\u00e9nyes\u00edt\u00e9si url gener\u00e1l\u00e1sa sor\u00e1n." }, "error": { "internal_error": "Bels\u0151 hiba t\u00f6rt\u00e9nt a k\u00f3d valid\u00e1l\u00e1s\u00e1n\u00e1l", - "invalid_code": "\u00c9rv\u00e9nytelen k\u00f3d", "timeout": "Id\u0151t\u00fall\u00e9p\u00e9s a k\u00f3d \u00e9rv\u00e9nyes\u00edt\u00e9se sor\u00e1n.", "unknown": "Ismeretlen hiba t\u00f6rt\u00e9nt a k\u00f3d \u00e9rv\u00e9nyes\u00edt\u00e9se sor\u00e1n" }, diff --git a/homeassistant/components/nest/translations/id.json b/homeassistant/components/nest/translations/id.json index 3a805baec05..4fc229c0d53 100644 --- a/homeassistant/components/nest/translations/id.json +++ b/homeassistant/components/nest/translations/id.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Anda hanya dapat mengonfigurasi satu akun Nest.", "authorize_url_fail": "Kesalahan tidak dikenal terjadi ketika menghasilkan URL otorisasi.", - "authorize_url_timeout": "Waktu tunggu menghasilkan otorisasi url telah habis.", - "no_flows": "Anda harus mengonfigurasi Nest sebelum dapat mengautentikasi dengan Nest. [Silakan baca instruksi] (https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "Waktu tunggu menghasilkan otorisasi url telah habis." }, "error": { "internal_error": "Kesalahan Internal memvalidasi kode", - "invalid_code": "Kode salah", "timeout": "Waktu tunggu memvalidasi kode telah habis.", "unknown": "Error tidak diketahui saat memvalidasi kode" }, diff --git a/homeassistant/components/nest/translations/it.json b/homeassistant/components/nest/translations/it.json index 516b055a355..d504b30c4bb 100644 --- a/homeassistant/components/nest/translations/it.json +++ b/homeassistant/components/nest/translations/it.json @@ -1,16 +1,17 @@ { "config": { "abort": { - "already_setup": "\u00c8 possibile configurare un solo account Nest.", "authorize_url_fail": "Errore sconosciuto nel generare l'url di autorizzazione", "authorize_url_timeout": "Tempo scaduto nel generare l'URL di autorizzazione.", "missing_configuration": "Il componente non \u00e8 configurato. Si prega di seguire la documentazione.", - "no_flows": "Devi configurare Nest prima di poter eseguire l'autenticazione. [Si prega di leggere le istruzioni](https://www.home-assistant.io/components/nest/).", + "no_url_available": "Nessun URL disponibile. Per informazioni su questo errore, [controlla la sezione della guida]({docs_url})", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, + "create_entry": { + "default": "Autenticazione riuscita" + }, "error": { "internal_error": "Errore interno nella convalida del codice", - "invalid_code": "Codice non valido", "invalid_pin": "Codice PIN non valido", "timeout": "Tempo scaduto per l'inserimento del codice di convalida", "unknown": "Errore imprevisto" @@ -29,6 +30,9 @@ }, "description": "Per collegare l'account Nido, [autorizzare l'account]({url}).\n\nDopo l'autorizzazione, copia-incolla il codice PIN fornito di seguito.", "title": "Collega un account Nest" + }, + "pick_implementation": { + "title": "Scegli il metodo di autenticazione" } } } diff --git a/homeassistant/components/nest/translations/ko.json b/homeassistant/components/nest/translations/ko.json index ee56fc4f11e..798f191e34a 100644 --- a/homeassistant/components/nest/translations/ko.json +++ b/homeassistant/components/nest/translations/ko.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "\ud558\ub098\uc758 Nest \uacc4\uc815\ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.", "authorize_url_fail": "\uc778\uc99d url \uc0dd\uc131\uc5d0 \uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.", - "authorize_url_timeout": "\uc778\uc99d url \uc0dd\uc131 \uc2dc\uac04\uc774 \ucd08\uacfc\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "no_flows": "Nest \ub97c \uc778\uc99d\ud558\ub824\uba74 \uba3c\uc800 Nest \ub97c \uad6c\uc131\ud574\uc57c \ud569\ub2c8\ub2e4. [\uc548\ub0b4](https://www.home-assistant.io/components/nest/) \ub97c \uc77d\uc5b4\ubcf4\uc138\uc694." + "authorize_url_timeout": "\uc778\uc99d url \uc0dd\uc131 \uc2dc\uac04\uc774 \ucd08\uacfc\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "error": { "internal_error": "\ucf54\ub4dc \uc720\ud6a8\uc131 \uac80\uc0ac\uc5d0 \ub0b4\ubd80 \uc624\ub958 \ubc1c\uc0dd", - "invalid_code": "\uc798\ubabb\ub41c \ucf54\ub4dc", "timeout": "\ucf54\ub4dc \uc720\ud6a8\uc131 \uac80\uc0ac \uc2dc\uac04 \ucd08\uacfc", "unknown": "\ucf54\ub4dc \uc720\ud6a8\uc131 \uac80\uc0ac\uc5d0 \uc54c \uc218 \uc5c6\ub294 \uc624\ub958 \ubc1c\uc0dd" }, diff --git a/homeassistant/components/nest/translations/lb.json b/homeassistant/components/nest/translations/lb.json index 526c258bb26..4c28b3becc6 100644 --- a/homeassistant/components/nest/translations/lb.json +++ b/homeassistant/components/nest/translations/lb.json @@ -1,31 +1,34 @@ { "config": { "abort": { - "already_setup": "Dir k\u00ebnnt n\u00ebmmen een eenzegen Nest Kont konfigur\u00e9ieren.", "authorize_url_fail": "Onbekannte Feeler beim gener\u00e9ieren vun der Autorisatiouns URL.", "authorize_url_timeout": "Z\u00e4it Iwwerschreidung beim gener\u00e9ieren vun der Autorisatiouns URL.", - "no_flows": "Dir musst Nest konfigur\u00e9ieren, ier Dir d\u00ebs Authentifiz\u00e9ierung k\u00ebnnt benotzen.[Liest w.e.g. d'Instruktioune](https://www.home-assistant.io/components/nest/)." + "missing_configuration": "Komponent net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { "internal_error": "Interne Feeler beim valid\u00e9ieren vum Code", - "invalid_code": "Ong\u00ebltege Code", + "invalid_pin": "Ong\u00eblte PIN Code", "timeout": "Z\u00e4it Iwwerschreidung beim valid\u00e9ieren vum Code", - "unknown": "Onbekannte Feeler beim valid\u00e9ieren vum Code" + "unknown": "Onerwaarte Feeler" }, "step": { "init": { "data": { "flow_impl": "Ubidder" }, - "description": "Wielt den Authentifikatioun Ubidder deen sech mat Nest verbanne soll.", + "description": "Wiel Authentifikatioun's Method aus", "title": "Authentifikatioun Ubidder" }, "link": { "data": { - "code": "Pin code" + "code": "PIN code" }, "description": "Fir den Nest Kont ze verbannen, [autoris\u00e9iert \u00e4ren Kont]({url}).\nKop\u00e9iert no der Autorisatioun den Pin hei \u00ebnnendr\u00ebnner", "title": "Nest Kont verbannen" + }, + "pick_implementation": { + "title": "Authentifikatioun's Method auswielen" } } } diff --git a/homeassistant/components/nest/translations/nl.json b/homeassistant/components/nest/translations/nl.json index 85775d06e21..bd72b659ae7 100644 --- a/homeassistant/components/nest/translations/nl.json +++ b/homeassistant/components/nest/translations/nl.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Je kunt slechts \u00e9\u00e9n Nest-account configureren.", "authorize_url_fail": "Onbekende fout bij het genereren van een autoriseer-URL.", - "authorize_url_timeout": "Toestemming voor het genereren van autoriseer-url.", - "no_flows": "U moet Nest configureren voordat u zich ermee kunt authenticeren. [Gelieve de instructies te lezen](https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "Toestemming voor het genereren van autoriseer-url." }, "error": { "internal_error": "Interne foutvalidatiecode", - "invalid_code": "Ongeldige code", "timeout": "Time-out validatie van code", "unknown": "Onbekende foutvalidatiecode" }, diff --git a/homeassistant/components/nest/translations/nn.json b/homeassistant/components/nest/translations/nn.json index a70720a3327..d9251d1e327 100644 --- a/homeassistant/components/nest/translations/nn.json +++ b/homeassistant/components/nest/translations/nn.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Du kan berre konfiguere \u00e9in Nest-brukar.", "authorize_url_fail": "Ukjent feil ved generering av autentiserings-URL", - "authorize_url_timeout": "Tida gjekk ut for generert autentikasjons-URL", - "no_flows": "Du m\u00e5 konfiguere Nest f\u00f8r du kan autentisere den. (Les instruksjonane) (https://www.home-assistant.io/components/nest/)" + "authorize_url_timeout": "Tida gjekk ut for generert autentikasjons-URL" }, "error": { "internal_error": "Intern feil ved validering av kode", - "invalid_code": "Ugyldig kode", "timeout": "Tida gjekk ut for validering av kode", "unknown": "Det hende ein ukjent feil ved validering av kode." }, diff --git a/homeassistant/components/nest/translations/no.json b/homeassistant/components/nest/translations/no.json index 67e7f2ca9d3..4708ddc5350 100644 --- a/homeassistant/components/nest/translations/no.json +++ b/homeassistant/components/nest/translations/no.json @@ -1,16 +1,17 @@ { "config": { "abort": { - "already_setup": "Du kan bare konfigurere en Nest konto.", "authorize_url_fail": "Ukjent feil ved oppretting av godkjenningsadresse.", "authorize_url_timeout": "Tidsavbrudd som genererer autorer URL-adresse.", "missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen.", - "no_flows": "Du m\u00e5 konfigurere Nest f\u00f8r du kan godkjenne den. [Vennligst les instruksjonene](https://www.home-assistant.io/components/nest/).", + "no_url_available": "Ingen URL tilgjengelig. For informasjon om denne feilen, [sjekk hjelpseksjonen]({docs_url})", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, + "create_entry": { + "default": "Vellykket godkjenning" + }, "error": { "internal_error": "Intern feil ved validering av kode", - "invalid_code": "Ugyldig kode", "invalid_pin": "Ugyldig PIN-kode", "timeout": "Tidsavbrudd ved validering av kode", "unknown": "Uventet feil" @@ -29,6 +30,9 @@ }, "description": "For \u00e5 koble din Nest-konto, [bekreft kontoen din]({url}). \n\nEtter bekreftelse, kopier og lim inn den oppgitte PIN koden nedenfor.", "title": "Koble til Nest konto" + }, + "pick_implementation": { + "title": "Velg godkjenningsmetode" } } } diff --git a/homeassistant/components/nest/translations/pl.json b/homeassistant/components/nest/translations/pl.json index 3b9f87a3f72..77c86ddfb07 100644 --- a/homeassistant/components/nest/translations/pl.json +++ b/homeassistant/components/nest/translations/pl.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno konto Nest", "authorize_url_fail": "Nieznany b\u0142\u0105d podczas generowania url autoryzacji", "authorize_url_timeout": "Przekroczono limit czasu generowania URL autoryzacji", "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105.", - "no_flows": "Musisz skonfigurowa\u0107 Nest, aby m\u00f3c si\u0119 z nim uwierzytelni\u0107. Zapoznaj si\u0119 z [instrukcj\u0105](https://www.home-assistant.io/components/nest/).", + "no_url_available": "Brak dost\u0119pnego adresu URL. Aby uzyska\u0107 informacje na temat tego b\u0142\u0119du, [sprawd\u017a sekcj\u0119 pomocy] ({docs_url})", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "create_entry": { @@ -13,7 +12,6 @@ }, "error": { "internal_error": "Wewn\u0119trzny b\u0142\u0105d sprawdzania poprawno\u015bci kodu", - "invalid_code": "Nieprawid\u0142owy kod", "invalid_pin": "Nieprawid\u0142owy kod PIN", "timeout": "Przekroczono limit czasu sprawdzania poprawno\u015bci kodu", "unknown": "Nieoczekiwany b\u0142\u0105d" diff --git a/homeassistant/components/nest/translations/pt-BR.json b/homeassistant/components/nest/translations/pt-BR.json index 2594540c6ea..ae2d88eeeaa 100644 --- a/homeassistant/components/nest/translations/pt-BR.json +++ b/homeassistant/components/nest/translations/pt-BR.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Voc\u00ea pode configurar somente uma conta do Nest", "authorize_url_fail": "Erro desconhecido ao gerar um URL de autoriza\u00e7\u00e3o.", - "authorize_url_timeout": "Excedido tempo limite de url de autoriza\u00e7\u00e3o", - "no_flows": "Voc\u00ea precisa configurar o Nest antes de poder autenticar com ele. [Por favor leio as instru\u00e7\u00f5es](https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "Excedido tempo limite de url de autoriza\u00e7\u00e3o" }, "error": { "internal_error": "Erro interno ao validar o c\u00f3digo", - "invalid_code": "C\u00f3digo inv\u00e1lido", "timeout": "Excedido tempo limite para validar c\u00f3digo", "unknown": "Erro desconhecido ao validar o c\u00f3digo" }, diff --git a/homeassistant/components/nest/translations/pt.json b/homeassistant/components/nest/translations/pt.json index f0e074aca2f..79c4276c23b 100644 --- a/homeassistant/components/nest/translations/pt.json +++ b/homeassistant/components/nest/translations/pt.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "S\u00f3 pode configurar uma \u00fanica conta Nest.", "authorize_url_fail": "Erro desconhecido ao gerar um URL de autoriza\u00e7\u00e3o.", - "authorize_url_timeout": "Limite temporal ultrapassado ao gerar um URL de autoriza\u00e7\u00e3o.", - "no_flows": "\u00c9 necess\u00e1rio configurar o Nest antes de poder autenticar com ele. [Por favor, leia as instru\u00e7\u00f5es] (https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "Limite temporal ultrapassado ao gerar um URL de autoriza\u00e7\u00e3o." }, "error": { "internal_error": "Erro interno ao validar o c\u00f3digo", - "invalid_code": "C\u00f3digo inv\u00e1lido", "timeout": "Limite temporal ultrapassado ao validar c\u00f3digo", "unknown": "Erro desconhecido ao validar o c\u00f3digo" }, diff --git a/homeassistant/components/nest/translations/ru.json b/homeassistant/components/nest/translations/ru.json index 82c50bab5ee..be8905156bd 100644 --- a/homeassistant/components/nest/translations/ru.json +++ b/homeassistant/components/nest/translations/ru.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "authorize_url_fail": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.", "authorize_url_timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.", "missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438.", - "no_flows": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 Nest \u043f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/nest/).", + "no_url_available": "URL-\u0430\u0434\u0440\u0435\u0441 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d. \u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439]({docs_url}) \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u044d\u0442\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0435.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "create_entry": { @@ -13,7 +12,6 @@ }, "error": { "internal_error": "\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u0434\u0430.", - "invalid_code": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043e\u0434.", "invalid_pin": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 PIN-\u043a\u043e\u0434.", "timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u0434\u0430.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." diff --git a/homeassistant/components/nest/translations/sl.json b/homeassistant/components/nest/translations/sl.json index 46b714b7299..4af5404c63b 100644 --- a/homeassistant/components/nest/translations/sl.json +++ b/homeassistant/components/nest/translations/sl.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Nastavite lahko samo en ra\u010dun Nest.", "authorize_url_fail": "Neznana napaka pri generiranju potrditvenega URL-ja.", - "authorize_url_timeout": "\u010casovna omejitev za generiranje potrditvenega URL-ja je potekla.", - "no_flows": "Preden lahko preverite pristnost, morate konfigurirati Nest. [Preberite navodila](https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "\u010casovna omejitev za generiranje potrditvenega URL-ja je potekla." }, "error": { "internal_error": "Notranja napaka pri preverjanju kode", - "invalid_code": "Neveljavna koda", "timeout": "\u010casovna omejitev je potekla pri preverjanju kode", "unknown": "Neznana napaka pri preverjanju kode" }, diff --git a/homeassistant/components/nest/translations/sv.json b/homeassistant/components/nest/translations/sv.json index f5f165e37e9..0abe4d75fac 100644 --- a/homeassistant/components/nest/translations/sv.json +++ b/homeassistant/components/nest/translations/sv.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "Du kan endast konfigurera ett Nest-konto.", "authorize_url_fail": "Ok\u00e4nt fel vid generering av autentisieringsadress.", - "authorize_url_timeout": "Timeout vid generering av en autentisieringsadress.", - "no_flows": "Du m\u00e5ste konfigurera Nest innan du kan autentisera med det. [V\u00e4nligen l\u00e4s instruktionerna] (https://www.home-assistant.io/components/nest/)." + "authorize_url_timeout": "Timeout vid generering av en autentisieringsadress." }, "error": { "internal_error": "Internt fel vid validering av kod", - "invalid_code": "Ogiltig kod", "timeout": "Timeout vid valididering av kod", "unknown": "Ok\u00e4nt fel vid validering av kod" }, diff --git a/homeassistant/components/nest/translations/th.json b/homeassistant/components/nest/translations/th.json index 6a434860c08..797aac82405 100644 --- a/homeassistant/components/nest/translations/th.json +++ b/homeassistant/components/nest/translations/th.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_code": "\u0e23\u0e2b\u0e31\u0e2a\u0e44\u0e21\u0e48\u0e16\u0e39\u0e01\u0e15\u0e49\u0e2d\u0e07" - }, "step": { "link": { "data": { diff --git a/homeassistant/components/nest/translations/vi.json b/homeassistant/components/nest/translations/vi.json index 4eb8677762a..d225f64e63f 100644 --- a/homeassistant/components/nest/translations/vi.json +++ b/homeassistant/components/nest/translations/vi.json @@ -2,7 +2,6 @@ "config": { "error": { "internal_error": "M\u00e3 x\u00e1c th\u1ef1c l\u1ed7i n\u1ed9i b\u1ed9", - "invalid_code": "M\u00e3 kh\u00f4ng h\u1ee3p l\u1ec7", "timeout": "M\u00e3 x\u00e1c th\u1ef1c h\u1ebft th\u1eddi gian ch\u1edd", "unknown": "M\u00e3 x\u00e1c th\u1ef1c l\u1ed7i kh\u00f4ng x\u00e1c \u0111\u1ecbnh" }, diff --git a/homeassistant/components/nest/translations/zh-Hans.json b/homeassistant/components/nest/translations/zh-Hans.json index 55d610219a6..38be428a0c7 100644 --- a/homeassistant/components/nest/translations/zh-Hans.json +++ b/homeassistant/components/nest/translations/zh-Hans.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_setup": "\u60a8\u53ea\u80fd\u914d\u7f6e\u4e00\u4e2a Nest \u5e10\u6237\u3002", "authorize_url_fail": "\u751f\u6210\u6388\u6743\u7f51\u5740\u65f6\u53d1\u751f\u672a\u77e5\u9519\u8bef\u3002", - "authorize_url_timeout": "\u751f\u6210\u6388\u6743\u7f51\u5740\u8d85\u65f6\u3002", - "no_flows": "\u60a8\u9700\u8981\u5148\u914d\u7f6e Nest\uff0c\u7136\u540e\u624d\u80fd\u5bf9\u5176\u8fdb\u884c\u6388\u6743\u3002 [\u8bf7\u9605\u8bfb\u8bf4\u660e](https://www.home-assistant.io/components/nest/)\u3002" + "authorize_url_timeout": "\u751f\u6210\u6388\u6743\u7f51\u5740\u8d85\u65f6\u3002" }, "error": { "internal_error": "\u9a8c\u8bc1\u4ee3\u7801\u65f6\u53d1\u751f\u5185\u90e8\u9519\u8bef", - "invalid_code": "\u9a8c\u8bc1\u7801\u65e0\u6548", "invalid_pin": "PIN\u7801\u65e0\u6548", "timeout": "\u9a8c\u8bc1\u7801\u8d85\u65f6", "unknown": "\u9a8c\u8bc1\u7801\u672a\u77e5\u9519\u8bef" diff --git a/homeassistant/components/nest/translations/zh-Hant.json b/homeassistant/components/nest/translations/zh-Hant.json index 87f8b62427a..d584381bdcc 100644 --- a/homeassistant/components/nest/translations/zh-Hant.json +++ b/homeassistant/components/nest/translations/zh-Hant.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44 Nest \u5e33\u865f\u3002", "authorize_url_fail": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u767c\u751f\u672a\u77e5\u932f\u8aa4", "authorize_url_timeout": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u903e\u6642\u3002", "missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002", - "no_flows": "\u5fc5\u9808\u5148\u8a2d\u5b9a Nest \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15](https://www.home-assistant.io/components/nest/)\u3002", + "no_url_available": "\u6c92\u6709\u53ef\u7528\u7684\u7db2\u5740\u3002\u95dc\u65bc\u6b64\u932f\u8aa4\u66f4\u8a73\u7d30\u8a0a\u606f\uff0c[\u9ede\u9078\u5354\u52a9\u7ae0\u7bc0]({docs_url})", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "create_entry": { @@ -13,7 +12,6 @@ }, "error": { "internal_error": "\u8a8d\u8b49\u78bc\u5167\u90e8\u932f\u8aa4", - "invalid_code": "\u8a8d\u8b49\u78bc\u7121\u6548", "invalid_pin": "\u7121\u6548\u7684 PIN \u78bc", "timeout": "\u8a8d\u8b49\u78bc\u903e\u6642", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" diff --git a/homeassistant/components/netatmo/sensor.py b/homeassistant/components/netatmo/sensor.py index 2e810ba2271..f8484444818 100644 --- a/homeassistant/components/netatmo/sensor.py +++ b/homeassistant/components/netatmo/sensor.py @@ -15,6 +15,7 @@ from homeassistant.const import ( LENGTH_MILLIMETERS, PERCENTAGE, PRESSURE_MBAR, + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, SPEED_KILOMETERS_PER_HOUR, TEMP_CELSIUS, ) @@ -91,9 +92,21 @@ SENSOR_TYPES = { ], "reachable": ["Reachability", None, "mdi:signal", None, False], "rf_status": ["Radio", None, "mdi:signal", None, False], - "rf_status_lvl": ["Radio Level", "", None, DEVICE_CLASS_SIGNAL_STRENGTH, False], + "rf_status_lvl": [ + "Radio Level", + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + None, + DEVICE_CLASS_SIGNAL_STRENGTH, + False, + ], "wifi_status": ["Wifi", None, "mdi:wifi", None, False], - "wifi_status_lvl": ["Wifi Level", "dBm", None, DEVICE_CLASS_SIGNAL_STRENGTH, False], + "wifi_status_lvl": [ + "Wifi Level", + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + None, + DEVICE_CLASS_SIGNAL_STRENGTH, + False, + ], "health_idx": ["Health", None, "mdi:cloud", None, True], } diff --git a/homeassistant/components/netatmo/translations/cs.json b/homeassistant/components/netatmo/translations/cs.json index 74a31f4199d..7857e345165 100644 --- a/homeassistant/components/netatmo/translations/cs.json +++ b/homeassistant/components/netatmo/translations/cs.json @@ -26,13 +26,17 @@ "lon_sw": "Zem\u011bpisn\u00e1 d\u00e9lka Jihoz\u00e1padn\u00ed roh", "mode": "V\u00fdpo\u010det", "show_on_map": "Zobrazit na map\u011b" - } + }, + "description": "Nastavte ve\u0159ejn\u00fd senzor po\u010das\u00ed pro oblast.", + "title": "Ve\u0159ejn\u00fd senzor po\u010das\u00ed Netatmo" }, "public_weather_areas": { "data": { "new_area": "Jm\u00e9no oblasti", "weather_areas": "Oblasti po\u010das\u00ed" - } + }, + "description": "Nastavte ve\u0159ejn\u00e9 senzory po\u010das\u00ed.", + "title": "Ve\u0159ejn\u00fd senzor po\u010das\u00ed Netatmo" } } } diff --git a/homeassistant/components/netatmo/translations/et.json b/homeassistant/components/netatmo/translations/et.json index 7e3a8ad5a8b..99e062b3842 100644 --- a/homeassistant/components/netatmo/translations/et.json +++ b/homeassistant/components/netatmo/translations/et.json @@ -1,9 +1,14 @@ { "config": { "abort": { + "authorize_url_timeout": "Kinnitus-URLi loomise ajal\u00f5pp.", + "missing_configuration": "Komponent pole seadistatud. Palun loe dokumentatsiooni.", "no_url_available": "URL pole saadaval. Rohkem teavet [check the help section]({docs_url})", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, + "create_entry": { + "default": "Tuvastamine \u00f5nnestus" + }, "step": { "pick_implementation": { "title": "Vali tuvastusmeetod" diff --git a/homeassistant/components/netatmo/translations/nl.json b/homeassistant/components/netatmo/translations/nl.json index 67919938ee2..590082b826a 100644 --- a/homeassistant/components/netatmo/translations/nl.json +++ b/homeassistant/components/netatmo/translations/nl.json @@ -1,7 +1,16 @@ { "config": { + "abort": { + "authorize_url_timeout": "Time-out genereren autorisatie-URL.", + "missing_configuration": "Het component is niet geconfigureerd. Volg de documentatie." + }, "create_entry": { "default": "Succesvol geauthenticeerd met Netatmo." + }, + "step": { + "pick_implementation": { + "title": "Kies de verificatiemethode" + } } }, "options": { diff --git a/homeassistant/components/netio/switch.py b/homeassistant/components/netio/switch.py index 08a5b7df862..3c1482844ad 100644 --- a/homeassistant/components/netio/switch.py +++ b/homeassistant/components/netio/switch.py @@ -79,7 +79,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): def dispose(event): """Close connections to Netio Devices.""" - for _, value in DEVICES.items(): + for value in DEVICES.values(): value.netio.stop() diff --git a/homeassistant/components/neurio_energy/sensor.py b/homeassistant/components/neurio_energy/sensor.py index 894bfae6180..264d7508347 100644 --- a/homeassistant/components/neurio_energy/sensor.py +++ b/homeassistant/components/neurio_energy/sensor.py @@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_API_KEY): cv.string, vol.Required(CONF_API_SECRET): cv.string, - vol.Optional(CONF_SENSOR_ID): cv.string, + vol.Required(CONF_SENSOR_ID): cv.string, } ) @@ -82,14 +82,6 @@ class NeurioData: neurio_tp = neurio.TokenProvider(key=api_key, secret=api_secret) self.neurio_client = neurio.Client(token_provider=neurio_tp) - if not self.sensor_id: - user_info = self.neurio_client.get_user_information() - _LOGGER.warning( - "Sensor ID auto-detected: %s", - user_info["locations"][0]["sensors"][0]["sensorId"], - ) - self.sensor_id = user_info["locations"][0]["sensors"][0]["sensorId"] - @property def daily_usage(self): """Return latest daily usage value.""" diff --git a/homeassistant/components/nexia/translations/et.json b/homeassistant/components/nexia/translations/et.json index 207eae740f6..ac8c354c3b3 100644 --- a/homeassistant/components/nexia/translations/et.json +++ b/homeassistant/components/nexia/translations/et.json @@ -13,7 +13,8 @@ "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "\u00dchendu mynexia.com" } } } diff --git a/homeassistant/components/nexia/translations/lb.json b/homeassistant/components/nexia/translations/lb.json index 3179afd93a2..fa9b186ccbf 100644 --- a/homeassistant/components/nexia/translations/lb.json +++ b/homeassistant/components/nexia/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "Den Nexia Home ass scho konfigur\u00e9iert" + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, diff --git a/homeassistant/components/nightscout/translations/et.json b/homeassistant/components/nightscout/translations/et.json index f072bf6f84c..1e77907f2af 100644 --- a/homeassistant/components/nightscout/translations/et.json +++ b/homeassistant/components/nightscout/translations/et.json @@ -12,7 +12,8 @@ "step": { "user": { "data": { - "api_key": "API v\u00f5ti" + "api_key": "API v\u00f5ti", + "url": "" }, "description": "- URL: NightScout eksemplari aadress. St: https://myhomeassistant.duckdns.org:5423\n - API v\u00f5ti (valikuline): kasutage ainult siis kui teie eksemplar on kaitstud (auth_default_roles! = readable).", "title": "Sisesta oma Nightscouti serveri teave." diff --git a/homeassistant/components/nightscout/translations/fr.json b/homeassistant/components/nightscout/translations/fr.json index 1bcd530d29b..bec90374906 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/nightscout/translations/nl.json b/homeassistant/components/nightscout/translations/nl.json index cfa9719c677..208299fd442 100644 --- a/homeassistant/components/nightscout/translations/nl.json +++ b/homeassistant/components/nightscout/translations/nl.json @@ -3,9 +3,14 @@ "abort": { "already_configured": "Apparaat is al geconfigureerd" }, + "error": { + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "api_key": "API-sleutel", "url": "URL" } } diff --git a/homeassistant/components/notion/__init__.py b/homeassistant/components/notion/__init__.py index 1e7d12df38c..296eb34934b 100644 --- a/homeassistant/components/notion/__init__.py +++ b/homeassistant/components/notion/__init__.py @@ -5,9 +5,8 @@ import logging from aionotion import async_get_client from aionotion.errors import InvalidCredentialsError, NotionError -import voluptuous as vol -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_ATTRIBUTION, CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady @@ -34,39 +33,12 @@ ATTR_SYSTEM_NAME = "system_name" DEFAULT_ATTRIBUTION = "Data provided by Notion" DEFAULT_SCAN_INTERVAL = timedelta(minutes=1) -CONFIG_SCHEMA = vol.Schema( - { - DOMAIN: vol.Schema( - { - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - } - ) - }, - extra=vol.ALLOW_EXTRA, -) +CONFIG_SCHEMA = cv.deprecated(DOMAIN, invalidation_version="0.119") async def async_setup(hass: HomeAssistant, config: dict) -> bool: """Set up the Notion component.""" hass.data[DOMAIN] = {DATA_COORDINATOR: {}} - - if DOMAIN not in config: - return True - - conf = config[DOMAIN] - - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={ - CONF_USERNAME: conf[CONF_USERNAME], - CONF_PASSWORD: conf[CONF_PASSWORD], - }, - ) - ) - return True @@ -274,15 +246,14 @@ class NotionEntity(CoordinatorEntity): """Update the entity from the latest data.""" raise NotImplementedError - async def async_added_to_hass(self) -> None: - """Register callbacks.""" - - @callback - def update(): - """Update the state.""" - self._async_update_from_latest_data() - self.async_write_ha_state() - - self.async_on_remove(self.coordinator.async_add_listener(update)) - + @callback + def _handle_coordinator_update(self): + """Respond to a DataUpdateCoordinator update.""" + self.hass.async_create_task(self._async_update_bridge_id()) + self._async_update_from_latest_data() + self.async_write_ha_state() + + async def async_added_to_hass(self): + """Handle entity which will be added.""" + await super().async_added_to_hass() self._async_update_from_latest_data() diff --git a/homeassistant/components/notion/binary_sensor.py b/homeassistant/components/notion/binary_sensor.py index 1597957c1f5..b8fd96fabc5 100644 --- a/homeassistant/components/notion/binary_sensor.py +++ b/homeassistant/components/notion/binary_sensor.py @@ -77,7 +77,12 @@ class NotionBinarySensor(NotionEntity, BinarySensorEntity): @callback def _async_update_from_latest_data(self) -> None: """Fetch new state data for the sensor.""" - self._state = self.coordinator.data["tasks"][self._task_id]["status"]["value"] + task = self.coordinator.data["tasks"][self._task_id] + + if "value" in task["status"]: + self._state = task["status"]["value"] + elif task["task_type"] == SENSOR_BATTERY: + self._state = task["status"]["data"]["to_state"] @property def is_on(self) -> bool: @@ -85,7 +90,7 @@ class NotionBinarySensor(NotionEntity, BinarySensorEntity): task = self.coordinator.data["tasks"][self._task_id] if task["task_type"] == SENSOR_BATTERY: - return self._state != "battery_good" + return self._state == "critical" if task["task_type"] in ( SENSOR_DOOR, SENSOR_GARAGE_DOOR, diff --git a/homeassistant/components/notion/config_flow.py b/homeassistant/components/notion/config_flow.py index bcbd22bccc6..86c51e3c13c 100644 --- a/homeassistant/components/notion/config_flow.py +++ b/homeassistant/components/notion/config_flow.py @@ -28,10 +28,6 @@ class NotionFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): step_id="user", data_schema=self.data_schema, errors=errors or {} ) - 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/homeassistant/components/notion/translations/bg.json b/homeassistant/components/notion/translations/bg.json index dcb76f65acd..f320ae6c5a3 100644 --- a/homeassistant/components/notion/translations/bg.json +++ b/homeassistant/components/notion/translations/bg.json @@ -1,7 +1,6 @@ { "config": { "error": { - "invalid_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435 \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u0430", "no_devices": "\u041d\u0435 \u0441\u0430 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u0430" }, "step": { diff --git a/homeassistant/components/notion/translations/ca.json b/homeassistant/components/notion/translations/ca.json index 7abc95e5990..5d89413d36f 100644 --- a/homeassistant/components/notion/translations/ca.json +++ b/homeassistant/components/notion/translations/ca.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Nom d'usuari o contrasenya incorrectes", "no_devices": "No s'han trobat dispositius al compte" }, "step": { diff --git a/homeassistant/components/notion/translations/cs.json b/homeassistant/components/notion/translations/cs.json index 7440c390a62..7d5eebeb564 100644 --- a/homeassistant/components/notion/translations/cs.json +++ b/homeassistant/components/notion/translations/cs.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Neplatn\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no nebo heslo", "no_devices": "V \u00fa\u010dtu nebyla nalezena \u017e\u00e1dn\u00e1 za\u0159\u00edzen\u00ed" }, "step": { diff --git a/homeassistant/components/notion/translations/da.json b/homeassistant/components/notion/translations/da.json index 8d0e0d37c4b..e8a1d35417a 100644 --- a/homeassistant/components/notion/translations/da.json +++ b/homeassistant/components/notion/translations/da.json @@ -4,7 +4,6 @@ "already_configured": "Dette brugernavn er allerede i brug." }, "error": { - "invalid_credentials": "Ugyldigt brugernavn eller adgangskode", "no_devices": "Ingen enheder fundet i konto" }, "step": { diff --git a/homeassistant/components/notion/translations/de.json b/homeassistant/components/notion/translations/de.json index c9a3e9bd5a4..f322826c45b 100644 --- a/homeassistant/components/notion/translations/de.json +++ b/homeassistant/components/notion/translations/de.json @@ -4,7 +4,6 @@ "already_configured": "Dieser Benutzername wird bereits benutzt." }, "error": { - "invalid_credentials": "Ung\u00fcltiger Benutzername oder Passwort", "no_devices": "Keine Ger\u00e4te im Konto gefunden" }, "step": { diff --git a/homeassistant/components/notion/translations/en.json b/homeassistant/components/notion/translations/en.json index b092cc000d9..a31befc0e95 100644 --- a/homeassistant/components/notion/translations/en.json +++ b/homeassistant/components/notion/translations/en.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid username or password", "no_devices": "No devices found in account" }, "step": { diff --git a/homeassistant/components/notion/translations/es-419.json b/homeassistant/components/notion/translations/es-419.json index a34d0356261..489df80f736 100644 --- a/homeassistant/components/notion/translations/es-419.json +++ b/homeassistant/components/notion/translations/es-419.json @@ -4,7 +4,6 @@ "already_configured": "Este nombre de usuario ya est\u00e1 en uso." }, "error": { - "invalid_credentials": "Nombre de usuario o contrase\u00f1a inv\u00e1lidos", "no_devices": "No se han encontrado dispositivos en la cuenta." }, "step": { diff --git a/homeassistant/components/notion/translations/es.json b/homeassistant/components/notion/translations/es.json index ef4aa8e22db..fd22f6b582f 100644 --- a/homeassistant/components/notion/translations/es.json +++ b/homeassistant/components/notion/translations/es.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_credentials": "Usuario o contrase\u00f1a no v\u00e1lido", "no_devices": "No se han encontrado dispositivos en la cuenta" }, "step": { diff --git a/homeassistant/components/notion/translations/et.json b/homeassistant/components/notion/translations/et.json index eec98de1f08..a377f1e69ab 100644 --- a/homeassistant/components/notion/translations/et.json +++ b/homeassistant/components/notion/translations/et.json @@ -5,14 +5,15 @@ }, "error": { "invalid_auth": "Tuvastamise viga", - "invalid_credentials": "Vale kasutajanimi v\u00f5i salas\u00f5na" + "no_devices": "Kontolt ei leitud \u00fchtegi seadet" }, "step": { "user": { "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "Sisesta oma teave" } } } diff --git a/homeassistant/components/notion/translations/fr.json b/homeassistant/components/notion/translations/fr.json index b5b6005ab9b..c8f82077a0a 100644 --- a/homeassistant/components/notion/translations/fr.json +++ b/homeassistant/components/notion/translations/fr.json @@ -4,7 +4,7 @@ "already_configured": "Ce nom d'utilisateur est d\u00e9j\u00e0 utilis\u00e9." }, "error": { - "invalid_credentials": "Nom d'utilisateur ou mot de passe invalide", + "invalid_auth": "Authentification invalide", "no_devices": "Aucun appareil trouv\u00e9 sur le compte" }, "step": { diff --git a/homeassistant/components/notion/translations/hr.json b/homeassistant/components/notion/translations/hr.json index 1c9cabbf74a..237845502dd 100644 --- a/homeassistant/components/notion/translations/hr.json +++ b/homeassistant/components/notion/translations/hr.json @@ -1,7 +1,6 @@ { "config": { "error": { - "invalid_credentials": "Neispravno korisni\u010dko ime ili lozinka", "no_devices": "Nisu prona\u0111eni ure\u0111aji na ra\u010dunu" }, "step": { diff --git a/homeassistant/components/notion/translations/hu.json b/homeassistant/components/notion/translations/hu.json index fdd239f03d2..6bf20925535 100644 --- a/homeassistant/components/notion/translations/hu.json +++ b/homeassistant/components/notion/translations/hu.json @@ -1,7 +1,6 @@ { "config": { "error": { - "invalid_credentials": "\u00c9rv\u00e9nytelen felhaszn\u00e1l\u00f3n\u00e9v vagy jelsz\u00f3", "no_devices": "Nem tal\u00e1lhat\u00f3 eszk\u00f6z a fi\u00f3kban" }, "step": { diff --git a/homeassistant/components/notion/translations/it.json b/homeassistant/components/notion/translations/it.json index 73298227868..3304d2b395a 100644 --- a/homeassistant/components/notion/translations/it.json +++ b/homeassistant/components/notion/translations/it.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "Autenticazione non valida", - "invalid_credentials": "Nome utente o password non validi", "no_devices": "Nessun dispositivo trovato nell'account" }, "step": { diff --git a/homeassistant/components/notion/translations/ko.json b/homeassistant/components/notion/translations/ko.json index 63f1b3e767c..323ea126445 100644 --- a/homeassistant/components/notion/translations/ko.json +++ b/homeassistant/components/notion/translations/ko.json @@ -4,7 +4,6 @@ "already_configured": "\uc774 \uc0ac\uc6a9\uc790 \uc774\ub984\uc740 \uc774\ubbf8 \uc0ac\uc6a9 \uc911\uc785\ub2c8\ub2e4." }, "error": { - "invalid_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ub610\ub294 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "no_devices": "\uacc4\uc815\uc5d0 \ub4f1\ub85d\ub41c \uae30\uae30\uac00 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4" }, "step": { diff --git a/homeassistant/components/notion/translations/lb.json b/homeassistant/components/notion/translations/lb.json index 7a86336eac0..a1bc1601e00 100644 --- a/homeassistant/components/notion/translations/lb.json +++ b/homeassistant/components/notion/translations/lb.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_configured": "D\u00ebse Benotzernumm g\u00ebtt scho benotzt." + "already_configured": "Kont ass scho konfigur\u00e9iert" }, "error": { "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_credentials": "Ong\u00ebltege Benotzernumm oder Passwuert", "no_devices": "Keng Apparater am Kont fonnt" }, "step": { diff --git a/homeassistant/components/notion/translations/nl.json b/homeassistant/components/notion/translations/nl.json index 473659c0eb2..86e059df4ff 100644 --- a/homeassistant/components/notion/translations/nl.json +++ b/homeassistant/components/notion/translations/nl.json @@ -4,7 +4,6 @@ "already_configured": "Deze gebruikersnaam is al in gebruik." }, "error": { - "invalid_credentials": "Ongeldige gebruikersnaam of wachtwoord", "no_devices": "Geen apparaten gevonden in account" }, "step": { diff --git a/homeassistant/components/notion/translations/no.json b/homeassistant/components/notion/translations/no.json index 82424f2738a..c1d8a1d17b5 100644 --- a/homeassistant/components/notion/translations/no.json +++ b/homeassistant/components/notion/translations/no.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig brukernavn eller passord", "no_devices": "Ingen enheter funnet i kontoen" }, "step": { diff --git a/homeassistant/components/notion/translations/pl.json b/homeassistant/components/notion/translations/pl.json index efe1154f49d..468a4c3d02e 100644 --- a/homeassistant/components/notion/translations/pl.json +++ b/homeassistant/components/notion/translations/pl.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owa nazwa u\u017cytkownika lub has\u0142o", "no_devices": "Nie znaleziono urz\u0105dze\u0144 na koncie" }, "step": { diff --git a/homeassistant/components/notion/translations/pt-BR.json b/homeassistant/components/notion/translations/pt-BR.json index db9ba8c1a47..084048a625a 100644 --- a/homeassistant/components/notion/translations/pt-BR.json +++ b/homeassistant/components/notion/translations/pt-BR.json @@ -1,7 +1,6 @@ { "config": { "error": { - "invalid_credentials": "Usu\u00e1rio ou senha inv\u00e1lidos", "no_devices": "Nenhum dispositivo encontrado na conta" }, "step": { diff --git a/homeassistant/components/notion/translations/pt.json b/homeassistant/components/notion/translations/pt.json index b09d2c55929..24825307e76 100644 --- a/homeassistant/components/notion/translations/pt.json +++ b/homeassistant/components/notion/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_credentials": "Nome de utilizador ou palavra passe incorretos" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/notion/translations/ru.json b/homeassistant/components/notion/translations/ru.json index 0ac19623c1a..678eff742b5 100644 --- a/homeassistant/components/notion/translations/ru.json +++ b/homeassistant/components/notion/translations/ru.json @@ -5,7 +5,6 @@ }, "error": { "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\u0439 \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c.", "no_devices": "\u041d\u0435\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u044c\u044e." }, "step": { diff --git a/homeassistant/components/notion/translations/sl.json b/homeassistant/components/notion/translations/sl.json index 7d76bcc9ed9..9e4a4c8d77e 100644 --- a/homeassistant/components/notion/translations/sl.json +++ b/homeassistant/components/notion/translations/sl.json @@ -4,7 +4,6 @@ "already_configured": "To uporabni\u0161ko ime je \u017ee v uporabi." }, "error": { - "invalid_credentials": "Neveljavno uporabni\u0161ko ime ali geslo", "no_devices": "V ra\u010dunu ni najdene nobene naprave" }, "step": { diff --git a/homeassistant/components/notion/translations/sv.json b/homeassistant/components/notion/translations/sv.json index 7e05095cf0e..0cbf4a937b9 100644 --- a/homeassistant/components/notion/translations/sv.json +++ b/homeassistant/components/notion/translations/sv.json @@ -4,7 +4,6 @@ "already_configured": "Det h\u00e4r anv\u00e4ndarnamnet anv\u00e4nds redan." }, "error": { - "invalid_credentials": "Felaktigt anv\u00e4ndarnamn eller l\u00f6senord", "no_devices": "Inga enheter hittades p\u00e5 kontot" }, "step": { diff --git a/homeassistant/components/notion/translations/zh-Hans.json b/homeassistant/components/notion/translations/zh-Hans.json index 736e9620ce5..2d670456235 100644 --- a/homeassistant/components/notion/translations/zh-Hans.json +++ b/homeassistant/components/notion/translations/zh-Hans.json @@ -1,7 +1,6 @@ { "config": { "error": { - "invalid_credentials": "\u65e0\u6548\u7684\u7528\u6237\u540d\u6216\u5bc6\u7801", "no_devices": "\u5e10\u6237\u4e2d\u627e\u4e0d\u5230\u8bbe\u5907" }, "step": { diff --git a/homeassistant/components/notion/translations/zh-Hant.json b/homeassistant/components/notion/translations/zh-Hant.json index 55b4d6a2e5d..12bc209815f 100644 --- a/homeassistant/components/notion/translations/zh-Hant.json +++ b/homeassistant/components/notion/translations/zh-Hant.json @@ -5,7 +5,6 @@ }, "error": { "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u4f7f\u7528\u8005\u540d\u7a31\u6216\u5bc6\u78bc\u7121\u6548", "no_devices": "\u5e33\u865f\u4e2d\u627e\u4e0d\u5230\u4efb\u4f55\u8a2d\u5099" }, "step": { diff --git a/homeassistant/components/nuheat/translations/et.json b/homeassistant/components/nuheat/translations/et.json index 207eae740f6..c302f5db244 100644 --- a/homeassistant/components/nuheat/translations/et.json +++ b/homeassistant/components/nuheat/translations/et.json @@ -6,14 +6,18 @@ "error": { "cannot_connect": "\u00dchenduse loomine nurjus. Proovi uuesti", "invalid_auth": "Tuvastamine nurjus", + "invalid_thermostat": "Termostaadi seerianumber on vale.", "unknown": "Ootamatu t\u00f5rge" }, "step": { "user": { "data": { "password": "Salas\u00f5na", + "serial_number": "Termostaadi seerianumber.", "username": "Kasutajanimi" - } + }, + "description": "Pead hankima oma termostaadi numbrilise seerianumbri v\u00f5i ID logides sisse aadressile https://MyNuHeat.com ja valides oma termostaadi (d).", + "title": "\u00dchendu NuHeat'iga" } } } diff --git a/homeassistant/components/nuheat/translations/lb.json b/homeassistant/components/nuheat/translations/lb.json index 0f8f81b4438..3c5b8dbe318 100644 --- a/homeassistant/components/nuheat/translations/lb.json +++ b/homeassistant/components/nuheat/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "Den Thermostat ass scho konfigur\u00e9iert" + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "invalid_thermostat": "Seriennummer vum Thermostat ass ong\u00eblteg", "unknown": "Onerwaarte Feeler" diff --git a/homeassistant/components/nut/translations/et.json b/homeassistant/components/nut/translations/et.json index 3e9ae01b36d..27745bfeeae 100644 --- a/homeassistant/components/nut/translations/et.json +++ b/homeassistant/components/nut/translations/et.json @@ -8,13 +8,38 @@ "unknown": "Tundmatu viga" }, "step": { + "resources": { + "data": { + "resources": "Ressursid" + }, + "title": "Vali j\u00e4lgitavad ressursid" + }, + "ups": { + "data": { + "alias": "", + "resources": "Ressursid" + }, + "title": "Vali j\u00e4lgitava UPS" + }, "user": { "data": { "host": "", "password": "Salas\u00f5na", "port": "", "username": "Kasutajanimi" - } + }, + "title": "Loo \u00fchendus NUT-serveriga" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "resources": "Ressursid", + "scan_interval": "P\u00e4ringute intervall (sekundites)" + }, + "description": "Vali anduri ressursid." } } } diff --git a/homeassistant/components/nut/translations/lb.json b/homeassistant/components/nut/translations/lb.json index fa7dc4da26d..da4840653c1 100644 --- a/homeassistant/components/nut/translations/lb.json +++ b/homeassistant/components/nut/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "unknown": "Onerwaarte Feeler" }, "step": { diff --git a/homeassistant/components/nws/translations/et.json b/homeassistant/components/nws/translations/et.json index 98882d81673..4ef73de7232 100644 --- a/homeassistant/components/nws/translations/et.json +++ b/homeassistant/components/nws/translations/et.json @@ -10,9 +10,12 @@ "step": { "user": { "data": { + "api_key": "API v\u00f5ti", "latitude": "Laiuskraad", - "longitude": "Pikkuskraad" + "longitude": "Pikkuskraad", + "station": "METAR jaamakood" }, + "description": "Kui METAR-i jaamakoodi pole m\u00e4\u00e4ratud, kasutatakse l\u00e4hima jaama leidmiseks laius- ja pikkuskraadi.", "title": "\u00dchendu riikliku ilmateenistusega (USA)" } } diff --git a/homeassistant/components/nws/translations/lb.json b/homeassistant/components/nws/translations/lb.json index a527406223d..30635e741d9 100644 --- a/homeassistant/components/nws/translations/lb.json +++ b/homeassistant/components/nws/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Apparat ass scho konfigur\u00e9iert" + "already_configured": "Service ass scho konfigur\u00e9iert" }, "error": { "cannot_connect": "Feeler beim verbannen", diff --git a/homeassistant/components/nzbget/translations/ca.json b/homeassistant/components/nzbget/translations/ca.json index b567d77bcb3..4bd1b53b762 100644 --- a/homeassistant/components/nzbget/translations/ca.json +++ b/homeassistant/components/nzbget/translations/ca.json @@ -5,8 +5,7 @@ "unknown": "Error inesperat" }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" + "cannot_connect": "Ha fallat la connexi\u00f3" }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/cs.json b/homeassistant/components/nzbget/translations/cs.json index c277ce42281..4f4dbe9c8e5 100644 --- a/homeassistant/components/nzbget/translations/cs.json +++ b/homeassistant/components/nzbget/translations/cs.json @@ -5,8 +5,7 @@ "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/en.json b/homeassistant/components/nzbget/translations/en.json index d9a6273c27c..b46c7b1d799 100644 --- a/homeassistant/components/nzbget/translations/en.json +++ b/homeassistant/components/nzbget/translations/en.json @@ -5,8 +5,7 @@ "unknown": "Unexpected error" }, "error": { - "cannot_connect": "Failed to connect", - "invalid_auth": "Invalid authentication" + "cannot_connect": "Failed to connect" }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/es.json b/homeassistant/components/nzbget/translations/es.json index 153fa5736af..cc89bdd2469 100644 --- a/homeassistant/components/nzbget/translations/es.json +++ b/homeassistant/components/nzbget/translations/es.json @@ -5,8 +5,7 @@ "unknown": "Error inesperado" }, "error": { - "cannot_connect": "No se pudo conectar", - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" + "cannot_connect": "No se pudo conectar" }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/et.json b/homeassistant/components/nzbget/translations/et.json index 93f7cab7cf8..ee83b59928d 100644 --- a/homeassistant/components/nzbget/translations/et.json +++ b/homeassistant/components/nzbget/translations/et.json @@ -5,9 +5,9 @@ "unknown": "Tundmatu viga" }, "error": { - "cannot_connect": "\u00dchendamine nurjus", - "invalid_auth": "Tuvastamine nurjus" + "cannot_connect": "\u00dchendamine nurjus" }, + "flow_title": "", "step": { "user": { "data": { @@ -15,6 +15,7 @@ "name": "Nimi", "password": "Salas\u00f5na", "port": "", + "ssl": "Kasutab SSL serti", "username": "Kasutajanimi", "verify_ssl": "Kontrolli SSL sertifikaati" }, diff --git a/homeassistant/components/nzbget/translations/fr.json b/homeassistant/components/nzbget/translations/fr.json index b08d8c2881a..4ccc080fbcc 100644 --- a/homeassistant/components/nzbget/translations/fr.json +++ b/homeassistant/components/nzbget/translations/fr.json @@ -5,8 +5,7 @@ "unknown": "Erreur inattendue" }, "error": { - "cannot_connect": "\u00c9chec de connexion", - "invalid_auth": "Authentification invalide" + "cannot_connect": "\u00c9chec de connexion" }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/it.json b/homeassistant/components/nzbget/translations/it.json index 88bea29987b..7eaf5c78e08 100644 --- a/homeassistant/components/nzbget/translations/it.json +++ b/homeassistant/components/nzbget/translations/it.json @@ -5,8 +5,7 @@ "unknown": "Errore imprevisto" }, "error": { - "cannot_connect": "Impossibile connettersi", - "invalid_auth": "Autenticazione non valida" + "cannot_connect": "Impossibile connettersi" }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/ko.json b/homeassistant/components/nzbget/translations/ko.json index ea9108b9367..dd53d52a236 100644 --- a/homeassistant/components/nzbget/translations/ko.json +++ b/homeassistant/components/nzbget/translations/ko.json @@ -5,8 +5,7 @@ "unknown": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc5d0\ub7ec" }, "error": { - "cannot_connect": "\uc5f0\uacb0 \uc2e4\ud328", - "invalid_auth": "\uc798\ubabb\ub41c \uc778\uc99d" + "cannot_connect": "\uc5f0\uacb0 \uc2e4\ud328" }, "flow_title": "NZBGet : {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/lb.json b/homeassistant/components/nzbget/translations/lb.json index 5da36a5d859..031da460822 100644 --- a/homeassistant/components/nzbget/translations/lb.json +++ b/homeassistant/components/nzbget/translations/lb.json @@ -1,11 +1,11 @@ { "config": { "abort": { + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech.", "unknown": "Onerwaarte Feeler" }, "error": { - "cannot_connect": "Feeler beim verbannen", - "invalid_auth": "Ong\u00eblteg Authentifikatioun" + "cannot_connect": "Feeler beim verbannen" }, "flow_title": "NZBGet: {name}", "step": { @@ -15,9 +15,9 @@ "name": "Numm", "password": "Passwuert", "port": "Port", - "ssl": "NZBGet benotzt een SSL Zertifikat", + "ssl": "benotzt een SSL Zertifikat", "username": "Benotzernumm", - "verify_ssl": "NZBGet benotzt ee g\u00ebltegen SSL Zertifikat" + "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" }, "title": "Mat NZBGet verbannen" } diff --git a/homeassistant/components/nzbget/translations/nl.json b/homeassistant/components/nzbget/translations/nl.json index b8caac157dc..cc7d8071c2c 100644 --- a/homeassistant/components/nzbget/translations/nl.json +++ b/homeassistant/components/nzbget/translations/nl.json @@ -1,7 +1,11 @@ { "config": { "abort": { - "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." + "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk.", + "unknown": "Onverwachte fout" + }, + "error": { + "cannot_connect": "Kon niet verbinden" }, "flow_title": "NZBGet: {name}", "step": { @@ -10,8 +14,11 @@ "name": "Naam", "password": "Wachtwoord", "port": "Poort", - "username": "Gebruikersnaam" - } + "ssl": "Maakt gebruik van een SSL-certificaat", + "username": "Gebruikersnaam", + "verify_ssl": "SSL-certificaat verifi\u00ebren" + }, + "title": "Maak verbinding met NZBGet" } } } diff --git a/homeassistant/components/nzbget/translations/no.json b/homeassistant/components/nzbget/translations/no.json index bf7840c9c60..cb9fce35897 100644 --- a/homeassistant/components/nzbget/translations/no.json +++ b/homeassistant/components/nzbget/translations/no.json @@ -5,8 +5,7 @@ "unknown": "Uventet feil" }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "invalid_auth": "Ugyldig godkjenning" + "cannot_connect": "Tilkobling mislyktes" }, "flow_title": "", "step": { diff --git a/homeassistant/components/nzbget/translations/pl.json b/homeassistant/components/nzbget/translations/pl.json index d1cfea50602..9ae5b46b680 100644 --- a/homeassistant/components/nzbget/translations/pl.json +++ b/homeassistant/components/nzbget/translations/pl.json @@ -5,8 +5,7 @@ "unknown": "Nieoczekiwany b\u0142\u0105d" }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "invalid_auth": "Niepoprawne uwierzytelnienie" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/pt.json b/homeassistant/components/nzbget/translations/pt.json index 2fa9743db44..ba038c72c68 100644 --- a/homeassistant/components/nzbget/translations/pt.json +++ b/homeassistant/components/nzbget/translations/pt.json @@ -5,8 +5,7 @@ "unknown": "Erro inesperado" }, "error": { - "cannot_connect": "Falha na liga\u00e7\u00e3o", - "invalid_auth": "Autentica\u00e7\u00e3o inv\u00e1lida" + "cannot_connect": "Falha na liga\u00e7\u00e3o" }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/ru.json b/homeassistant/components/nzbget/translations/ru.json index daab5c87ef7..e4f0a44fbcc 100644 --- a/homeassistant/components/nzbget/translations/ru.json +++ b/homeassistant/components/nzbget/translations/ru.json @@ -5,8 +5,7 @@ "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "flow_title": "NZBGet: {name}", "step": { diff --git a/homeassistant/components/nzbget/translations/zh-Hant.json b/homeassistant/components/nzbget/translations/zh-Hant.json index e2c3c8ea820..7858092db4f 100644 --- a/homeassistant/components/nzbget/translations/zh-Hant.json +++ b/homeassistant/components/nzbget/translations/zh-Hant.json @@ -5,8 +5,7 @@ "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "flow_title": "NZBGet\uff1a{name}", "step": { diff --git a/homeassistant/components/obihai/sensor.py b/homeassistant/components/obihai/sensor.py index a81b381f1ed..c105b91971d 100644 --- a/homeassistant/components/obihai/sensor.py +++ b/homeassistant/components/obihai/sensor.py @@ -126,6 +126,16 @@ class ObihaiServiceSensors(Entity): if self._state == "Off Hook": return "mdi:phone-in-talk" return "mdi:phone-hangup" + if "Service Status" in self._service_name: + if "OBiTALK Service Status" in self._service_name: + return "mdi:phone-check" + if self._state == "0": + return "mdi:phone-hangup" + return "mdi:phone-in-talk" + if "Reboot Required" in self._service_name: + if self._state == "false": + return "mdi:restart-off" + return "mdi:restart-alert" return "mdi:phone" def update(self): diff --git a/homeassistant/components/octoprint/__init__.py b/homeassistant/components/octoprint/__init__.py index 373988ca08a..6f178f26578 100644 --- a/homeassistant/components/octoprint/__init__.py +++ b/homeassistant/components/octoprint/__init__.py @@ -193,8 +193,9 @@ class OctoPrintAPI: self.job_last_reading = [{}, None] self.job_available = False self.printer_available = False - self.available = False self.printer_error_logged = False + self.available = False + self.available_error_logged = False self.job_error_logged = False self.bed = bed self.number_of_tools = number_of_tools @@ -240,13 +241,30 @@ class OctoPrintAPI: self.printer_last_reading[0] = response.json() self.printer_last_reading[1] = time.time() self.printer_available = True + self.available = self.printer_available and self.job_available if self.available: self.job_error_logged = False self.printer_error_logged = False + self.available_error_logged = False + return response.json() - except Exception as conn_exc: # pylint: disable=broad-except - log_string = "Failed to update OctoPrint status. Error: %s" % conn_exc + + except requests.ConnectionError as exc_con: + log_string = "Failed to connect to Octoprint server. Error: %s" % exc_con + + if not self.available_error_logged: + _LOGGER.error(log_string) + self.job_available = False + self.printer_available = False + self.available_error_logged = True + + return None + + except requests.HTTPError as ex_http: + status_code = ex_http.response.status_code + + log_string = "Failed to update OctoPrint status. Error: %s" % ex_http # Only log the first failure if endpoint == "job": log_string = f"Endpoint: job {log_string}" @@ -255,12 +273,19 @@ class OctoPrintAPI: self.job_error_logged = True self.job_available = False elif endpoint == "printer": - log_string = f"Endpoint: printer {log_string}" - if not self.printer_error_logged: - _LOGGER.error(log_string) - self.printer_error_logged = True + if ( + status_code == 409 + ): # octoprint returns HTTP 409 when printer is not connected (and many other states) self.printer_available = False + else: + log_string = f"Endpoint: printer {log_string}" + if not self.printer_error_logged: + _LOGGER.error(log_string) + self.printer_error_logged = True + self.printer_available = False + self.available = False + return None def update(self, sensor_type, end_point, group, tool=None): @@ -268,6 +293,7 @@ class OctoPrintAPI: response = self.get(end_point) if response is not None: return get_value_from_json(response, sensor_type, group, tool) + return response @@ -279,6 +305,7 @@ def get_value_from_json(json_dict, sensor_type, group, tool): if sensor_type in json_dict[group]: if sensor_type == "target" and json_dict[sensor_type] is None: return 0 + return json_dict[group][sensor_type] if tool is not None: diff --git a/homeassistant/components/omnilogic/strings.json b/homeassistant/components/omnilogic/strings.json index 285bc29b802..c050a7945f1 100644 --- a/homeassistant/components/omnilogic/strings.json +++ b/homeassistant/components/omnilogic/strings.json @@ -1,5 +1,4 @@ { - "title": "Omnilogic", "config": { "step": { "user": { @@ -27,4 +26,4 @@ } } } -} \ No newline at end of file +} diff --git a/homeassistant/components/omnilogic/translations/ca.json b/homeassistant/components/omnilogic/translations/ca.json index 53c8755dd36..b460e47f2b8 100644 --- a/homeassistant/components/omnilogic/translations/ca.json +++ b/homeassistant/components/omnilogic/translations/ca.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/cs.json b/homeassistant/components/omnilogic/translations/cs.json index 6f2b3f709ab..b5521c4b9ec 100644 --- a/homeassistant/components/omnilogic/translations/cs.json +++ b/homeassistant/components/omnilogic/translations/cs.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/de.json b/homeassistant/components/omnilogic/translations/de.json index c4002834589..6f398062876 100644 --- a/homeassistant/components/omnilogic/translations/de.json +++ b/homeassistant/components/omnilogic/translations/de.json @@ -8,6 +8,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/el.json b/homeassistant/components/omnilogic/translations/el.json index fbe77ec16c0..79464ad7d0e 100644 --- a/homeassistant/components/omnilogic/translations/el.json +++ b/homeassistant/components/omnilogic/translations/el.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/en.json b/homeassistant/components/omnilogic/translations/en.json index 858cfe31323..e46253a922d 100644 --- a/homeassistant/components/omnilogic/translations/en.json +++ b/homeassistant/components/omnilogic/translations/en.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/es.json b/homeassistant/components/omnilogic/translations/es.json index aa9cafc9ddb..7e054159bf9 100644 --- a/homeassistant/components/omnilogic/translations/es.json +++ b/homeassistant/components/omnilogic/translations/es.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/et.json b/homeassistant/components/omnilogic/translations/et.json index 2ad446f3716..c9a06f01117 100644 --- a/homeassistant/components/omnilogic/translations/et.json +++ b/homeassistant/components/omnilogic/translations/et.json @@ -25,6 +25,5 @@ } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/fr.json b/homeassistant/components/omnilogic/translations/fr.json index 167beb756a8..ab73af0d27a 100644 --- a/homeassistant/components/omnilogic/translations/fr.json +++ b/homeassistant/components/omnilogic/translations/fr.json @@ -16,5 +16,14 @@ } } } + }, + "options": { + "step": { + "init": { + "data": { + "polling_interval": "Intervalle d'interrogation (en secondes)" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/it.json b/homeassistant/components/omnilogic/translations/it.json index 38ace995177..ceff0e81258 100644 --- a/homeassistant/components/omnilogic/translations/it.json +++ b/homeassistant/components/omnilogic/translations/it.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/ko.json b/homeassistant/components/omnilogic/translations/ko.json index 686ca520bff..5389207cdda 100644 --- a/homeassistant/components/omnilogic/translations/ko.json +++ b/homeassistant/components/omnilogic/translations/ko.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/lb.json b/homeassistant/components/omnilogic/translations/lb.json index 22f3cb54a6e..a99b69c2943 100644 --- a/homeassistant/components/omnilogic/translations/lb.json +++ b/homeassistant/components/omnilogic/translations/lb.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/nl.json b/homeassistant/components/omnilogic/translations/nl.json index 31587927587..1127dc941ea 100644 --- a/homeassistant/components/omnilogic/translations/nl.json +++ b/homeassistant/components/omnilogic/translations/nl.json @@ -16,6 +16,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/no.json b/homeassistant/components/omnilogic/translations/no.json index e19146aa4c1..96c072082e1 100644 --- a/homeassistant/components/omnilogic/translations/no.json +++ b/homeassistant/components/omnilogic/translations/no.json @@ -25,6 +25,5 @@ } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/pl.json b/homeassistant/components/omnilogic/translations/pl.json index 10cbbdb12b7..5fafc963760 100644 --- a/homeassistant/components/omnilogic/translations/pl.json +++ b/homeassistant/components/omnilogic/translations/pl.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/ru.json b/homeassistant/components/omnilogic/translations/ru.json index 3b05c74695d..9040654e58c 100644 --- a/homeassistant/components/omnilogic/translations/ru.json +++ b/homeassistant/components/omnilogic/translations/ru.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/omnilogic/translations/zh-Hant.json b/homeassistant/components/omnilogic/translations/zh-Hant.json index 335e26ced8c..99b5a46570e 100644 --- a/homeassistant/components/omnilogic/translations/zh-Hant.json +++ b/homeassistant/components/omnilogic/translations/zh-Hant.json @@ -25,6 +25,5 @@ } } } - }, - "title": "Omnilogic" + } } \ No newline at end of file diff --git a/homeassistant/components/onboarding/translations/et.json b/homeassistant/components/onboarding/translations/et.json new file mode 100644 index 00000000000..0f7ce6a3578 --- /dev/null +++ b/homeassistant/components/onboarding/translations/et.json @@ -0,0 +1,7 @@ +{ + "area": { + "bedroom": "Magamistuba", + "kitchen": "K\u00f6\u00f6k", + "living_room": "Elutuba" + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/__init__.py b/homeassistant/components/onewire/__init__.py index 21dc0c2ead3..6d64478aa72 100644 --- a/homeassistant/components/onewire/__init__.py +++ b/homeassistant/components/onewire/__init__.py @@ -1 +1,48 @@ """The 1-Wire component.""" +import asyncio + +from homeassistant.config_entries import ConfigEntry +from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.helpers.typing import HomeAssistantType + +from .const import DOMAIN, SUPPORTED_PLATFORMS +from .onewirehub import CannotConnect, OneWireHub + + +async def async_setup(hass, config): + """Set up 1-Wire integrations.""" + return True + + +async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry): + """Set up a 1-Wire proxy for a config entry.""" + hass.data.setdefault(DOMAIN, {}) + + onewirehub = OneWireHub(hass) + try: + await onewirehub.initialize(config_entry) + except CannotConnect as exc: + raise ConfigEntryNotReady() from exc + + hass.data[DOMAIN][config_entry.unique_id] = onewirehub + + for component in SUPPORTED_PLATFORMS: + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(config_entry, component) + ) + return True + + +async def async_unload_entry(hass: HomeAssistantType, config_entry: ConfigEntry): + """Unload a config entry.""" + unload_ok = all( + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(config_entry, component) + for component in SUPPORTED_PLATFORMS + ] + ) + ) + if unload_ok: + hass.data[DOMAIN].pop(config_entry.unique_id) + return unload_ok diff --git a/homeassistant/components/onewire/binary_sensor.py b/homeassistant/components/onewire/binary_sensor.py new file mode 100644 index 00000000000..031dd984702 --- /dev/null +++ b/homeassistant/components/onewire/binary_sensor.py @@ -0,0 +1,132 @@ +"""Support for 1-Wire binary sensors.""" +import os + +from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.const import CONF_TYPE + +from .const import CONF_TYPE_OWSERVER, DOMAIN, SENSOR_TYPE_SENSED +from .onewire_entities import OneWireProxyEntity +from .onewirehub import OneWireHub + +DEVICE_BINARY_SENSORS = { + # Family : { path, sensor_type } + "12": [ + { + "path": "sensed.A", + "name": "Sensed A", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + { + "path": "sensed.B", + "name": "Sensed B", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + ], + "29": [ + { + "path": "sensed.0", + "name": "Sensed 0", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + { + "path": "sensed.1", + "name": "Sensed 1", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + { + "path": "sensed.2", + "name": "Sensed 2", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + { + "path": "sensed.3", + "name": "Sensed 3", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + { + "path": "sensed.4", + "name": "Sensed 4", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + { + "path": "sensed.5", + "name": "Sensed 5", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + { + "path": "sensed.6", + "name": "Sensed 6", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + { + "path": "sensed.7", + "name": "Sensed 7", + "type": SENSOR_TYPE_SENSED, + "default_disabled": True, + }, + ], +} + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up 1-Wire platform.""" + # Only OWServer implementation works with binary sensors + if config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER: + onewirehub = hass.data[DOMAIN][config_entry.unique_id] + + entities = await hass.async_add_executor_job(get_entities, onewirehub) + async_add_entities(entities, True) + + +def get_entities(onewirehub: OneWireHub): + """Get a list of entities.""" + entities = [] + + for device in onewirehub.devices: + family = device["family"] + device_type = device["type"] + sensor_id = os.path.split(os.path.split(device["path"])[0])[1] + + if family not in DEVICE_BINARY_SENSORS: + continue + device_info = { + "identifiers": {(DOMAIN, sensor_id)}, + "manufacturer": "Maxim Integrated", + "model": device_type, + "name": sensor_id, + } + for device_sensor in DEVICE_BINARY_SENSORS[family]: + device_file = os.path.join( + os.path.split(device["path"])[0], device_sensor["path"] + ) + entities.append( + OneWireProxyBinarySensor( + sensor_id, + device_file, + device_sensor["type"], + device_sensor["name"], + device_info, + device_sensor.get("default_disabled", False), + onewirehub.owproxy, + ) + ) + + return entities + + +class OneWireProxyBinarySensor(OneWireProxyEntity, BinarySensorEntity): + """Implementation of a 1-Wire binary sensor.""" + + @property + def is_on(self): + """Return true if sensor is on.""" + return self._state diff --git a/homeassistant/components/onewire/config_flow.py b/homeassistant/components/onewire/config_flow.py new file mode 100644 index 00000000000..f83431111d8 --- /dev/null +++ b/homeassistant/components/onewire/config_flow.py @@ -0,0 +1,187 @@ +"""Config flow for 1-Wire component.""" +import voluptuous as vol + +from homeassistant.config_entries import CONN_CLASS_LOCAL_POLL, ConfigFlow +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE +from homeassistant.helpers.typing import HomeAssistantType + +from .const import ( # pylint: disable=unused-import + CONF_MOUNT_DIR, + CONF_TYPE_OWFS, + CONF_TYPE_OWSERVER, + CONF_TYPE_SYSBUS, + DEFAULT_OWSERVER_HOST, + DEFAULT_OWSERVER_PORT, + DEFAULT_SYSBUS_MOUNT_DIR, + DOMAIN, +) +from .onewirehub import CannotConnect, InvalidPath, OneWireHub + +DATA_SCHEMA_USER = vol.Schema( + {vol.Required(CONF_TYPE): vol.In([CONF_TYPE_OWSERVER, CONF_TYPE_SYSBUS])} +) +DATA_SCHEMA_OWSERVER = vol.Schema( + { + vol.Required(CONF_HOST, default=DEFAULT_OWSERVER_HOST): str, + vol.Required(CONF_PORT, default=DEFAULT_OWSERVER_PORT): int, + } +) +DATA_SCHEMA_MOUNTDIR = vol.Schema( + { + vol.Required(CONF_MOUNT_DIR, default=DEFAULT_SYSBUS_MOUNT_DIR): str, + } +) + + +async def validate_input_owserver(hass: HomeAssistantType, data): + """Validate the user input allows us to connect. + + Data has the keys from DATA_SCHEMA_OWSERVER with values provided by the user. + """ + + hub = OneWireHub(hass) + + host = data[CONF_HOST] + port = data[CONF_PORT] + # Raises CannotConnect exception on failure + await hub.connect(host, port) + + # Return info that you want to store in the config entry. + return {"title": host} + + +def is_duplicate_owserver_entry(hass: HomeAssistantType, user_input): + """Check existing entries for matching host and port.""" + for config_entry in hass.config_entries.async_entries(DOMAIN): + if ( + config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER + and config_entry.data[CONF_HOST] == user_input[CONF_HOST] + and config_entry.data[CONF_PORT] == str(user_input[CONF_PORT]) + ): + return True + return False + + +async def validate_input_mount_dir(hass: HomeAssistantType, data): + """Validate the user input allows us to connect. + + Data has the keys from DATA_SCHEMA_MOUNTDIR with values provided by the user. + """ + hub = OneWireHub(hass) + + mount_dir = data[CONF_MOUNT_DIR] + + # Raises InvalidDir exception on failure + await hub.check_mount_dir(mount_dir) + + # Return info that you want to store in the config entry. + return {"title": mount_dir} + + +class OneWireFlowHandler(ConfigFlow, domain=DOMAIN): + """Handle 1-Wire config flow.""" + + VERSION = 1 + CONNECTION_CLASS = CONN_CLASS_LOCAL_POLL + + def __init__(self): + """Initialize 1-Wire config flow.""" + self.onewire_config = {} + + async def async_step_user(self, user_input=None): + """Handle 1-Wire config flow start. + + Let user manually input configuration. + """ + errors = {} + if user_input is not None: + self.onewire_config.update(user_input) + if CONF_TYPE_OWSERVER == user_input[CONF_TYPE]: + return await self.async_step_owserver() + if CONF_TYPE_SYSBUS == user_input[CONF_TYPE]: + return await self.async_step_mount_dir() + + return self.async_show_form( + step_id="user", + data_schema=DATA_SCHEMA_USER, + errors=errors, + ) + + async def async_step_owserver(self, user_input=None): + """Handle OWServer configuration.""" + errors = {} + if user_input: + # Prevent duplicate entries + if is_duplicate_owserver_entry(self.hass, user_input): + return self.async_abort(reason="already_configured") + + self.onewire_config.update(user_input) + + try: + info = await validate_input_owserver(self.hass, user_input) + except CannotConnect: + errors["base"] = "cannot_connect" + else: + return self.async_create_entry( + title=info["title"], data=self.onewire_config + ) + + return self.async_show_form( + step_id="owserver", + data_schema=DATA_SCHEMA_OWSERVER, + errors=errors, + ) + + async def async_step_mount_dir(self, user_input=None): + """Handle SysBus configuration.""" + errors = {} + if user_input: + # Prevent duplicate entries + await self.async_set_unique_id( + f"{CONF_TYPE_SYSBUS}:{user_input[CONF_MOUNT_DIR]}" + ) + self._abort_if_unique_id_configured() + + self.onewire_config.update(user_input) + + try: + info = await validate_input_mount_dir(self.hass, user_input) + except InvalidPath: + errors["base"] = "invalid_path" + else: + return self.async_create_entry( + title=info["title"], data=self.onewire_config + ) + + return self.async_show_form( + step_id="mount_dir", + data_schema=DATA_SCHEMA_MOUNTDIR, + errors=errors, + ) + + async def async_step_import(self, platform_config): + """Handle import configuration from YAML.""" + # OWServer + if platform_config[CONF_TYPE] == CONF_TYPE_OWSERVER: + if CONF_PORT not in platform_config: + platform_config[CONF_PORT] = DEFAULT_OWSERVER_PORT + return await self.async_step_owserver(platform_config) + + # OWFS + if platform_config[CONF_TYPE] == CONF_TYPE_OWFS: # pragma: no cover + # This part of the implementation does not conform to policy regarding 3rd-party libraries, and will not longer be updated. + # https://developers.home-assistant.io/docs/creating_platform_code_review/#5-communication-with-devicesservices + await self.async_set_unique_id( + f"{CONF_TYPE_OWFS}:{platform_config[CONF_MOUNT_DIR]}" + ) + self._abort_if_unique_id_configured( + updates=platform_config, reload_on_update=True + ) + return self.async_create_entry( + title=platform_config[CONF_MOUNT_DIR], data=platform_config + ) + + # SysBus + if CONF_MOUNT_DIR not in platform_config: + platform_config[CONF_MOUNT_DIR] = DEFAULT_SYSBUS_MOUNT_DIR + return await self.async_step_mount_dir(platform_config) diff --git a/homeassistant/components/onewire/const.py b/homeassistant/components/onewire/const.py index 83ffa12706c..e68039078e9 100644 --- a/homeassistant/components/onewire/const.py +++ b/homeassistant/components/onewire/const.py @@ -1,5 +1,21 @@ """Constants for 1-Wire component.""" +from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from homeassistant.const import ( + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_ILLUMINANCE, + DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLTAGE, + ELECTRICAL_CURRENT_AMPERE, + LIGHT_LUX, + PERCENTAGE, + PRESSURE_MBAR, + TEMP_CELSIUS, + VOLT, +) CONF_MOUNT_DIR = "mount_dir" CONF_NAMES = "names" @@ -8,6 +24,7 @@ CONF_TYPE_OWFS = "OWFS" CONF_TYPE_OWSERVER = "OWServer" CONF_TYPE_SYSBUS = "SysBus" +DEFAULT_OWSERVER_HOST = "localhost" DEFAULT_OWSERVER_PORT = 4304 DEFAULT_SYSBUS_MOUNT_DIR = "/sys/bus/w1/devices/" @@ -15,6 +32,37 @@ DOMAIN = "onewire" PRESSURE_CBAR = "cbar" +SENSOR_TYPE_COUNT = "count" +SENSOR_TYPE_CURRENT = "current" +SENSOR_TYPE_HUMIDITY = "humidity" +SENSOR_TYPE_ILLUMINANCE = "illuminance" +SENSOR_TYPE_MOISTURE = "moisture" +SENSOR_TYPE_PRESSURE = "pressure" +SENSOR_TYPE_SENSED = "sensed" +SENSOR_TYPE_TEMPERATURE = "temperature" +SENSOR_TYPE_VOLTAGE = "voltage" +SENSOR_TYPE_WETNESS = "wetness" +SWITCH_TYPE_LATCH = "latch" +SWITCH_TYPE_PIO = "pio" + +SENSOR_TYPES = { + # SensorType: [ Unit, DeviceClass ] + SENSOR_TYPE_TEMPERATURE: [TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE], + SENSOR_TYPE_HUMIDITY: [PERCENTAGE, DEVICE_CLASS_HUMIDITY], + SENSOR_TYPE_PRESSURE: [PRESSURE_MBAR, DEVICE_CLASS_PRESSURE], + SENSOR_TYPE_ILLUMINANCE: [LIGHT_LUX, DEVICE_CLASS_ILLUMINANCE], + SENSOR_TYPE_WETNESS: [PERCENTAGE, DEVICE_CLASS_HUMIDITY], + SENSOR_TYPE_MOISTURE: [PRESSURE_CBAR, DEVICE_CLASS_PRESSURE], + SENSOR_TYPE_COUNT: ["count", None], + SENSOR_TYPE_VOLTAGE: [VOLT, DEVICE_CLASS_VOLTAGE], + SENSOR_TYPE_CURRENT: [ELECTRICAL_CURRENT_AMPERE, DEVICE_CLASS_CURRENT], + SENSOR_TYPE_SENSED: [None, None], + SWITCH_TYPE_LATCH: [None, None], + SWITCH_TYPE_PIO: [None, None], +} + SUPPORTED_PLATFORMS = [ + BINARY_SENSOR_DOMAIN, SENSOR_DOMAIN, + SWITCH_DOMAIN, ] diff --git a/homeassistant/components/onewire/manifest.json b/homeassistant/components/onewire/manifest.json index 42ef7e54603..47ab6ad2404 100644 --- a/homeassistant/components/onewire/manifest.json +++ b/homeassistant/components/onewire/manifest.json @@ -2,6 +2,7 @@ "domain": "onewire", "name": "1-Wire", "documentation": "https://www.home-assistant.io/integrations/onewire", + "config_flow": true, "requirements": ["pyownet==0.10.0.post1", "pi1wire==0.1.0"], "codeowners": ["@garbled1", "@epenet"] } diff --git a/homeassistant/components/onewire/onewire_entities.py b/homeassistant/components/onewire/onewire_entities.py new file mode 100644 index 00000000000..d16a2e9b493 --- /dev/null +++ b/homeassistant/components/onewire/onewire_entities.py @@ -0,0 +1,125 @@ +"""Support for 1-Wire entities.""" +import logging +from typing import Any, Dict, Optional + +from pyownet import protocol + +from homeassistant.helpers.entity import Entity + +from .const import ( + SENSOR_TYPE_COUNT, + SENSOR_TYPE_SENSED, + SENSOR_TYPES, + SWITCH_TYPE_LATCH, + SWITCH_TYPE_PIO, +) + +_LOGGER = logging.getLogger(__name__) + + +class OneWireBaseEntity(Entity): + """Implementation of a 1-Wire entity.""" + + def __init__( + self, + name, + device_file, + entity_type: str, + entity_name: str = None, + device_info=None, + default_disabled: bool = False, + ): + """Initialize the entity.""" + self._name = f"{name} {entity_name or entity_type.capitalize()}" + self._device_file = device_file + self._entity_type = entity_type + self._device_class = SENSOR_TYPES[entity_type][1] + self._unit_of_measurement = SENSOR_TYPES[entity_type][0] + self._device_info = device_info + self._state = None + self._value_raw = None + self._default_disabled = default_disabled + + @property + def name(self) -> Optional[str]: + """Return the name of the entity.""" + return self._name + + @property + def device_class(self) -> Optional[str]: + """Return the class of this device.""" + return self._device_class + + @property + def unit_of_measurement(self) -> Optional[str]: + """Return the unit the value is expressed in.""" + return self._unit_of_measurement + + @property + def device_state_attributes(self) -> Optional[Dict[str, Any]]: + """Return the state attributes of the entity.""" + return {"device_file": self._device_file, "raw_value": self._value_raw} + + @property + def unique_id(self) -> Optional[str]: + """Return a unique ID.""" + return self._device_file + + @property + def device_info(self) -> Optional[Dict[str, Any]]: + """Return device specific attributes.""" + return self._device_info + + @property + def entity_registry_enabled_default(self) -> bool: + """Return if the entity should be enabled when first added to the entity registry.""" + return not self._default_disabled + + +class OneWireProxyEntity(OneWireBaseEntity): + """Implementation of a 1-Wire entity connected through owserver.""" + + def __init__( + self, + name: str, + device_file: str, + entity_type: str, + entity_name: str, + device_info: Dict[str, Any], + default_disabled: bool, + owproxy: protocol._Proxy, + ): + """Initialize the sensor.""" + super().__init__( + name, device_file, entity_type, entity_name, device_info, default_disabled + ) + self._owproxy = owproxy + + def _read_value_ownet(self): + """Read a value from the owserver.""" + return self._owproxy.read(self._device_file).decode().lstrip() + + def _write_value_ownet(self, value: bytes): + """Write a value to the owserver.""" + return self._owproxy.write(self._device_file, value) + + def update(self): + """Get the latest data from the device.""" + value = None + try: + self._value_raw = float(self._read_value_ownet()) + except protocol.Error as exc: + _LOGGER.error("Owserver failure in read(), got: %s", exc) + else: + if self._entity_type == SENSOR_TYPE_COUNT: + value = int(self._value_raw) + elif self._entity_type in [ + SENSOR_TYPE_SENSED, + SWITCH_TYPE_LATCH, + SWITCH_TYPE_PIO, + ]: + value = int(self._value_raw) == 1 + else: + value = round(self._value_raw, 1) + + self._state = value diff --git a/homeassistant/components/onewire/onewirehub.py b/homeassistant/components/onewire/onewirehub.py new file mode 100644 index 00000000000..3b715eed0dd --- /dev/null +++ b/homeassistant/components/onewire/onewirehub.py @@ -0,0 +1,84 @@ +"""Hub for communication with 1-Wire server or mount_dir.""" +import os + +from pi1wire import Pi1Wire +from pyownet import protocol + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.typing import HomeAssistantType + +from .const import CONF_MOUNT_DIR, CONF_TYPE_OWSERVER, CONF_TYPE_SYSBUS + + +class OneWireHub: + """Hub to communicate with SysBus or OWServer.""" + + def __init__(self, hass: HomeAssistantType): + """Initialize.""" + self.hass = hass + self.type: str = None + self.pi1proxy: Pi1Wire = None + self.owproxy: protocol._Proxy = None + self.devices = None + + async def connect(self, host: str, port: int) -> None: + """Connect to the owserver host.""" + try: + self.owproxy = await self.hass.async_add_executor_job( + protocol.proxy, host, port + ) + except protocol.ConnError as exc: + raise CannotConnect from exc + + async def check_mount_dir(self, mount_dir: str) -> None: + """Test that the mount_dir is a valid path.""" + if not await self.hass.async_add_executor_job(os.path.isdir, mount_dir): + raise InvalidPath + self.pi1proxy = Pi1Wire(mount_dir) + + async def initialize(self, config_entry: ConfigEntry) -> None: + """Initialize a config entry.""" + self.type = config_entry.data[CONF_TYPE] + if self.type == CONF_TYPE_SYSBUS: + await self.check_mount_dir(config_entry.data[CONF_MOUNT_DIR]) + elif self.type == CONF_TYPE_OWSERVER: + host = config_entry.data[CONF_HOST] + port = config_entry.data[CONF_PORT] + await self.connect(host, port) + await self.discover_devices() + + async def discover_devices(self): + """Discover all devices.""" + if self.devices is None: + if self.type == CONF_TYPE_SYSBUS: + self.devices = await self.hass.async_add_executor_job( + self.pi1proxy.find_all_sensors + ) + if self.type == CONF_TYPE_OWSERVER: + self.devices = await self.hass.async_add_executor_job( + self._discover_devices_owserver + ) + return self.devices + + def _discover_devices_owserver(self): + """Discover all owserver devices.""" + devices = [] + for device_path in self.owproxy.dir(): + devices.append( + { + "path": device_path, + "family": self.owproxy.read(f"{device_path}family").decode(), + "type": self.owproxy.read(f"{device_path}type").decode(), + } + ) + return devices + + +class CannotConnect(HomeAssistantError): + """Error to indicate we cannot connect.""" + + +class InvalidPath(HomeAssistantError): + """Error to indicate the path is invalid.""" diff --git a/homeassistant/components/onewire/sensor.py b/homeassistant/components/onewire/sensor.py index bce17dbf3cb..f908c1ada2d 100644 --- a/homeassistant/components/onewire/sensor.py +++ b/homeassistant/components/onewire/sensor.py @@ -3,23 +3,14 @@ from glob import glob import logging import os -from pi1wire import InvalidCRCException, Pi1Wire, UnsupportResponseException -from pyownet import protocol +from pi1wire import InvalidCRCException, UnsupportResponseException import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import ( - CONF_HOST, - CONF_PORT, - ELECTRICAL_CURRENT_AMPERE, - LIGHT_LUX, - PERCENTAGE, - PRESSURE_MBAR, - TEMP_CELSIUS, - VOLT, -) +from homeassistant.config_entries import SOURCE_IMPORT +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.entity import Entity +from homeassistant.helpers.typing import StateType from .const import ( CONF_MOUNT_DIR, @@ -29,34 +20,121 @@ from .const import ( CONF_TYPE_SYSBUS, DEFAULT_OWSERVER_PORT, DEFAULT_SYSBUS_MOUNT_DIR, - PRESSURE_CBAR, + DOMAIN, + SENSOR_TYPE_COUNT, + SENSOR_TYPE_CURRENT, + SENSOR_TYPE_HUMIDITY, + SENSOR_TYPE_ILLUMINANCE, + SENSOR_TYPE_MOISTURE, + SENSOR_TYPE_PRESSURE, + SENSOR_TYPE_TEMPERATURE, + SENSOR_TYPE_VOLTAGE, + SENSOR_TYPE_WETNESS, ) +from .onewire_entities import OneWireBaseEntity, OneWireProxyEntity +from .onewirehub import OneWireHub _LOGGER = logging.getLogger(__name__) DEVICE_SENSORS = { # Family : { SensorType: owfs path } - "10": {"temperature": "temperature"}, - "12": {"temperature": "TAI8570/temperature", "pressure": "TAI8570/pressure"}, - "22": {"temperature": "temperature"}, - "26": { - "temperature": "temperature", - "humidity": "humidity", - "humidity_hih3600": "HIH3600/humidity", - "humidity_hih4000": "HIH4000/humidity", - "humidity_hih5030": "HIH5030/humidity", - "humidity_htm1735": "HTM1735/humidity", - "pressure": "B1-R1-A/pressure", - "illuminance": "S3-R1-A/illuminance", - "voltage_VAD": "VAD", - "voltage_VDD": "VDD", - "current": "IAD", - }, - "28": {"temperature": "temperature"}, - "3B": {"temperature": "temperature"}, - "42": {"temperature": "temperature"}, - "1D": {"counter_a": "counter.A", "counter_b": "counter.B"}, - "EF": {"HobbyBoard": "special"}, + "10": [ + {"path": "temperature", "name": "Temperature", "type": SENSOR_TYPE_TEMPERATURE} + ], + "12": [ + { + "path": "TAI8570/temperature", + "name": "Temperature", + "type": SENSOR_TYPE_TEMPERATURE, + "default_disabled": True, + }, + { + "path": "TAI8570/pressure", + "name": "Pressure", + "type": SENSOR_TYPE_PRESSURE, + "default_disabled": True, + }, + ], + "22": [ + {"path": "temperature", "name": "Temperature", "type": SENSOR_TYPE_TEMPERATURE} + ], + "26": [ + {"path": "temperature", "name": "Temperature", "type": SENSOR_TYPE_TEMPERATURE}, + { + "path": "humidity", + "name": "Humidity", + "type": SENSOR_TYPE_HUMIDITY, + "default_disabled": True, + }, + { + "path": "HIH3600/humidity", + "name": "Humidity HIH3600", + "type": SENSOR_TYPE_HUMIDITY, + "default_disabled": True, + }, + { + "path": "HIH4000/humidity", + "name": "Humidity HIH4000", + "type": SENSOR_TYPE_HUMIDITY, + "default_disabled": True, + }, + { + "path": "HIH5030/humidity", + "name": "Humidity HIH5030", + "type": SENSOR_TYPE_HUMIDITY, + "default_disabled": True, + }, + { + "path": "HTM1735/humidity", + "name": "Humidity HTM1735", + "type": SENSOR_TYPE_HUMIDITY, + "default_disabled": True, + }, + { + "path": "B1-R1-A/pressure", + "name": "Pressure", + "type": SENSOR_TYPE_PRESSURE, + "default_disabled": True, + }, + { + "path": "S3-R1-A/illuminance", + "name": "Illuminance", + "type": SENSOR_TYPE_ILLUMINANCE, + "default_disabled": True, + }, + { + "path": "VAD", + "name": "Voltage VAD", + "type": SENSOR_TYPE_VOLTAGE, + "default_disabled": True, + }, + { + "path": "VDD", + "name": "Voltage VDD", + "type": SENSOR_TYPE_VOLTAGE, + "default_disabled": True, + }, + { + "path": "IAD", + "name": "Current", + "type": SENSOR_TYPE_CURRENT, + "default_disabled": True, + }, + ], + "28": [ + {"path": "temperature", "name": "Temperature", "type": SENSOR_TYPE_TEMPERATURE} + ], + "3B": [ + {"path": "temperature", "name": "Temperature", "type": SENSOR_TYPE_TEMPERATURE} + ], + "42": [ + {"path": "temperature", "name": "Temperature", "type": SENSOR_TYPE_TEMPERATURE} + ], + "1D": [ + {"path": "counter.A", "name": "Counter A", "type": SENSOR_TYPE_COUNT}, + {"path": "counter.B", "name": "Counter B", "type": SENSOR_TYPE_COUNT}, + ], + "EF": [], # "HobbyBoard": special } DEVICE_SUPPORT_SYSBUS = ["10", "22", "28", "3B", "42"] @@ -66,45 +144,45 @@ DEVICE_SUPPORT_SYSBUS = ["10", "22", "28", "3B", "42"] # via owserver (network protocol) HOBBYBOARD_EF = { - "HobbyBoards_EF": { - "humidity": "humidity/humidity_corrected", - "humidity_raw": "humidity/humidity_raw", - "temperature": "humidity/temperature", - }, - "HB_MOISTURE_METER": { - "moisture_0": "moisture/sensor.0", - "moisture_1": "moisture/sensor.1", - "moisture_2": "moisture/sensor.2", - "moisture_3": "moisture/sensor.3", - }, -} - -SENSOR_TYPES = { - # SensorType: [ Measured unit, Unit ] - "temperature": ["temperature", TEMP_CELSIUS], - "humidity": ["humidity", PERCENTAGE], - "humidity_hih3600": ["humidity", PERCENTAGE], - "humidity_hih4000": ["humidity", PERCENTAGE], - "humidity_hih5030": ["humidity", PERCENTAGE], - "humidity_htm1735": ["humidity", PERCENTAGE], - "humidity_raw": ["humidity", PERCENTAGE], - "pressure": ["pressure", PRESSURE_MBAR], - "illuminance": ["illuminance", LIGHT_LUX], - "wetness_0": ["wetness", PERCENTAGE], - "wetness_1": ["wetness", PERCENTAGE], - "wetness_2": ["wetness", PERCENTAGE], - "wetness_3": ["wetness", PERCENTAGE], - "moisture_0": ["moisture", PRESSURE_CBAR], - "moisture_1": ["moisture", PRESSURE_CBAR], - "moisture_2": ["moisture", PRESSURE_CBAR], - "moisture_3": ["moisture", PRESSURE_CBAR], - "counter_a": ["counter", "count"], - "counter_b": ["counter", "count"], - "HobbyBoard": ["none", "none"], - "voltage": ["voltage", VOLT], - "voltage_VAD": ["voltage", VOLT], - "voltage_VDD": ["voltage", VOLT], - "current": ["current", ELECTRICAL_CURRENT_AMPERE], + "HobbyBoards_EF": [ + { + "path": "humidity/humidity_corrected", + "name": "Humidity", + "type": SENSOR_TYPE_HUMIDITY, + }, + { + "path": "humidity/humidity_raw", + "name": "Humidity Raw", + "type": SENSOR_TYPE_HUMIDITY, + }, + { + "path": "humidity/temperature", + "name": "Temperature", + "type": SENSOR_TYPE_TEMPERATURE, + }, + ], + "HB_MOISTURE_METER": [ + { + "path": "moisture/sensor.0", + "name": "Moisture 0", + "type": SENSOR_TYPE_MOISTURE, + }, + { + "path": "moisture/sensor.1", + "name": "Moisture 1", + "type": SENSOR_TYPE_MOISTURE, + }, + { + "path": "moisture/sensor.2", + "name": "Moisture 2", + "type": SENSOR_TYPE_MOISTURE, + }, + { + "path": "moisture/sensor.3", + "name": "Moisture 3", + "type": SENSOR_TYPE_MOISTURE, + }, + ], } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( @@ -125,83 +203,97 @@ def hb_info_from_type(dev_type="std"): return HOBBYBOARD_EF -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up 1-Wire platform.""" - entities = get_entities(config) - add_entities(entities, True) - - -def get_entities(config): - """Get a list of entities.""" - base_dir = config[CONF_MOUNT_DIR] - owhost = config.get(CONF_HOST) - owport = config[CONF_PORT] - - # Ensure type is configured - if owhost: - conf_type = CONF_TYPE_OWSERVER - elif base_dir == DEFAULT_SYSBUS_MOUNT_DIR: - conf_type = CONF_TYPE_SYSBUS +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): + """Old way of setting up 1-Wire platform.""" + if config.get(CONF_HOST): + config[CONF_TYPE] = CONF_TYPE_OWSERVER + elif config[CONF_MOUNT_DIR] == DEFAULT_SYSBUS_MOUNT_DIR: + config[CONF_TYPE] = CONF_TYPE_SYSBUS else: # pragma: no cover # This part of the implementation does not conform to policy regarding 3rd-party libraries, and will not longer be updated. # https://developers.home-assistant.io/docs/creating_platform_code_review/#5-communication-with-devicesservices - conf_type = CONF_TYPE_OWFS + config[CONF_TYPE] = CONF_TYPE_OWFS + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=config + ) + ) + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up 1-Wire platform.""" + onewirehub = hass.data[DOMAIN][config_entry.unique_id] + entities = await hass.async_add_executor_job( + get_entities, onewirehub, config_entry.data + ) + async_add_entities(entities, True) + + +def get_entities(onewirehub: OneWireHub, config): + """Get a list of entities.""" entities = [] device_names = {} if CONF_NAMES in config: if isinstance(config[CONF_NAMES], dict): device_names = config[CONF_NAMES] + conf_type = config[CONF_TYPE] # We have an owserver on a remote(or local) host/port if conf_type == CONF_TYPE_OWSERVER: - _LOGGER.debug("Initializing using %s:%s", owhost, owport) - try: - owproxy = protocol.proxy(host=owhost, port=owport) - devices = owproxy.dir() - except protocol.Error as exc: - _LOGGER.error( - "Cannot connect to owserver on %s:%d, got: %s", owhost, owport, exc - ) - devices = [] - for device in devices: - _LOGGER.debug("Found device: %s", device) - family = owproxy.read(f"{device}family").decode() + for device in onewirehub.devices: + family = device["family"] + device_type = device["type"] + sensor_id = os.path.split(os.path.split(device["path"])[0])[1] dev_type = "std" if "EF" in family: dev_type = "HobbyBoard" - family = owproxy.read(f"{device}type").decode() + family = device_type if family not in hb_info_from_type(dev_type): _LOGGER.warning( "Ignoring unknown family (%s) of sensor found for device: %s", family, - device, + sensor_id, ) continue - for sensor_key, sensor_value in hb_info_from_type(dev_type)[family].items(): - if "moisture" in sensor_key: - s_id = sensor_key.split("_")[1] + device_info = { + "identifiers": {(DOMAIN, sensor_id)}, + "manufacturer": "Maxim Integrated", + "model": device_type, + "name": sensor_id, + } + for device_sensor in hb_info_from_type(dev_type)[family]: + if device_sensor["type"] == SENSOR_TYPE_MOISTURE: + s_id = device_sensor["path"].split(".")[1] is_leaf = int( - owproxy.read(f"{device}moisture/is_leaf.{s_id}").decode() + onewirehub.owproxy.read( + f"{device['path']}moisture/is_leaf.{s_id}" + ).decode() ) if is_leaf: - sensor_key = f"wetness_{s_id}" - sensor_id = os.path.split(os.path.split(device)[0])[1] - device_file = os.path.join(os.path.split(device)[0], sensor_value) + device_sensor["type"] = SENSOR_TYPE_WETNESS + device_sensor["name"] = f"Wetness {s_id}" + device_file = os.path.join( + os.path.split(device["path"])[0], device_sensor["path"] + ) entities.append( - OneWireProxy( + OneWireProxySensor( device_names.get(sensor_id, sensor_id), device_file, - sensor_key, - owproxy, + device_sensor["type"], + device_sensor["name"], + device_info, + device_sensor.get("default_disabled", False), + onewirehub.owproxy, ) ) # We have a raw GPIO ow sensor on a Pi elif conf_type == CONF_TYPE_SYSBUS: - _LOGGER.debug("Initializing using SysBus") - for p1sensor in Pi1Wire().find_all_sensors(): + base_dir = config[CONF_MOUNT_DIR] + _LOGGER.debug("Initializing using SysBus %s", base_dir) + for p1sensor in onewirehub.devices: family = p1sensor.mac_address[:2] sensor_id = f"{family}-{p1sensor.mac_address[2:]}" if family not in DEVICE_SUPPORT_SYSBUS: @@ -212,12 +304,18 @@ def get_entities(config): ) continue + device_info = { + "identifiers": {(DOMAIN, sensor_id)}, + "manufacturer": "Maxim Integrated", + "model": family, + "name": sensor_id, + } device_file = f"/sys/bus/w1/devices/{sensor_id}/w1_slave" entities.append( - OneWireDirect( + OneWireDirectSensor( device_names.get(sensor_id, sensor_id), device_file, - "temperature", + device_info, p1sensor, ) ) @@ -232,6 +330,7 @@ def get_entities(config): else: # pragma: no cover # This part of the implementation does not conform to policy regarding 3rd-party libraries, and will not longer be updated. # https://developers.home-assistant.io/docs/creating_platform_code_review/#5-communication-with-devicesservices + base_dir = config[CONF_MOUNT_DIR] _LOGGER.debug("Initializing using OWFS %s", base_dir) _LOGGER.warning( "The OWFS implementation of 1-Wire sensors is deprecated, " @@ -252,7 +351,7 @@ def get_entities(config): os.path.split(family_file_path)[0], sensor_value ) entities.append( - OneWireOWFS( + OneWireOWFSSensor( device_names.get(sensor_id, sensor_id), device_file, sensor_key, @@ -262,80 +361,28 @@ def get_entities(config): return entities -class OneWire(Entity): - """Implementation of a 1-Wire sensor.""" - - def __init__(self, name, device_file, sensor_type): - """Initialize the sensor.""" - self._name = f"{name} {sensor_type.capitalize()}" - self._device_file = device_file - self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] - self._state = None - self._value_raw = None +class OneWireProxySensor(OneWireProxyEntity): + """Implementation of a 1-Wire sensor connected through owserver.""" @property - def name(self): - """Return the name of the sensor.""" - return self._name - - @property - def state(self): - """Return the state of the sensor.""" - if "count" in self._unit_of_measurement: - return int(self._state) + def state(self) -> StateType: + """Return the state of the entity.""" return self._state - @property - def unit_of_measurement(self): - """Return the unit the value is expressed in.""" - return self._unit_of_measurement - @property - def device_state_attributes(self): - """Return the state attributes of the sensor.""" - return {"device_file": self._device_file, "raw_value": self._value_raw} - - @property - def unique_id(self) -> str: - """Return a unique ID.""" - return self._device_file - - -class OneWireProxy(OneWire): - """Implementation of a 1-Wire sensor through owserver.""" - - def __init__(self, name, device_file, sensor_type, owproxy): - """Initialize the sensor.""" - super().__init__(name, device_file, sensor_type) - self._owproxy = owproxy - - def _read_value_ownet(self): - """Read a value from the owserver.""" - return self._owproxy.read(self._device_file).decode().lstrip() - - def update(self): - """Get the latest data from the device.""" - value = None - value_read = False - try: - value_read = self._read_value_ownet() - except protocol.Error as exc: - _LOGGER.error("Owserver failure in read(), got: %s", exc) - if value_read: - value = round(float(value_read), 1) - self._value_raw = float(value_read) - - self._state = value - - -class OneWireDirect(OneWire): +class OneWireDirectSensor(OneWireBaseEntity): """Implementation of a 1-Wire sensor directly connected to RPI GPIO.""" - def __init__(self, name, device_file, sensor_type, owsensor): + def __init__(self, name, device_file, device_info, owsensor): """Initialize the sensor.""" - super().__init__(name, device_file, sensor_type) + super().__init__(name, device_file, "temperature", "Temperature", device_info) self._owsensor = owsensor + @property + def state(self) -> StateType: + """Return the state of the entity.""" + return self._state + def update(self): """Get the latest data from the device.""" value = None @@ -351,13 +398,18 @@ class OneWireDirect(OneWire): self._state = value -class OneWireOWFS(OneWire): # pragma: no cover +class OneWireOWFSSensor(OneWireBaseEntity): # pragma: no cover """Implementation of a 1-Wire sensor through owfs. This part of the implementation does not conform to policy regarding 3rd-party libraries, and will not longer be updated. https://developers.home-assistant.io/docs/creating_platform_code_review/#5-communication-with-devicesservices """ + @property + def state(self) -> StateType: + """Return the state of the entity.""" + return self._state + def _read_value_raw(self): """Read the value as it is returned by the sensor.""" with open(self._device_file) as ds_device_file: diff --git a/homeassistant/components/onewire/strings.json b/homeassistant/components/onewire/strings.json new file mode 100644 index 00000000000..928907b319a --- /dev/null +++ b/homeassistant/components/onewire/strings.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + }, + "error": { + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "invalid_path": "Directory not found." + }, + "step": { + "owserver": { + "data": { + "host": "[%key:common::config_flow::data::host%]", + "port": "[%key:common::config_flow::data::port%]" + }, + "title": "Set owserver details" + }, + "user": { + "data": { + "type": "Connection type" + }, + "title": "Set up 1-Wire" + } + } + } +} diff --git a/homeassistant/components/onewire/switch.py b/homeassistant/components/onewire/switch.py new file mode 100644 index 00000000000..f1b588690ae --- /dev/null +++ b/homeassistant/components/onewire/switch.py @@ -0,0 +1,204 @@ +"""Support for 1-Wire environment switches.""" +import logging +import os + +from homeassistant.components.switch import SwitchEntity +from homeassistant.const import CONF_TYPE + +from .const import CONF_TYPE_OWSERVER, DOMAIN, SWITCH_TYPE_LATCH, SWITCH_TYPE_PIO +from .onewire_entities import OneWireProxyEntity +from .onewirehub import OneWireHub + +DEVICE_SWITCHES = { + # Family : { owfs path } + "12": [ + { + "path": "PIO.A", + "name": "PIO A", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "PIO.B", + "name": "PIO B", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "latch.A", + "name": "Latch A", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + { + "path": "latch.B", + "name": "Latch B", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + ], + "29": [ + { + "path": "PIO.0", + "name": "PIO 0", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "PIO.1", + "name": "PIO 1", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "PIO.2", + "name": "PIO 2", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "PIO.3", + "name": "PIO 3", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "PIO.4", + "name": "PIO 4", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "PIO.5", + "name": "PIO 5", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "PIO.6", + "name": "PIO 6", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "PIO.7", + "name": "PIO 7", + "type": SWITCH_TYPE_PIO, + "default_disabled": True, + }, + { + "path": "latch.0", + "name": "Latch 0", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + { + "path": "latch.1", + "name": "Latch 1", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + { + "path": "latch.2", + "name": "Latch 2", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + { + "path": "latch.3", + "name": "Latch 3", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + { + "path": "latch.4", + "name": "Latch 4", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + { + "path": "latch.5", + "name": "Latch 5", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + { + "path": "latch.6", + "name": "Latch 6", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + { + "path": "latch.7", + "name": "Latch 7", + "type": SWITCH_TYPE_LATCH, + "default_disabled": True, + }, + ], +} + +LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up 1-Wire platform.""" + # Only OWServer implementation works with switches + if config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER: + onewirehub = hass.data[DOMAIN][config_entry.unique_id] + + entities = await hass.async_add_executor_job(get_entities, onewirehub) + async_add_entities(entities, True) + + +def get_entities(onewirehub: OneWireHub): + """Get a list of entities.""" + entities = [] + + for device in onewirehub.devices: + family = device["family"] + device_type = device["type"] + sensor_id = os.path.split(os.path.split(device["path"])[0])[1] + + if family not in DEVICE_SWITCHES: + continue + + device_info = { + "identifiers": {(DOMAIN, sensor_id)}, + "manufacturer": "Maxim Integrated", + "model": device_type, + "name": sensor_id, + } + for device_switch in DEVICE_SWITCHES[family]: + device_file = os.path.join( + os.path.split(device["path"])[0], device_switch["path"] + ) + entities.append( + OneWireProxySwitch( + sensor_id, + device_file, + device_switch["type"], + device_switch["name"], + device_info, + device_switch.get("default_disabled", False), + onewirehub.owproxy, + ) + ) + + return entities + + +class OneWireProxySwitch(OneWireProxyEntity, SwitchEntity): + """Implementation of a 1-Wire switch.""" + + @property + def is_on(self): + """Return true if sensor is on.""" + return self._state + + def turn_on(self, **kwargs) -> None: + """Turn the entity on.""" + self._write_value_ownet(b"1") + + def turn_off(self, **kwargs) -> None: + """Turn the entity off.""" + self._write_value_ownet(b"0") diff --git a/homeassistant/components/onewire/translations/af.json b/homeassistant/components/onewire/translations/af.json new file mode 100644 index 00000000000..779febe67cd --- /dev/null +++ b/homeassistant/components/onewire/translations/af.json @@ -0,0 +1,14 @@ +{ + "config": { + "error": { + "invalid_path": "Verzeichnis nicht gefunden." + }, + "step": { + "user": { + "data": { + "type": "Verbindungstyp" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/ca.json b/homeassistant/components/onewire/translations/ca.json new file mode 100644 index 00000000000..73c6cb0991e --- /dev/null +++ b/homeassistant/components/onewire/translations/ca.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "El dispositiu ja est\u00e0 configurat" + }, + "error": { + "cannot_connect": "Ha fallat la connexi\u00f3", + "invalid_path": "No s'ha trobat el directori." + }, + "step": { + "owserver": { + "data": { + "host": "Amfitri\u00f3", + "port": "Port" + }, + "title": "Defineix els detalls d'owserver" + }, + "user": { + "data": { + "type": "Tipus de connexi\u00f3" + }, + "title": "Configuraci\u00f3 d'1-Wire" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/cs.json b/homeassistant/components/onewire/translations/cs.json new file mode 100644 index 00000000000..c5298d095d8 --- /dev/null +++ b/homeassistant/components/onewire/translations/cs.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" + }, + "error": { + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", + "invalid_path": "Adres\u00e1\u0159 nebyl nalezen." + }, + "step": { + "owserver": { + "data": { + "host": "Hostitel", + "port": "Port" + }, + "title": "Nastaven\u00ed owserver" + }, + "user": { + "data": { + "type": "Typ p\u0159ipojen\u00ed" + }, + "title": "Nastaven\u00ed 1-Wire" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/de.json b/homeassistant/components/onewire/translations/de.json new file mode 100644 index 00000000000..3cc9f9cfc68 --- /dev/null +++ b/homeassistant/components/onewire/translations/de.json @@ -0,0 +1,21 @@ +{ + "config": { + "error": { + "cannot_connect": "Verbindung fehlgeschlagen", + "invalid_path": "Verzeichnis nicht gefunden." + }, + "step": { + "owserver": { + "data": { + "host": "Host", + "port": "Port" + } + }, + "user": { + "data": { + "type": "Verbindungstyp" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/en.json b/homeassistant/components/onewire/translations/en.json new file mode 100644 index 00000000000..ff4d1cb53b9 --- /dev/null +++ b/homeassistant/components/onewire/translations/en.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "Device is already configured" + }, + "error": { + "cannot_connect": "Failed to connect", + "invalid_path": "Directory not found." + }, + "step": { + "owserver": { + "data": { + "host": "Host", + "port": "Port" + }, + "title": "Set owserver details" + }, + "user": { + "data": { + "type": "Connection type" + }, + "title": "Set up 1-Wire" + } + } + } +} \ 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 00000000000..a2d8da218ba --- /dev/null +++ b/homeassistant/components/onewire/translations/es.json @@ -0,0 +1,26 @@ +{ + "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" + }, + "title": "Configurar los detalles del servidor" + }, + "user": { + "data": { + "type": "Tipo de conexi\u00f3n" + }, + "title": "Configurar 1 cable" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/et.json b/homeassistant/components/onewire/translations/et.json new file mode 100644 index 00000000000..175c26cebb5 --- /dev/null +++ b/homeassistant/components/onewire/translations/et.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "Seade on juba h\u00e4\u00e4lestatud" + }, + "error": { + "cannot_connect": "\u00dchendus nurjus", + "invalid_path": "Kausta ei leitud." + }, + "step": { + "owserver": { + "data": { + "host": "", + "port": "" + }, + "title": "M\u00e4\u00e4ra owserver-i \u00fcksikasjad" + }, + "user": { + "data": { + "type": "\u00dchenduse t\u00fc\u00fcp" + }, + "title": "Seadista 1-wire sidumine" + } + } + } +} \ 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 00000000000..13a5438b1a9 --- /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/onewire/translations/it.json b/homeassistant/components/onewire/translations/it.json new file mode 100644 index 00000000000..108cadc635e --- /dev/null +++ b/homeassistant/components/onewire/translations/it.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato" + }, + "error": { + "cannot_connect": "Impossibile connettersi", + "invalid_path": "Directory non trovata." + }, + "step": { + "owserver": { + "data": { + "host": "Host", + "port": "Porta" + }, + "title": "Impostare i dettagli dell'owserver" + }, + "user": { + "data": { + "type": "Tipo di connessione" + }, + "title": "Configurazione 1-Wire" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/lb.json b/homeassistant/components/onewire/translations/lb.json new file mode 100644 index 00000000000..c7c302ab683 --- /dev/null +++ b/homeassistant/components/onewire/translations/lb.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "already_configured": "Apparat ass scho konfigur\u00e9iert" + }, + "error": { + "cannot_connect": "Feeler beim verbannen", + "invalid_path": "Dossier net fonnt" + }, + "step": { + "owserver": { + "data": { + "host": "Host", + "port": "Port" + } + }, + "user": { + "data": { + "type": "Typ vun der Verbindung" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/nl.json b/homeassistant/components/onewire/translations/nl.json new file mode 100644 index 00000000000..8b2702b6708 --- /dev/null +++ b/homeassistant/components/onewire/translations/nl.json @@ -0,0 +1,7 @@ +{ + "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/no.json b/homeassistant/components/onewire/translations/no.json new file mode 100644 index 00000000000..b126349fb81 --- /dev/null +++ b/homeassistant/components/onewire/translations/no.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "Enheten er allerede konfigurert" + }, + "error": { + "cannot_connect": "Tilkobling mislyktes", + "invalid_path": "Finner ikke mappen" + }, + "step": { + "owserver": { + "data": { + "host": "Vert", + "port": "Port" + }, + "title": "Angi detaljer om owserver" + }, + "user": { + "data": { + "type": "Tilkoblingstype" + }, + "title": "Sett opp 1-Wire" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/pl.json b/homeassistant/components/onewire/translations/pl.json new file mode 100644 index 00000000000..e1200b968b8 --- /dev/null +++ b/homeassistant/components/onewire/translations/pl.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" + }, + "error": { + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", + "invalid_path": "Nie znaleziono katalogu" + }, + "step": { + "owserver": { + "data": { + "host": "Nazwa hosta lub adres IP", + "port": "Port" + }, + "title": "Ustawienia owserver" + }, + "user": { + "data": { + "type": "Rodzaj po\u0142\u0105czenia" + }, + "title": "Konfiguracja 1-Wire" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/ru.json b/homeassistant/components/onewire/translations/ru.json new file mode 100644 index 00000000000..4459607604b --- /dev/null +++ b/homeassistant/components/onewire/translations/ru.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." + }, + "error": { + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", + "invalid_path": "\u041a\u0430\u0442\u0430\u043b\u043e\u0433 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d." + }, + "step": { + "owserver": { + "data": { + "host": "\u0425\u043e\u0441\u0442", + "port": "\u041f\u043e\u0440\u0442" + }, + "title": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a owserver" + }, + "user": { + "data": { + "type": "\u0422\u0438\u043f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f" + }, + "title": "1-Wire" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/kodi/translations/sv.json b/homeassistant/components/onewire/translations/sv.json similarity index 62% rename from homeassistant/components/kodi/translations/sv.json rename to homeassistant/components/onewire/translations/sv.json index bb3424b4d45..e5717348568 100644 --- a/homeassistant/components/kodi/translations/sv.json +++ b/homeassistant/components/onewire/translations/sv.json @@ -1,9 +1,9 @@ { "config": { "step": { - "host": { + "owserver": { "data": { - "ssl": "Anslut med SSL" + "port": "Port" } } } diff --git a/homeassistant/components/onewire/translations/zh-Hans.json b/homeassistant/components/onewire/translations/zh-Hans.json new file mode 100644 index 00000000000..2941dfd9383 --- /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/onewire/translations/zh-Hant.json b/homeassistant/components/onewire/translations/zh-Hant.json new file mode 100644 index 00000000000..acafb6eee4b --- /dev/null +++ b/homeassistant/components/onewire/translations/zh-Hant.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + }, + "error": { + "cannot_connect": "\u9023\u7dda\u5931\u6557", + "invalid_path": "\u672a\u627e\u5230\u8a2d\u5099\u3002" + }, + "step": { + "owserver": { + "data": { + "host": "\u4e3b\u6a5f\u7aef", + "port": "\u901a\u8a0a\u57e0" + }, + "title": "\u8a2d\u5b9a owserver \u8a73\u7d30\u8cc7\u6599" + }, + "user": { + "data": { + "type": "\u9023\u7dda\u985e\u578b" + }, + "title": "\u8a2d\u5b9a 1-Wire" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onkyo/media_player.py b/homeassistant/components/onkyo/media_player.py index 54df7735f10..2cd4faaf314 100644 --- a/homeassistant/components/onkyo/media_player.py +++ b/homeassistant/components/onkyo/media_player.py @@ -299,8 +299,8 @@ class OnkyoDevice(MediaPlayerEntity): self._muted = bool(mute_raw[1] == "on") # AMP_VOL/MAX_RECEIVER_VOL*(MAX_VOL/100) - self._volume = ( - volume_raw[1] / self._receiver_max_volume * (self._max_volume / 100) + self._volume = volume_raw[1] / ( + self._receiver_max_volume * self._max_volume / 100 ) if not hdmi_out_raw: diff --git a/homeassistant/components/onvif/__init__.py b/homeassistant/components/onvif/__init__.py index 0a30173c7d7..c4fbdc3f40f 100644 --- a/homeassistant/components/onvif/__init__.py +++ b/homeassistant/components/onvif/__init__.py @@ -45,7 +45,7 @@ async def async_setup(hass: HomeAssistant, config: dict): continue config = p_config.copy() - if config[CONF_HOST] not in configs.keys(): + if config[CONF_HOST] not in configs: configs[config[CONF_HOST]] = { CONF_HOST: config[CONF_HOST], CONF_NAME: config.get(CONF_NAME, DEFAULT_NAME), diff --git a/homeassistant/components/onvif/device.py b/homeassistant/components/onvif/device.py index 8ede2ab24cd..599e6084581 100644 --- a/homeassistant/components/onvif/device.py +++ b/homeassistant/components/onvif/device.py @@ -386,7 +386,7 @@ class ONVIFDevice: # Guard against unsupported operation if not profile.ptz.relative: LOGGER.warning( - "ContinuousMove not supported on device '%s'", self.name + "RelativeMove not supported on device '%s'", self.name ) return @@ -403,7 +403,7 @@ class ONVIFDevice: # Guard against unsupported operation if not profile.ptz.absolute: LOGGER.warning( - "ContinuousMove not supported on device '%s'", self.name + "AbsoluteMove not supported on device '%s'", self.name ) return diff --git a/homeassistant/components/onvif/translations/ca.json b/homeassistant/components/onvif/translations/ca.json index 99701f4020b..a364552f9b7 100644 --- a/homeassistant/components/onvif/translations/ca.json +++ b/homeassistant/components/onvif/translations/ca.json @@ -8,8 +8,7 @@ "onvif_error": "Error durant la configuraci\u00f3 del dispositiu ONVIF. Consulta els registres per a m\u00e9s informaci\u00f3." }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_failed": "No s'ha pogut connectar al servei ONVIF amb les credencials proporcionades." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/cs.json b/homeassistant/components/onvif/translations/cs.json index 4b26acdb786..49e7dde324a 100644 --- a/homeassistant/components/onvif/translations/cs.json +++ b/homeassistant/components/onvif/translations/cs.json @@ -8,8 +8,7 @@ "onvif_error": "P\u0159i nastavov\u00e1n\u00ed za\u0159\u00edzen\u00ed ONVIF do\u0161lo k chyb\u011b. Dal\u0161\u00ed informace naleznete v protokolech." }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_failed": "Nelze se p\u0159ipojit ke slu\u017eb\u011b ONVIF s poskytnut\u00fdmi p\u0159ihla\u0161ovac\u00edmi \u00fadaji." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/de.json b/homeassistant/components/onvif/translations/de.json index 46aeb515716..25984ecf3e1 100644 --- a/homeassistant/components/onvif/translations/de.json +++ b/homeassistant/components/onvif/translations/de.json @@ -7,9 +7,6 @@ "no_mac": "Die eindeutige ID f\u00fcr das ONVIF-Ger\u00e4t konnte nicht konfiguriert werden.", "onvif_error": "Fehler beim Einrichten des ONVIF-Ger\u00e4ts. \u00dcberpr\u00fcfen Sie die Protokolle auf weitere Informationen." }, - "error": { - "connection_failed": "Es konnte keine Verbindung zum ONVIF-Dienst mit den angegebenen Anmeldeinformationen hergestellt werden." - }, "step": { "auth": { "data": { diff --git a/homeassistant/components/onvif/translations/en.json b/homeassistant/components/onvif/translations/en.json index e414d5a6d8d..f52b96fbdc5 100644 --- a/homeassistant/components/onvif/translations/en.json +++ b/homeassistant/components/onvif/translations/en.json @@ -8,8 +8,7 @@ "onvif_error": "Error setting up ONVIF device. Check logs for more information." }, "error": { - "cannot_connect": "Failed to connect", - "connection_failed": "Could not connect to ONVIF service with provided credentials." + "cannot_connect": "Failed to connect" }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/es-419.json b/homeassistant/components/onvif/translations/es-419.json index 823f1d15880..d0db75beb96 100644 --- a/homeassistant/components/onvif/translations/es-419.json +++ b/homeassistant/components/onvif/translations/es-419.json @@ -7,9 +7,6 @@ "no_mac": "No se pudo configurar una identificaci\u00f3n \u00fanica para el dispositivo ONVIF.", "onvif_error": "Error al configurar el dispositivo ONVIF. Consulte los registros para obtener m\u00e1s informaci\u00f3n." }, - "error": { - "connection_failed": "No se pudo conectar al servicio ONVIF con las credenciales proporcionadas." - }, "step": { "auth": { "data": { diff --git a/homeassistant/components/onvif/translations/es.json b/homeassistant/components/onvif/translations/es.json index 9cb854b5988..4f75a639ee5 100644 --- a/homeassistant/components/onvif/translations/es.json +++ b/homeassistant/components/onvif/translations/es.json @@ -8,8 +8,7 @@ "onvif_error": "Error de configuraci\u00f3n del dispositivo ONVIF. Revise los registros para m\u00e1s informaci\u00f3n." }, "error": { - "cannot_connect": "No se pudo conectar", - "connection_failed": "No se pudo conectar al servicio ONVIF con las credenciales proporcionadas." + "cannot_connect": "No se pudo conectar" }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/et.json b/homeassistant/components/onvif/translations/et.json index 2a9e9b23408..9ba14ffaa52 100644 --- a/homeassistant/components/onvif/translations/et.json +++ b/homeassistant/components/onvif/translations/et.json @@ -2,7 +2,10 @@ "config": { "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "already_in_progress": "Seadistamine on juba k\u00e4imas" + "already_in_progress": "Seadistamine on juba k\u00e4imas", + "no_h264": "H264 vooge pole saadaval. Kontrollie oma seadme profiili seadeid.", + "no_mac": "ONVIF-seadme unikaalset ID-d ei \u00f5nnestunud konfigureerida.", + "onvif_error": "T\u00f5rge ONVIF-seadme seadistamisel. Lisateabe saamiseks kontrolli logisid." }, "error": { "cannot_connect": "\u00dchendamine nurjus" @@ -12,18 +15,44 @@ "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "Autentimise seadistamine" + }, + "configure_profile": { + "data": { + "include": "Loo kaamera olem" + }, + "description": "Kas loon {profile} jaoks kaamera olem eraldusv\u00f5imega {resolution}?", + "title": "Profiilide seadistamine" }, "device": { "data": { "host": "Vali avastatud ONVIF seade" - } + }, + "title": "Vali ONVIF-seade" }, "manual_input": { "data": { "host": "", + "name": "Nimi", "port": "" - } + }, + "title": "H\u00e4\u00e4lesta ONVIF-seade" + }, + "user": { + "description": "Kl\u00f5psates nuppu Esita, otsime v\u00f5rgust ONVIF-seadmeid, mis toetavad Profile S'i.\n\n M\u00f5ned tootjad on ONVIF-i vaikimisi keelanud. Veendu, et ONVIF on kaamera seadistustes lubatud.", + "title": "ONVIF-seadme seadistamine" + } + } + }, + "options": { + "step": { + "onvif_devices": { + "data": { + "extra_arguments": "T\u00e4iendavad FFMPEG argumendid", + "rtsp_transport": "RTSP edastusviis" + }, + "title": "ONVIF-seadme suvandid" } } } diff --git a/homeassistant/components/onvif/translations/fr.json b/homeassistant/components/onvif/translations/fr.json index 2fa433d7441..d8d1cf89611 100644 --- a/homeassistant/components/onvif/translations/fr.json +++ b/homeassistant/components/onvif/translations/fr.json @@ -8,7 +8,7 @@ "onvif_error": "Erreur lors de la configuration du p\u00e9riph\u00e9rique ONVIF. Consultez les journaux pour plus d'informations." }, "error": { - "connection_failed": "Impossible de se connecter au service ONVIF avec les informations d'identification fournies." + "cannot_connect": "\u00c9chec de connexion" }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/it.json b/homeassistant/components/onvif/translations/it.json index 2183945d680..118af410974 100644 --- a/homeassistant/components/onvif/translations/it.json +++ b/homeassistant/components/onvif/translations/it.json @@ -8,8 +8,7 @@ "onvif_error": "Errore durante la configurazione del dispositivo ONVIF. Controllare i registri per ulteriori informazioni." }, "error": { - "cannot_connect": "Impossibile connettersi", - "connection_failed": "Impossibile connettersi al servizio ONVIF con le credenziali fornite." + "cannot_connect": "Impossibile connettersi" }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/ko.json b/homeassistant/components/onvif/translations/ko.json index 5619a6daa2b..3b992e8d35f 100644 --- a/homeassistant/components/onvif/translations/ko.json +++ b/homeassistant/components/onvif/translations/ko.json @@ -7,9 +7,6 @@ "no_mac": "ONVIF \uae30\uae30\uc758 \uace0\uc720 ID \ub97c \uad6c\uc131\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", "onvif_error": "ONVIF \uae30\uae30 \uc124\uc815 \uc911 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \uc790\uc138\ud55c \ub0b4\uc6a9\uc740 \ub85c\uadf8\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694." }, - "error": { - "connection_failed": "\uc785\ub825\ud558\uc2e0 \uc790\uaca9 \uc99d\uba85\uc73c\ub85c ONVIF \uc11c\ube44\uc2a4\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." - }, "step": { "auth": { "data": { diff --git a/homeassistant/components/onvif/translations/lb.json b/homeassistant/components/onvif/translations/lb.json index b13e6836384..f9b2843b5cb 100644 --- a/homeassistant/components/onvif/translations/lb.json +++ b/homeassistant/components/onvif/translations/lb.json @@ -8,8 +8,7 @@ "onvif_error": "Feeler beim ariichten vum ONVIF Apparat. Kuck d'Logs fir m\u00e9i Informatiounen." }, "error": { - "cannot_connect": "Feeler beim verbannen", - "connection_failed": "Konnt sech net mam ONVIF Service mat den ugebueden Umeldungsinformatiounen verbannen." + "cannot_connect": "Feeler beim verbannen" }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/nl.json b/homeassistant/components/onvif/translations/nl.json index deb2ba42c5f..4d76e939af0 100644 --- a/homeassistant/components/onvif/translations/nl.json +++ b/homeassistant/components/onvif/translations/nl.json @@ -1,7 +1,11 @@ { "config": { "abort": { - "already_configured": "Apparaat is al geconfigureerd" + "already_configured": "Apparaat is al geconfigureerd", + "already_in_progress": "De configuratiestroom is al begonnen", + "no_h264": "Er waren geen H264-streams beschikbaar. Controleer de profielconfiguratie op uw apparaat.", + "no_mac": "Kan geen unieke ID configureren voor ONVIF-apparaat.", + "onvif_error": "Fout bij het instellen van ONVIF-apparaat. Controleer de logboeken voor meer informatie." }, "error": { "cannot_connect": "Kan geen verbinding maken" @@ -18,20 +22,36 @@ "data": { "include": "Cameraentiteit maken" }, + "description": "Camera-entiteit maken voor {profile} met {resolution} resolutie?", "title": "Configureer profielen" }, + "device": { + "data": { + "host": "Selecteer het ontdekte ONVIF-apparaat" + }, + "title": "Selecteer ONVIF-apparaat" + }, "manual_input": { "data": { "host": "Host", "name": "Naam", "port": "Poort" - } + }, + "title": "Configureer ONVIF-apparaat" + }, + "user": { + "description": "Door op verzenden te klikken, zoeken we in uw netwerk naar ONVIF-apparaten die Profiel S ondersteunen. \n\nSommige fabrikanten zijn begonnen ONVIF standaard uit te schakelen. Zorg ervoor dat ONVIF is ingeschakeld in de configuratie van uw camera.", + "title": "ONVIF-apparaat instellen" } } }, "options": { "step": { "onvif_devices": { + "data": { + "extra_arguments": "Extra FFMPEG argumenten", + "rtsp_transport": "RTSP-transportmechanisme" + }, "title": "[%%] Apparaatopties" } } diff --git a/homeassistant/components/onvif/translations/no.json b/homeassistant/components/onvif/translations/no.json index 39ea140d836..e30f4e4e909 100644 --- a/homeassistant/components/onvif/translations/no.json +++ b/homeassistant/components/onvif/translations/no.json @@ -8,8 +8,7 @@ "onvif_error": "Feil ved konfigurering av ONVIF-enhet. Sjekk logger for mer informasjon." }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "connection_failed": "Kan ikke koble til ONVIF-tjenesten med angitt legitimasjon." + "cannot_connect": "Tilkobling mislyktes" }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/pl.json b/homeassistant/components/onvif/translations/pl.json index 3baf940cbd6..2d2f55728ad 100644 --- a/homeassistant/components/onvif/translations/pl.json +++ b/homeassistant/components/onvif/translations/pl.json @@ -8,8 +8,7 @@ "onvif_error": "Wyst\u0105pi\u0142 b\u0142\u0105d podczas konfigurowania urz\u0105dzenia ONVIF. Sprawd\u017a logi, aby uzyska\u0107 wi\u0119cej informacji." }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_failed": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z us\u0142ug\u0105 ONVIF z podanymi po\u015bwiadczeniami" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "auth": { @@ -17,14 +16,14 @@ "password": "Has\u0142o", "username": "Nazwa u\u017cytkownika" }, - "title": "Konfigurowanie uwierzytelniania" + "title": "Konfiguracja uwierzytelniania" }, "configure_profile": { "data": { "include": "Utw\u00f3rz encj\u0119 kamery" }, "description": "Czy utworzy\u0107 encj\u0119 kamery dla {profile} o rozdzielczo\u015bci {resolution}?", - "title": "Konfigurowanie profili" + "title": "Konfiguracja profili" }, "device": { "data": { @@ -38,7 +37,7 @@ "name": "Nazwa", "port": "Port" }, - "title": "Konfigurowanie urz\u0105dzenia ONVIF" + "title": "Konfiguracja urz\u0105dzenia ONVIF" }, "user": { "description": "Klikaj\u0105c przycisk Zatwierd\u017a, Twoja sie\u0107 zostanie przeszukana pod k\u0105tem urz\u0105dze\u0144 ONVIF obs\u0142uguj\u0105cych profil S.\n\nNiekt\u00f3rzy producenci zacz\u0119li domy\u015blnie wy\u0142\u0105cza\u0107 ONVIF. Upewnij si\u0119, \u017ce ONVIF jest w\u0142\u0105czony w konfiguracji kamery.", diff --git a/homeassistant/components/onvif/translations/pt-BR.json b/homeassistant/components/onvif/translations/pt-BR.json index 5f2cce217ea..3304203c57a 100644 --- a/homeassistant/components/onvif/translations/pt-BR.json +++ b/homeassistant/components/onvif/translations/pt-BR.json @@ -7,9 +7,6 @@ "no_mac": "N\u00e3o foi poss\u00edvel configurar um ID \u00fanico para o dispositivo ONVIF.", "onvif_error": "Erro ao configurar o dispositivo ONVIF. Verifique os logs para obter mais informa\u00e7\u00f5es." }, - "error": { - "connection_failed": "N\u00e3o foi poss\u00edvel conectar ao servi\u00e7o ONVIF com as credenciais fornecidas." - }, "step": { "auth": { "data": { diff --git a/homeassistant/components/onvif/translations/pt.json b/homeassistant/components/onvif/translations/pt.json index a0678fa6916..cfc92a512d4 100644 --- a/homeassistant/components/onvif/translations/pt.json +++ b/homeassistant/components/onvif/translations/pt.json @@ -7,9 +7,6 @@ "no_mac": "N\u00e3o foi poss\u00edvel configurar o ID unico para o dispositivo ONVIF.", "onvif_error": "Erro ao configurar o dispositivo ONVIF. Verifique os logs para obter mais informa\u00e7\u00f5es." }, - "error": { - "connection_failed": "N\u00e3o foi poss\u00edvel ligar ao servi\u00e7o ONVIF com as credenciais fornecidas." - }, "step": { "auth": { "data": { diff --git a/homeassistant/components/onvif/translations/ru.json b/homeassistant/components/onvif/translations/ru.json index 7d6cd66f8cd..823dd8eb7fd 100644 --- a/homeassistant/components/onvif/translations/ru.json +++ b/homeassistant/components/onvif/translations/ru.json @@ -8,8 +8,7 @@ "onvif_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043b\u043e\u0433\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u043b\u0443\u0436\u0431\u0435 ONVIF \u0441 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0443\u0447\u0435\u0442\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "auth": { diff --git a/homeassistant/components/onvif/translations/sl.json b/homeassistant/components/onvif/translations/sl.json index f7e2df98556..37994d88e14 100644 --- a/homeassistant/components/onvif/translations/sl.json +++ b/homeassistant/components/onvif/translations/sl.json @@ -7,9 +7,6 @@ "no_mac": "Edinstvenega ID-ja za napravo ONVIF ni bilo mogo\u010de konfigurirati.", "onvif_error": "Napaka pri nastavitvi naprave ONVIF. Za ve\u010d informacij preverite dnevnike." }, - "error": { - "connection_failed": "Ni bilo mogo\u010de povezati s storitvijo ONVIF s predlo\u017eenimi poverilnicami." - }, "step": { "auth": { "data": { diff --git a/homeassistant/components/onvif/translations/tr.json b/homeassistant/components/onvif/translations/tr.json index 7a22e22a4aa..4e3ad18a60d 100644 --- a/homeassistant/components/onvif/translations/tr.json +++ b/homeassistant/components/onvif/translations/tr.json @@ -10,7 +10,7 @@ "step": { "onvif_devices": { "data": { - "extra_arguments": "Ekstra FFMPEG arg\u00fcmanlar", + "extra_arguments": "Ekstra FFMPEG arg\u00fcmanlar\u0131", "rtsp_transport": "RTSP ta\u015f\u0131ma mekanizmas\u0131" }, "title": "ONVIF Cihaz Se\u00e7enekleri" diff --git a/homeassistant/components/onvif/translations/zh-Hans.json b/homeassistant/components/onvif/translations/zh-Hans.json index b6ad5c30a77..0a0b6db3d38 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/onvif/translations/zh-Hant.json b/homeassistant/components/onvif/translations/zh-Hant.json index a5349f2148e..6541d8accde 100644 --- a/homeassistant/components/onvif/translations/zh-Hant.json +++ b/homeassistant/components/onvif/translations/zh-Hant.json @@ -8,8 +8,7 @@ "onvif_error": "\u8a2d\u5b9a ONVIF \u8a2d\u5099\u932f\u8aa4\uff0c\u8acb\u53c3\u95b1\u65e5\u8a8c\u4ee5\u7372\u5f97\u66f4\u8a73\u7d30\u8cc7\u8a0a\u3002" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_failed": "\u7121\u6cd5\u4ee5\u6240\u63d0\u4f9b\u7684\u6191\u8b49\u9023\u7dda\u81f3 ONVIF \u670d\u52d9\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "auth": { diff --git a/homeassistant/components/openerz/manifest.json b/homeassistant/components/openerz/manifest.json index 7f56e2b8c55..9fa696a873a 100644 --- a/homeassistant/components/openerz/manifest.json +++ b/homeassistant/components/openerz/manifest.json @@ -2,7 +2,6 @@ "domain": "openerz", "name": "Open ERZ", "documentation": "https://www.home-assistant.io/integrations/openerz", - "dependencies": [], "codeowners": ["@misialq"], "requirements": ["openerz-api==0.1.0"] } diff --git a/homeassistant/components/opentherm_gw/climate.py b/homeassistant/components/opentherm_gw/climate.py index 64625541352..237733e6870 100644 --- a/homeassistant/components/opentherm_gw/climate.py +++ b/homeassistant/components/opentherm_gw/climate.py @@ -33,7 +33,6 @@ from .const import CONF_FLOOR_TEMP, CONF_PRECISION, DATA_GATEWAYS, DATA_OPENTHER _LOGGER = logging.getLogger(__name__) DEFAULT_FLOOR_TEMP = False -DEFAULT_PRECISION = None SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE @@ -62,7 +61,7 @@ class OpenThermClimate(ClimateEntity): ) self.friendly_name = gw_dev.name self.floor_temp = options.get(CONF_FLOOR_TEMP, DEFAULT_FLOOR_TEMP) - self.temp_precision = options.get(CONF_PRECISION, DEFAULT_PRECISION) + self.temp_precision = options.get(CONF_PRECISION) self._available = False self._current_operation = None self._current_temperature = None @@ -177,7 +176,7 @@ class OpenThermClimate(ClimateEntity): @property def precision(self): """Return the precision of the system.""" - if self.temp_precision is not None: + if self.temp_precision is not None and self.temp_precision != 0: return self.temp_precision if self.hass.config.units.temperature_unit == TEMP_CELSIUS: return PRECISION_HALVES diff --git a/homeassistant/components/opentherm_gw/config_flow.py b/homeassistant/components/opentherm_gw/config_flow.py index 4afc508b8ee..59f14ab2ee5 100644 --- a/homeassistant/components/opentherm_gw/config_flow.py +++ b/homeassistant/components/opentherm_gw/config_flow.py @@ -58,10 +58,8 @@ class OpenThermGwConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): try: res = await asyncio.wait_for(test_connection(), timeout=10) - except asyncio.TimeoutError: - return self._show_form({"base": "timeout"}) - except SerialException: - return self._show_form({"base": "serial_error"}) + except (asyncio.TimeoutError, SerialException): + return self._show_form({"base": "cannot_connect"}) if res: return self._create_entry(gw_id, name, device) @@ -116,8 +114,6 @@ class OpenThermGwOptionsFlow(config_entries.OptionsFlow): async def async_step_init(self, user_input=None): """Manage the opentherm_gw options.""" if user_input is not None: - if user_input.get(CONF_PRECISION) == 0: - user_input[CONF_PRECISION] = None return self.async_create_entry(title="", data=user_input) return self.async_show_form( diff --git a/homeassistant/components/opentherm_gw/strings.json b/homeassistant/components/opentherm_gw/strings.json index 332b97eb5ee..306529e7be1 100644 --- a/homeassistant/components/opentherm_gw/strings.json +++ b/homeassistant/components/opentherm_gw/strings.json @@ -11,10 +11,9 @@ } }, "error": { - "already_configured": "Gateway already configured", + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "id_exists": "Gateway id already exists", - "serial_error": "Error connecting to device", - "timeout": "Connection attempt timed out" + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" } }, "options": { diff --git a/homeassistant/components/opentherm_gw/translations/af.json b/homeassistant/components/opentherm_gw/translations/af.json new file mode 100644 index 00000000000..6b9d85fd9fb --- /dev/null +++ b/homeassistant/components/opentherm_gw/translations/af.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "cannot_connect": "Verbindung fehlgeschlagen" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/opentherm_gw/translations/bg.json b/homeassistant/components/opentherm_gw/translations/bg.json index 5d23794c07b..fbcaed52db5 100644 --- a/homeassistant/components/opentherm_gw/translations/bg.json +++ b/homeassistant/components/opentherm_gw/translations/bg.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "\u0428\u043b\u044e\u0437\u044a\u0442 \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d", - "id_exists": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440a \u043d\u0430 \u0448\u043b\u044e\u0437\u0430 \u0432\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430", - "serial_error": "\u0413\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e", - "timeout": "\u0412\u0440\u0435\u043c\u0435\u0442\u043e \u0437\u0430 \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0438\u0437\u0442\u0435\u0447\u0435" + "id_exists": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440a \u043d\u0430 \u0448\u043b\u044e\u0437\u0430 \u0432\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/ca.json b/homeassistant/components/opentherm_gw/translations/ca.json index 6660c93767e..1da9bbb584e 100644 --- a/homeassistant/components/opentherm_gw/translations/ca.json +++ b/homeassistant/components/opentherm_gw/translations/ca.json @@ -1,10 +1,9 @@ { "config": { "error": { - "already_configured": "Passarel\u00b7la ja configurada", - "id_exists": "L'identificador de passarel\u00b7la ja existeix", - "serial_error": "S'ha produ\u00eft un error en connectar-se al dispositiu", - "timeout": "S'ha acabat el temps d'espera en l'intent de connexi\u00f3" + "already_configured": "El dispositiu ja est\u00e0 configurat", + "cannot_connect": "Ha fallat la connexi\u00f3", + "id_exists": "L'identificador de passarel\u00b7la ja existeix" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/cs.json b/homeassistant/components/opentherm_gw/translations/cs.json index 09d03116635..1b497fcf396 100644 --- a/homeassistant/components/opentherm_gw/translations/cs.json +++ b/homeassistant/components/opentherm_gw/translations/cs.json @@ -1,10 +1,9 @@ { "config": { "error": { - "already_configured": "Br\u00e1na je ji\u017e nastavena", - "id_exists": "ID br\u00e1ny ji\u017e existuje", - "serial_error": "Chyba p\u0159i p\u0159ipojov\u00e1n\u00ed k za\u0159\u00edzen\u00ed", - "timeout": "\u010casov\u00fd limit p\u0159ipojen\u00ed vypr\u0161el" + "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", + "id_exists": "ID br\u00e1ny ji\u017e existuje" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/da.json b/homeassistant/components/opentherm_gw/translations/da.json index 25006b481b1..efc2262b415 100644 --- a/homeassistant/components/opentherm_gw/translations/da.json +++ b/homeassistant/components/opentherm_gw/translations/da.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Gateway allerede konfigureret", - "id_exists": "Gateway-id findes allerede", - "serial_error": "Fejl ved tilslutning til enheden", - "timeout": "Forbindelsesfors\u00f8g fik timeout" + "id_exists": "Gateway-id findes allerede" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/de.json b/homeassistant/components/opentherm_gw/translations/de.json index 1533e586514..6e8d02bc792 100644 --- a/homeassistant/components/opentherm_gw/translations/de.json +++ b/homeassistant/components/opentherm_gw/translations/de.json @@ -2,9 +2,8 @@ "config": { "error": { "already_configured": "Gateway bereits konfiguriert", - "id_exists": "Gateway-ID ist bereits vorhanden", - "serial_error": "Fehler beim Verbinden mit dem Ger\u00e4t", - "timeout": "Zeit\u00fcberschreitung beim Verbindungsversuch" + "cannot_connect": "Verbindung fehlgeschlagen", + "id_exists": "Gateway-ID ist bereits vorhanden" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/en.json b/homeassistant/components/opentherm_gw/translations/en.json index 17d259ad1d1..9d74a168bae 100644 --- a/homeassistant/components/opentherm_gw/translations/en.json +++ b/homeassistant/components/opentherm_gw/translations/en.json @@ -1,10 +1,9 @@ { "config": { "error": { - "already_configured": "Gateway already configured", - "id_exists": "Gateway id already exists", - "serial_error": "Error connecting to device", - "timeout": "Connection attempt timed out" + "already_configured": "Device is already configured", + "cannot_connect": "Failed to connect", + "id_exists": "Gateway id already exists" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/es-419.json b/homeassistant/components/opentherm_gw/translations/es-419.json index 9338998d377..935be180777 100644 --- a/homeassistant/components/opentherm_gw/translations/es-419.json +++ b/homeassistant/components/opentherm_gw/translations/es-419.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Gateway ya configurado", - "id_exists": "La identificaci\u00f3n de la puerta ya existe", - "serial_error": "Error al conectarse al dispositivo", - "timeout": "Tiempo de intento de conexi\u00f3n agotado" + "id_exists": "La identificaci\u00f3n de la puerta ya existe" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/es.json b/homeassistant/components/opentherm_gw/translations/es.json index 73918a9e8a9..44b6c6dfabc 100644 --- a/homeassistant/components/opentherm_gw/translations/es.json +++ b/homeassistant/components/opentherm_gw/translations/es.json @@ -2,9 +2,8 @@ "config": { "error": { "already_configured": "Gateway ya configurado", - "id_exists": "El ID del Gateway ya existe", - "serial_error": "Error de conexi\u00f3n al dispositivo", - "timeout": "Intento de conexi\u00f3n agotado" + "cannot_connect": "No se pudo conectar", + "id_exists": "El ID del Gateway ya existe" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/et.json b/homeassistant/components/opentherm_gw/translations/et.json index d20d1832961..4ab500e5531 100644 --- a/homeassistant/components/opentherm_gw/translations/et.json +++ b/homeassistant/components/opentherm_gw/translations/et.json @@ -1,7 +1,30 @@ { "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", + "id_exists": "L\u00fc\u00fcsi ID on juba olemas" + }, + "step": { + "init": { + "data": { + "device": "Rada v\u00f5i URL", + "id": "", + "name": "Nimi" + }, + "title": "" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "floor_temperature": "P\u00f5randa temperatuur", + "precision": "T\u00e4psus" + }, + "description": "OpenTherm Gateway suvandid" + } } } } \ No newline at end of file diff --git a/homeassistant/components/opentherm_gw/translations/fr.json b/homeassistant/components/opentherm_gw/translations/fr.json index 11cce45dcd7..f060503ea23 100644 --- a/homeassistant/components/opentherm_gw/translations/fr.json +++ b/homeassistant/components/opentherm_gw/translations/fr.json @@ -2,9 +2,8 @@ "config": { "error": { "already_configured": "Passerelle d\u00e9j\u00e0 configur\u00e9e", - "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" + "cannot_connect": "\u00c9chec de connexion", + "id_exists": "L'identifiant de la passerelle existe d\u00e9j\u00e0" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/hu.json b/homeassistant/components/opentherm_gw/translations/hu.json index 6ccdae6437c..c3dd3f10206 100644 --- a/homeassistant/components/opentherm_gw/translations/hu.json +++ b/homeassistant/components/opentherm_gw/translations/hu.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Az \u00e1tj\u00e1r\u00f3 m\u00e1r konfigur\u00e1lva van", - "id_exists": "Az \u00e1tj\u00e1r\u00f3 azonos\u00edt\u00f3ja m\u00e1r l\u00e9tezik", - "serial_error": "Hiba t\u00f6rt\u00e9nt az eszk\u00f6zh\u00f6z val\u00f3 csatlakoz\u00e1skor", - "timeout": "A csatlakoz\u00e1si k\u00eds\u00e9rletre sz\u00e1nt id\u0151 lej\u00e1rt" + "id_exists": "Az \u00e1tj\u00e1r\u00f3 azonos\u00edt\u00f3ja m\u00e1r l\u00e9tezik" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/it.json b/homeassistant/components/opentherm_gw/translations/it.json index f26e7998567..df1c36cd8d5 100644 --- a/homeassistant/components/opentherm_gw/translations/it.json +++ b/homeassistant/components/opentherm_gw/translations/it.json @@ -1,10 +1,9 @@ { "config": { "error": { - "already_configured": "Gateway gi\u00e0 configurato", - "id_exists": "ID del gateway esiste gi\u00e0", - "serial_error": "Errore durante la connessione al dispositivo", - "timeout": "Tentativo di connessione scaduto" + "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", + "cannot_connect": "Impossibile connettersi", + "id_exists": "ID del gateway esiste gi\u00e0" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/ko.json b/homeassistant/components/opentherm_gw/translations/ko.json index 27b3fd1cbd8..eece1492002 100644 --- a/homeassistant/components/opentherm_gw/translations/ko.json +++ b/homeassistant/components/opentherm_gw/translations/ko.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "OpenTherm Gateway \uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "id_exists": "OpenTherm Gateway id \uac00 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4", - "serial_error": "\uae30\uae30 \uc5f0\uacb0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4", - "timeout": "\uc5f0\uacb0 \uc2dc\ub3c4 \uc2dc\uac04\uc774 \ucd08\uacfc\ub418\uc5c8\uc2b5\ub2c8\ub2e4" + "id_exists": "OpenTherm Gateway id \uac00 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/lb.json b/homeassistant/components/opentherm_gw/translations/lb.json index 1ce0a275f1c..452ca69540f 100644 --- a/homeassistant/components/opentherm_gw/translations/lb.json +++ b/homeassistant/components/opentherm_gw/translations/lb.json @@ -1,10 +1,9 @@ { "config": { "error": { - "already_configured": "Gateway ass scho konfigur\u00e9iert", - "id_exists": "Gateway ID g\u00ebtt et schonn", - "serial_error": "Feeler beim verbannen", - "timeout": "Z\u00e4it Iwwerschreidung beim Verbindungs Versuch" + "already_configured": "Apparat ass scho konfigur\u00e9iert", + "cannot_connect": "Feeler beim verbannen", + "id_exists": "Gateway ID g\u00ebtt et schonn" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/nl.json b/homeassistant/components/opentherm_gw/translations/nl.json index 4b5fea8f312..7c9c89381e8 100644 --- a/homeassistant/components/opentherm_gw/translations/nl.json +++ b/homeassistant/components/opentherm_gw/translations/nl.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Gateway al geconfigureerd", - "id_exists": "Gateway id bestaat al", - "serial_error": "Fout bij het verbinden met het apparaat", - "timeout": "Er is een time-out opgetreden voor de verbindingspoging" + "id_exists": "Gateway id bestaat al" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/no.json b/homeassistant/components/opentherm_gw/translations/no.json index f0ecf0277b2..7789573a42e 100644 --- a/homeassistant/components/opentherm_gw/translations/no.json +++ b/homeassistant/components/opentherm_gw/translations/no.json @@ -1,10 +1,9 @@ { "config": { "error": { - "already_configured": "Gateway er allerede konfigurert", - "id_exists": "Gateway-ID finnes allerede", - "serial_error": "Feil ved tilkobling til enhet", - "timeout": "Tilkoblingsfors\u00f8k ble tidsavbrutt" + "already_configured": "Enheten er allerede konfigurert", + "cannot_connect": "Tilkobling mislyktes", + "id_exists": "Gateway-ID finnes allerede" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/pl.json b/homeassistant/components/opentherm_gw/translations/pl.json index dc14f383d41..3fe12393a14 100644 --- a/homeassistant/components/opentherm_gw/translations/pl.json +++ b/homeassistant/components/opentherm_gw/translations/pl.json @@ -2,9 +2,8 @@ "config": { "error": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "id_exists": "Identyfikator bramki ju\u017c istnieje", - "serial_error": "B\u0142\u0105d po\u0142\u0105czenia z urz\u0105dzeniem", - "timeout": "Przekroczono limit czasu pr\u00f3by po\u0142\u0105czenia" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", + "id_exists": "Identyfikator bramki ju\u017c istnieje" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/ru.json b/homeassistant/components/opentherm_gw/translations/ru.json index b81fe14497a..e63bfb58d95 100644 --- a/homeassistant/components/opentherm_gw/translations/ru.json +++ b/homeassistant/components/opentherm_gw/translations/ru.json @@ -1,10 +1,9 @@ { "config": { "error": { - "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0448\u043b\u044e\u0437\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "id_exists": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0448\u043b\u044e\u0437\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.", - "serial_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443.", - "timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f." + "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", + "id_exists": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0448\u043b\u044e\u0437\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442." }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/sl.json b/homeassistant/components/opentherm_gw/translations/sl.json index 5ab4b0145b0..fb8ed5cac6d 100644 --- a/homeassistant/components/opentherm_gw/translations/sl.json +++ b/homeassistant/components/opentherm_gw/translations/sl.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Prehod je \u017ee konfiguriran", - "id_exists": "ID prehoda \u017ee obstaja", - "serial_error": "Napaka pri povezovanju z napravo", - "timeout": "Poskus povezave je potekel" + "id_exists": "ID prehoda \u017ee obstaja" }, "step": { "init": { diff --git a/homeassistant/components/opentherm_gw/translations/sv.json b/homeassistant/components/opentherm_gw/translations/sv.json index 3b8cbf12ea0..6f21273b67c 100644 --- a/homeassistant/components/opentherm_gw/translations/sv.json +++ b/homeassistant/components/opentherm_gw/translations/sv.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Gateway redan konfigurerad", - "id_exists": "Gateway-id finns redan", - "serial_error": "Fel vid anslutning till enheten", - "timeout": "Anslutningsf\u00f6rs\u00f6ket avbr\u00f6ts" + "id_exists": "Gateway-id finns redan" }, "step": { "init": { 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 00000000000..7751b1f2f7d --- /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/opentherm_gw/translations/zh-Hant.json b/homeassistant/components/opentherm_gw/translations/zh-Hant.json index c938db307db..35099f2a59b 100644 --- a/homeassistant/components/opentherm_gw/translations/zh-Hant.json +++ b/homeassistant/components/opentherm_gw/translations/zh-Hant.json @@ -1,10 +1,9 @@ { "config": { "error": { - "already_configured": "\u9598\u9053\u5668\u5df2\u8a2d\u5b9a\u5b8c\u6210", - "id_exists": "\u9598\u9053\u5668 ID \u5df2\u5b58\u5728", - "serial_error": "\u9023\u7dda\u81f3\u8a2d\u5099\u932f\u8aa4", - "timeout": "\u9023\u7dda\u5617\u8a66\u903e\u6642" + "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", + "cannot_connect": "\u9023\u7dda\u5931\u6557", + "id_exists": "\u9598\u9053\u5668 ID \u5df2\u5b58\u5728" }, "step": { "init": { diff --git a/homeassistant/components/openuv/strings.json b/homeassistant/components/openuv/strings.json index d5dec9e0eed..f865aa1e621 100644 --- a/homeassistant/components/openuv/strings.json +++ b/homeassistant/components/openuv/strings.json @@ -5,14 +5,13 @@ "title": "Fill in your information", "data": { "api_key": "[%key:common::config_flow::data::api_key%]", - "elevation": "Elevation", + "elevation": "[%key:common::config_flow::data::elevation%]", "latitude": "[%key:common::config_flow::data::latitude%]", "longitude": "[%key:common::config_flow::data::longitude%]" } } }, "error": { - "identifier_exists": "Coordinates already registered", "invalid_api_key": "[%key:common::config_flow::error::invalid_api_key%]" }, "abort": { diff --git a/homeassistant/components/openuv/translations/bg.json b/homeassistant/components/openuv/translations/bg.json index 9677642266f..59cbf3d1c55 100644 --- a/homeassistant/components/openuv/translations/bg.json +++ b/homeassistant/components/openuv/translations/bg.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "\u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0438\u0442\u0435 \u0441\u0430 \u0432\u0435\u0447\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d\u0438", "invalid_api_key": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d API \u043a\u043b\u044e\u0447" }, "step": { diff --git a/homeassistant/components/openuv/translations/ca.json b/homeassistant/components/openuv/translations/ca.json index f55303e5c09..fbe163212f3 100644 --- a/homeassistant/components/openuv/translations/ca.json +++ b/homeassistant/components/openuv/translations/ca.json @@ -4,14 +4,13 @@ "already_configured": "La ubicaci\u00f3 ja est\u00e0 configurada" }, "error": { - "identifier_exists": "Les coordenades ja estan registrades", "invalid_api_key": "Clau API inv\u00e0lida" }, "step": { "user": { "data": { "api_key": "Clau API", - "elevation": "Elevaci\u00f3", + "elevation": "Altitud", "latitude": "Latitud", "longitude": "Longitud" }, diff --git a/homeassistant/components/openuv/translations/cs.json b/homeassistant/components/openuv/translations/cs.json index 64344c79d02..0a674b6aff6 100644 --- a/homeassistant/components/openuv/translations/cs.json +++ b/homeassistant/components/openuv/translations/cs.json @@ -4,7 +4,6 @@ "already_configured": "Um\u00edst\u011bn\u00ed je ji\u017e nastaveno" }, "error": { - "identifier_exists": "Sou\u0159adnice jsou ji\u017e zaregistrovan\u00e9", "invalid_api_key": "Neplatn\u00fd kl\u00ed\u010d API" }, "step": { diff --git a/homeassistant/components/openuv/translations/da.json b/homeassistant/components/openuv/translations/da.json index 6ff9546167e..0fdf9fb37b5 100644 --- a/homeassistant/components/openuv/translations/da.json +++ b/homeassistant/components/openuv/translations/da.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Koordinater er allerede registreret", "invalid_api_key": "Ugyldig API-n\u00f8gle" }, "step": { diff --git a/homeassistant/components/openuv/translations/de.json b/homeassistant/components/openuv/translations/de.json index 497955f9001..fae3f0f0620 100644 --- a/homeassistant/components/openuv/translations/de.json +++ b/homeassistant/components/openuv/translations/de.json @@ -4,7 +4,6 @@ "already_configured": "Diese Koordinaten sind bereits registriert." }, "error": { - "identifier_exists": "Koordinaten existieren bereits", "invalid_api_key": "Ung\u00fcltiger API-Schl\u00fcssel" }, "step": { diff --git a/homeassistant/components/openuv/translations/en.json b/homeassistant/components/openuv/translations/en.json index 052f5ca304e..6021c7a2030 100644 --- a/homeassistant/components/openuv/translations/en.json +++ b/homeassistant/components/openuv/translations/en.json @@ -4,7 +4,6 @@ "already_configured": "Location is already configured" }, "error": { - "identifier_exists": "Coordinates already registered", "invalid_api_key": "Invalid API key" }, "step": { diff --git a/homeassistant/components/openuv/translations/es-419.json b/homeassistant/components/openuv/translations/es-419.json index 158bb08b25d..1f135186dc2 100644 --- a/homeassistant/components/openuv/translations/es-419.json +++ b/homeassistant/components/openuv/translations/es-419.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Coordenadas ya registradas", "invalid_api_key": "Clave de API inv\u00e1lida" }, "step": { diff --git a/homeassistant/components/openuv/translations/es.json b/homeassistant/components/openuv/translations/es.json index 45e566ac2af..7736adaa674 100644 --- a/homeassistant/components/openuv/translations/es.json +++ b/homeassistant/components/openuv/translations/es.json @@ -4,7 +4,6 @@ "already_configured": "Estas coordenadas ya est\u00e1n registradas." }, "error": { - "identifier_exists": "Coordenadas ya registradas", "invalid_api_key": "Clave API no v\u00e1lida" }, "step": { diff --git a/homeassistant/components/openuv/translations/et.json b/homeassistant/components/openuv/translations/et.json index 9ea66935864..b238b0a0964 100644 --- a/homeassistant/components/openuv/translations/et.json +++ b/homeassistant/components/openuv/translations/et.json @@ -4,7 +4,6 @@ "already_configured": "Asukoht on juba m\u00e4\u00e4ratud" }, "error": { - "identifier_exists": "Koordinaadid on juba registreeritud", "invalid_api_key": "Vigane API v\u00f5ti" }, "step": { @@ -14,7 +13,8 @@ "elevation": "K\u00f5rgus merepinnast", "latitude": "Laiuskraad", "longitude": "Pikkuskraad" - } + }, + "title": "Sisesta oma teave" } } } diff --git a/homeassistant/components/openuv/translations/fi.json b/homeassistant/components/openuv/translations/fi.json index 4b023bff905..570c38ab053 100644 --- a/homeassistant/components/openuv/translations/fi.json +++ b/homeassistant/components/openuv/translations/fi.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Koordinaatit on jo rekister\u00f6ity", "invalid_api_key": "Virheellinen API-avain" }, "step": { diff --git a/homeassistant/components/openuv/translations/fr.json b/homeassistant/components/openuv/translations/fr.json index c34aebdee57..60000cd0058 100644 --- a/homeassistant/components/openuv/translations/fr.json +++ b/homeassistant/components/openuv/translations/fr.json @@ -4,7 +4,6 @@ "already_configured": "Coordonn\u00e9es d\u00e9j\u00e0 enregistr\u00e9es" }, "error": { - "identifier_exists": "Coordonn\u00e9es d\u00e9j\u00e0 enregistr\u00e9es", "invalid_api_key": "Cl\u00e9 d'API invalide" }, "step": { diff --git a/homeassistant/components/openuv/translations/he.json b/homeassistant/components/openuv/translations/he.json index 6c253be7855..1a93fb4b438 100644 --- a/homeassistant/components/openuv/translations/he.json +++ b/homeassistant/components/openuv/translations/he.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "\u05d4\u05e7\u05d5\u05d0\u05d5\u05e8\u05d3\u05d9\u05e0\u05d8\u05d5\u05ea \u05db\u05d1\u05e8 \u05e8\u05e9\u05d5\u05de\u05d5\u05ea", "invalid_api_key": "\u05de\u05e4\u05ea\u05d7 API \u05dc\u05d0 \u05d7\u05d5\u05e7\u05d9" }, "step": { diff --git a/homeassistant/components/openuv/translations/hu.json b/homeassistant/components/openuv/translations/hu.json index 8e06c5d4ad0..3a6f6a8ae91 100644 --- a/homeassistant/components/openuv/translations/hu.json +++ b/homeassistant/components/openuv/translations/hu.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "A koordin\u00e1t\u00e1k m\u00e1r regisztr\u00e1lva vannak", "invalid_api_key": "\u00c9rv\u00e9nytelen API kulcs" }, "step": { diff --git a/homeassistant/components/openuv/translations/id.json b/homeassistant/components/openuv/translations/id.json index bb396d8329a..4d0edd93ea9 100644 --- a/homeassistant/components/openuv/translations/id.json +++ b/homeassistant/components/openuv/translations/id.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Koordinat sudah terdaftar", "invalid_api_key": "Kunci API tidak valid" }, "step": { diff --git a/homeassistant/components/openuv/translations/it.json b/homeassistant/components/openuv/translations/it.json index 4b957b23551..ab7cfd39af9 100644 --- a/homeassistant/components/openuv/translations/it.json +++ b/homeassistant/components/openuv/translations/it.json @@ -4,7 +4,6 @@ "already_configured": "La posizione \u00e8 gi\u00e0 configurata" }, "error": { - "identifier_exists": "Coordinate gi\u00e0 registrate", "invalid_api_key": "Chiave API non valida" }, "step": { diff --git a/homeassistant/components/openuv/translations/ko.json b/homeassistant/components/openuv/translations/ko.json index d9cb9ec33d7..480b745fe36 100644 --- a/homeassistant/components/openuv/translations/ko.json +++ b/homeassistant/components/openuv/translations/ko.json @@ -4,7 +4,6 @@ "already_configured": "\uc88c\ud45c\uac12\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "error": { - "identifier_exists": "\uc88c\ud45c\uac12\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "invalid_api_key": "API \ud0a4\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "step": { diff --git a/homeassistant/components/openuv/translations/lb.json b/homeassistant/components/openuv/translations/lb.json index 483a949f143..c816bba685d 100644 --- a/homeassistant/components/openuv/translations/lb.json +++ b/homeassistant/components/openuv/translations/lb.json @@ -4,7 +4,6 @@ "already_configured": "Standuert ass scho konfigur\u00e9iert" }, "error": { - "identifier_exists": "Koordinate si scho\u00a0registr\u00e9iert", "invalid_api_key": "Ong\u00ebltegen API Schl\u00ebssel" }, "step": { diff --git a/homeassistant/components/openuv/translations/nl.json b/homeassistant/components/openuv/translations/nl.json index e3badcb796a..118e8f05141 100644 --- a/homeassistant/components/openuv/translations/nl.json +++ b/homeassistant/components/openuv/translations/nl.json @@ -4,7 +4,6 @@ "already_configured": "Deze co\u00f6rdinaten zijn al geregistreerd." }, "error": { - "identifier_exists": "Co\u00f6rdinaten al geregistreerd", "invalid_api_key": "Ongeldige API-sleutel" }, "step": { diff --git a/homeassistant/components/openuv/translations/nn.json b/homeassistant/components/openuv/translations/nn.json index 284285af65c..543f42d09fa 100644 --- a/homeassistant/components/openuv/translations/nn.json +++ b/homeassistant/components/openuv/translations/nn.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Koordinata er allereie registrerte", "invalid_api_key": "Ugyldig API-n\u00f8kkel" }, "step": { diff --git a/homeassistant/components/openuv/translations/no.json b/homeassistant/components/openuv/translations/no.json index 1ba3d83be77..0c4356c6f79 100644 --- a/homeassistant/components/openuv/translations/no.json +++ b/homeassistant/components/openuv/translations/no.json @@ -4,7 +4,6 @@ "already_configured": "Plasseringen er allerede konfigurert" }, "error": { - "identifier_exists": "Koordinatene er allerede registrert", "invalid_api_key": "Ugyldig API-n\u00f8kkel" }, "step": { diff --git a/homeassistant/components/openuv/translations/pl.json b/homeassistant/components/openuv/translations/pl.json index 60469ab8f8b..bd633e92f05 100644 --- a/homeassistant/components/openuv/translations/pl.json +++ b/homeassistant/components/openuv/translations/pl.json @@ -4,7 +4,6 @@ "already_configured": "Lokalizacja jest ju\u017c skonfigurowana" }, "error": { - "identifier_exists": "Wsp\u00f3\u0142rz\u0119dne s\u0105 ju\u017c zarejestrowane", "invalid_api_key": "Nieprawid\u0142owy klucz API" }, "step": { diff --git a/homeassistant/components/openuv/translations/pt-BR.json b/homeassistant/components/openuv/translations/pt-BR.json index b3e40ae29bd..01a756a2ebb 100644 --- a/homeassistant/components/openuv/translations/pt-BR.json +++ b/homeassistant/components/openuv/translations/pt-BR.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Coordenadas j\u00e1 cadastradas", "invalid_api_key": "Chave de API inv\u00e1lida" }, "step": { diff --git a/homeassistant/components/openuv/translations/pt.json b/homeassistant/components/openuv/translations/pt.json index 92ecaad74c1..c408b4bec33 100644 --- a/homeassistant/components/openuv/translations/pt.json +++ b/homeassistant/components/openuv/translations/pt.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Coordenadas j\u00e1 registadas", "invalid_api_key": "Chave de API inv\u00e1lida" }, "step": { diff --git a/homeassistant/components/openuv/translations/ro.json b/homeassistant/components/openuv/translations/ro.json index 9e6e01c427a..def4742494a 100644 --- a/homeassistant/components/openuv/translations/ro.json +++ b/homeassistant/components/openuv/translations/ro.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Coordonatele deja \u00eenregistrate", "invalid_api_key": "Cheie API invalid\u0103" }, "step": { diff --git a/homeassistant/components/openuv/translations/ru.json b/homeassistant/components/openuv/translations/ru.json index 52f464b7a0d..405b9625d32 100644 --- a/homeassistant/components/openuv/translations/ru.json +++ b/homeassistant/components/openuv/translations/ru.json @@ -4,7 +4,6 @@ "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." }, "error": { - "identifier_exists": "\u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b.", "invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API." }, "step": { diff --git a/homeassistant/components/openuv/translations/sl.json b/homeassistant/components/openuv/translations/sl.json index f95723b6d43..cbd73cc9ddc 100644 --- a/homeassistant/components/openuv/translations/sl.json +++ b/homeassistant/components/openuv/translations/sl.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Koordinate \u017ee registrirane", "invalid_api_key": "Neveljaven API klju\u010d" }, "step": { diff --git a/homeassistant/components/openuv/translations/sv.json b/homeassistant/components/openuv/translations/sv.json index 7c7f26b4328..0df9a0434ab 100644 --- a/homeassistant/components/openuv/translations/sv.json +++ b/homeassistant/components/openuv/translations/sv.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "Koordinater \u00e4r redan registrerade", "invalid_api_key": "Ogiltigt API-l\u00f6senord" }, "step": { diff --git a/homeassistant/components/openuv/translations/uk.json b/homeassistant/components/openuv/translations/uk.json index 144ae8b8d36..fef350a3f3c 100644 --- a/homeassistant/components/openuv/translations/uk.json +++ b/homeassistant/components/openuv/translations/uk.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "identifier_exists": "\u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0438 \u0432\u0436\u0435 \u0437\u0430\u0440\u0435\u0454\u0441\u0442\u0440\u043e\u0432\u0430\u043d\u0456" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/openuv/translations/zh-Hans.json b/homeassistant/components/openuv/translations/zh-Hans.json index d960e2d93b4..d23c6f3d52c 100644 --- a/homeassistant/components/openuv/translations/zh-Hans.json +++ b/homeassistant/components/openuv/translations/zh-Hans.json @@ -1,7 +1,6 @@ { "config": { "error": { - "identifier_exists": "\u5750\u6807\u5df2\u7ecf\u6ce8\u518c", "invalid_api_key": "\u65e0\u6548\u7684 API \u5bc6\u94a5" }, "step": { diff --git a/homeassistant/components/openuv/translations/zh-Hant.json b/homeassistant/components/openuv/translations/zh-Hant.json index 9a5867fe0c8..f2b34ae8bf2 100644 --- a/homeassistant/components/openuv/translations/zh-Hant.json +++ b/homeassistant/components/openuv/translations/zh-Hant.json @@ -4,7 +4,6 @@ "already_configured": "\u5ea7\u6a19\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "identifier_exists": "\u8a72\u5ea7\u6a19\u5df2\u8a3b\u518a", "invalid_api_key": "API \u5bc6\u9470\u7121\u6548" }, "step": { diff --git a/homeassistant/components/openweathermap/__init__.py b/homeassistant/components/openweathermap/__init__.py index bdda75bae29..4754c4b2eff 100644 --- a/homeassistant/components/openweathermap/__init__.py +++ b/homeassistant/components/openweathermap/__init__.py @@ -3,8 +3,9 @@ import asyncio import logging from pyowm import OWM +from pyowm.utils.config import get_default_config -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONF_API_KEY, CONF_LATITUDE, @@ -18,13 +19,14 @@ from homeassistant.exceptions import ConfigEntryNotReady from .const import ( COMPONENTS, CONF_LANGUAGE, + CONFIG_FLOW_VERSION, DOMAIN, - ENTRY_FORECAST_COORDINATOR, ENTRY_NAME, ENTRY_WEATHER_COORDINATOR, + FORECAST_MODE_FREE_DAILY, + FORECAST_MODE_ONECALL_DAILY, UPDATE_LISTENER, ) -from .forecast_update_coordinator import ForecastUpdateCoordinator from .weather_update_coordinator import WeatherUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -33,11 +35,6 @@ _LOGGER = logging.getLogger(__name__) async def async_setup(hass: HomeAssistant, config: dict) -> bool: """Set up the OpenWeatherMap component.""" hass.data.setdefault(DOMAIN, {}) - - weather_configs = _filter_domain_configs(config.get("weather", []), DOMAIN) - sensor_configs = _filter_domain_configs(config.get("sensor", []), DOMAIN) - - _import_configs(hass, weather_configs + sensor_configs) return True @@ -50,26 +47,22 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry): forecast_mode = _get_config_value(config_entry, CONF_MODE) language = _get_config_value(config_entry, CONF_LANGUAGE) - owm = OWM(API_key=api_key, language=language) - weather_coordinator = WeatherUpdateCoordinator(owm, latitude, longitude, hass) - forecast_coordinator = ForecastUpdateCoordinator( + config_dict = _get_owm_config(language) + + owm = OWM(api_key, config_dict).weather_manager() + weather_coordinator = WeatherUpdateCoordinator( owm, latitude, longitude, forecast_mode, hass ) await weather_coordinator.async_refresh() - await forecast_coordinator.async_refresh() - if ( - not weather_coordinator.last_update_success - and not forecast_coordinator.last_update_success - ): + if not weather_coordinator.last_update_success: raise ConfigEntryNotReady hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][config_entry.entry_id] = { ENTRY_NAME: name, ENTRY_WEATHER_COORDINATOR: weather_coordinator, - ENTRY_FORECAST_COORDINATOR: forecast_coordinator, } for component in COMPONENTS: @@ -83,6 +76,28 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry): return True +async def async_migrate_entry(hass, entry): + """Migrate old entry.""" + config_entries = hass.config_entries + data = entry.data + version = entry.version + + _LOGGER.debug("Migrating OpenWeatherMap entry from version %s", version) + + if version == 1: + mode = data[CONF_MODE] + if mode == FORECAST_MODE_FREE_DAILY: + mode = FORECAST_MODE_ONECALL_DAILY + + new_data = {**data, CONF_MODE: mode} + version = entry.version = CONFIG_FLOW_VERSION + config_entries.async_update_entry(entry, data=new_data) + + _LOGGER.info("Migration to version %s successful", version) + + return True + + async def async_update_options(hass: HomeAssistant, config_entry: ConfigEntry): """Update options.""" await hass.config_entries.async_reload(config_entry.entry_id) @@ -106,18 +121,6 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry): return unload_ok -def _import_configs(hass, configs): - for config in configs: - _LOGGER.debug("Importing OpenWeatherMap %s", config) - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=config, - ) - ) - - def _filter_domain_configs(elements, domain): return list(filter(lambda elem: elem["platform"] == domain, elements)) @@ -126,3 +129,10 @@ def _get_config_value(config_entry, key): if config_entry.options: return config_entry.options[key] return config_entry.data[key] + + +def _get_owm_config(language): + """Get OpenWeatherMap configuration and add language to it.""" + config_dict = get_default_config() + config_dict["language"] = language + return config_dict diff --git a/homeassistant/components/openweathermap/config_flow.py b/homeassistant/components/openweathermap/config_flow.py index f383a5cb123..2c2070141d5 100644 --- a/homeassistant/components/openweathermap/config_flow.py +++ b/homeassistant/components/openweathermap/config_flow.py @@ -1,7 +1,6 @@ """Config flow for OpenWeatherMap.""" from pyowm import OWM -from pyowm.exceptions.api_call_error import APICallError -from pyowm.exceptions.api_response_error import UnauthorizedError +from pyowm.commons.exceptions import APIRequestError, UnauthorizedError import voluptuous as vol from homeassistant import config_entries @@ -17,6 +16,7 @@ import homeassistant.helpers.config_validation as cv from .const import ( CONF_LANGUAGE, + CONFIG_FLOW_VERSION, DEFAULT_FORECAST_MODE, DEFAULT_LANGUAGE, DEFAULT_NAME, @@ -25,22 +25,11 @@ from .const import ( ) from .const import DOMAIN # pylint:disable=unused-import -SCHEMA = vol.Schema( - { - vol.Required(CONF_API_KEY): str, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): str, - vol.Optional(CONF_LATITUDE): cv.latitude, - vol.Optional(CONF_LONGITUDE): cv.longitude, - vol.Optional(CONF_MODE, default=DEFAULT_FORECAST_MODE): vol.In(FORECAST_MODES), - vol.Optional(CONF_LANGUAGE, default=DEFAULT_LANGUAGE): vol.In(LANGUAGES), - } -) - class OpenWeatherMapConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Config flow for OpenWeatherMap.""" - VERSION = 1 + VERSION = CONFIG_FLOW_VERSION CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL @staticmethod @@ -62,35 +51,40 @@ class OpenWeatherMapConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): try: api_online = await _is_owm_api_online( - self.hass, user_input[CONF_API_KEY] + self.hass, user_input[CONF_API_KEY], latitude, longitude ) if not api_online: errors["base"] = "invalid_api_key" except UnauthorizedError: errors["base"] = "invalid_api_key" - except APICallError: + except APIRequestError: errors["base"] = "cannot_connect" if not errors: return self.async_create_entry( title=user_input[CONF_NAME], data=user_input ) - return self.async_show_form(step_id="user", data_schema=SCHEMA, errors=errors) - async def async_step_import(self, import_input=None): - """Set the config entry up from yaml.""" - config = import_input.copy() - if CONF_NAME not in config: - config[CONF_NAME] = DEFAULT_NAME - if CONF_LATITUDE not in config: - config[CONF_LATITUDE] = self.hass.config.latitude - if CONF_LONGITUDE not in config: - config[CONF_LONGITUDE] = self.hass.config.longitude - if CONF_MODE not in config: - config[CONF_MODE] = DEFAULT_FORECAST_MODE - if CONF_LANGUAGE not in config: - config[CONF_LANGUAGE] = DEFAULT_LANGUAGE - return await self.async_step_user(config) + schema = vol.Schema( + { + vol.Required(CONF_API_KEY): str, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): str, + vol.Optional( + CONF_LATITUDE, default=self.hass.config.latitude + ): cv.latitude, + vol.Optional( + CONF_LONGITUDE, default=self.hass.config.longitude + ): cv.longitude, + vol.Optional(CONF_MODE, default=DEFAULT_FORECAST_MODE): vol.In( + FORECAST_MODES + ), + vol.Optional(CONF_LANGUAGE, default=DEFAULT_LANGUAGE): vol.In( + LANGUAGES + ), + } + ) + + return self.async_show_form(step_id="user", data_schema=schema, errors=errors) class OpenWeatherMapOptionsFlow(config_entries.OptionsFlow): @@ -129,6 +123,6 @@ class OpenWeatherMapOptionsFlow(config_entries.OptionsFlow): ) -async def _is_owm_api_online(hass, api_key): - owm = OWM(api_key) - return await hass.async_add_executor_job(owm.is_API_online) +async def _is_owm_api_online(hass, api_key, lat, lon): + owm = OWM(api_key).weather_manager() + return await hass.async_add_executor_job(owm.one_call, lat, lon) diff --git a/homeassistant/components/openweathermap/const.py b/homeassistant/components/openweathermap/const.py index 03ed97d4075..2c23c618c75 100644 --- a/homeassistant/components/openweathermap/const.py +++ b/homeassistant/components/openweathermap/const.py @@ -16,7 +16,7 @@ from homeassistant.const import ( DEVICE_CLASS_TIMESTAMP, LENGTH_MILLIMETERS, PERCENTAGE, - PRESSURE_PA, + PRESSURE_HPA, SPEED_METERS_PER_SECOND, TEMP_CELSIUS, ) @@ -24,11 +24,10 @@ from homeassistant.const import ( DOMAIN = "openweathermap" DEFAULT_NAME = "OpenWeatherMap" DEFAULT_LANGUAGE = "en" -DEFAULT_FORECAST_MODE = "freedaily" ATTRIBUTION = "Data provided by OpenWeatherMap" CONF_LANGUAGE = "language" +CONFIG_FLOW_VERSION = 2 ENTRY_NAME = "name" -ENTRY_FORECAST_COORDINATOR = "forecast_coordinator" ENTRY_WEATHER_COORDINATOR = "weather_coordinator" ATTR_API_PRECIPITATION = "precipitation" ATTR_API_DATETIME = "datetime" @@ -44,13 +43,25 @@ ATTR_API_RAIN = "rain" ATTR_API_SNOW = "snow" ATTR_API_WEATHER_CODE = "weather_code" ATTR_API_FORECAST = "forecast" -ATTR_API_THIS_DAY_FORECAST = "this_day_forecast" SENSOR_NAME = "sensor_name" SENSOR_UNIT = "sensor_unit" SENSOR_DEVICE_CLASS = "sensor_device_class" UPDATE_LISTENER = "update_listener" COMPONENTS = ["sensor", "weather"] -FORECAST_MODES = ["hourly", "daily", "freedaily"] + +FORECAST_MODE_HOURLY = "hourly" +FORECAST_MODE_DAILY = "daily" +FORECAST_MODE_FREE_DAILY = "freedaily" +FORECAST_MODE_ONECALL_HOURLY = "onecall_hourly" +FORECAST_MODE_ONECALL_DAILY = "onecall_daily" +FORECAST_MODES = [ + FORECAST_MODE_HOURLY, + FORECAST_MODE_DAILY, + FORECAST_MODE_ONECALL_HOURLY, + FORECAST_MODE_ONECALL_DAILY, +] +DEFAULT_FORECAST_MODE = FORECAST_MODE_ONECALL_DAILY + MONITORED_CONDITIONS = [ ATTR_API_WEATHER, ATTR_API_TEMPERATURE, @@ -159,7 +170,7 @@ WEATHER_SENSOR_TYPES = { }, ATTR_API_PRESSURE: { SENSOR_NAME: "Pressure", - SENSOR_UNIT: PRESSURE_PA, + SENSOR_UNIT: PRESSURE_HPA, SENSOR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE, }, ATTR_API_CLOUDS: {SENSOR_NAME: "Cloud coverage", SENSOR_UNIT: PERCENTAGE}, diff --git a/homeassistant/components/openweathermap/forecast_update_coordinator.py b/homeassistant/components/openweathermap/forecast_update_coordinator.py deleted file mode 100644 index 66fa7d39ab4..00000000000 --- a/homeassistant/components/openweathermap/forecast_update_coordinator.py +++ /dev/null @@ -1,137 +0,0 @@ -"""Forecast data coordinator for the OpenWeatherMap (OWM) service.""" -from datetime import timedelta -import logging - -import async_timeout -from pyowm.exceptions.api_call_error import APICallError -from pyowm.exceptions.api_response_error import UnauthorizedError - -from homeassistant.components.weather import ( - ATTR_FORECAST_CONDITION, - ATTR_FORECAST_PRECIPITATION, - ATTR_FORECAST_TEMP, - ATTR_FORECAST_TEMP_LOW, - ATTR_FORECAST_TIME, - ATTR_FORECAST_WIND_BEARING, - ATTR_FORECAST_WIND_SPEED, -) -from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed - -from .const import ( - ATTR_API_FORECAST, - ATTR_API_THIS_DAY_FORECAST, - CONDITION_CLASSES, - DOMAIN, -) - -_LOGGER = logging.getLogger(__name__) - -FORECAST_UPDATE_INTERVAL = timedelta(minutes=30) - - -class ForecastUpdateCoordinator(DataUpdateCoordinator): - """Forecast data update coordinator.""" - - def __init__(self, owm, latitude, longitude, forecast_mode, hass): - """Initialize coordinator.""" - self._owm_client = owm - self._forecast_mode = forecast_mode - self._latitude = latitude - self._longitude = longitude - self._forecast_limit = 15 - - super().__init__( - hass, _LOGGER, name=DOMAIN, update_interval=FORECAST_UPDATE_INTERVAL - ) - - async def _async_update_data(self): - data = {} - with async_timeout.timeout(20): - try: - forecast_response = await self._get_owm_forecast() - data = self._convert_forecast_response(forecast_response) - except (APICallError, UnauthorizedError) as error: - raise UpdateFailed(error) from error - - return data - - async def _get_owm_forecast(self): - if self._forecast_mode == "daily": - forecast_response = await self.hass.async_add_executor_job( - self._owm_client.daily_forecast_at_coords, - self._latitude, - self._longitude, - self._forecast_limit, - ) - else: - forecast_response = await self.hass.async_add_executor_job( - self._owm_client.three_hours_forecast_at_coords, - self._latitude, - self._longitude, - ) - return forecast_response.get_forecast() - - def _convert_forecast_response(self, forecast_response): - weathers = self._get_weathers(forecast_response) - - forecast_entries = self._convert_forecast_entries(weathers) - - return { - ATTR_API_FORECAST: forecast_entries, - ATTR_API_THIS_DAY_FORECAST: forecast_entries[0], - } - - def _get_weathers(self, forecast_response): - if self._forecast_mode == "freedaily": - return forecast_response.get_weathers()[::8] - return forecast_response.get_weathers() - - def _convert_forecast_entries(self, entries): - if self._forecast_mode == "daily": - return list(map(self._convert_daily_forecast, entries)) - return list(map(self._convert_forecast, entries)) - - def _convert_daily_forecast(self, entry): - return { - ATTR_FORECAST_TIME: entry.get_reference_time("unix") * 1000, - ATTR_FORECAST_TEMP: entry.get_temperature("celsius").get("day"), - ATTR_FORECAST_TEMP_LOW: entry.get_temperature("celsius").get("night"), - ATTR_FORECAST_PRECIPITATION: self._calc_daily_precipitation( - entry.get_rain().get("all"), entry.get_snow().get("all") - ), - ATTR_FORECAST_WIND_SPEED: entry.get_wind().get("speed"), - ATTR_FORECAST_WIND_BEARING: entry.get_wind().get("deg"), - ATTR_FORECAST_CONDITION: self._get_condition(entry.get_weather_code()), - } - - def _convert_forecast(self, entry): - return { - ATTR_FORECAST_TIME: entry.get_reference_time("unix") * 1000, - ATTR_FORECAST_TEMP: entry.get_temperature("celsius").get("temp"), - ATTR_FORECAST_PRECIPITATION: self._calc_precipitation(entry), - ATTR_FORECAST_WIND_SPEED: entry.get_wind().get("speed"), - ATTR_FORECAST_WIND_BEARING: entry.get_wind().get("deg"), - ATTR_FORECAST_CONDITION: self._get_condition(entry.get_weather_code()), - } - - @staticmethod - def _calc_daily_precipitation(rain, snow): - """Calculate the precipitation.""" - rain_value = 0 if rain is None else rain - snow_value = 0 if snow is None else snow - if round(rain_value + snow_value, 1) == 0: - return None - return round(rain_value + snow_value, 1) - - @staticmethod - def _calc_precipitation(entry): - return ( - round(entry.get_rain().get("1h"), 1) - if entry.get_rain().get("1h") is not None - and (round(entry.get_rain().get("1h"), 1) > 0) - else None - ) - - @staticmethod - def _get_condition(weather_code): - return [k for k, v in CONDITION_CLASSES.items() if weather_code in v][0] diff --git a/homeassistant/components/openweathermap/manifest.json b/homeassistant/components/openweathermap/manifest.json index dcd5d15f18d..4ebdaf44c9e 100644 --- a/homeassistant/components/openweathermap/manifest.json +++ b/homeassistant/components/openweathermap/manifest.json @@ -3,6 +3,6 @@ "name": "OpenWeatherMap", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/openweathermap", - "requirements": ["pyowm==2.10.0"], - "codeowners": ["@fabaff", "@freekode"] + "requirements": ["pyowm==3.1.0"], + "codeowners": ["@fabaff", "@freekode", "@nzapponi"] } diff --git a/homeassistant/components/openweathermap/sensor.py b/homeassistant/components/openweathermap/sensor.py index 3879d270b52..39c50c3b941 100644 --- a/homeassistant/components/openweathermap/sensor.py +++ b/homeassistant/components/openweathermap/sensor.py @@ -1,9 +1,8 @@ """Support for the OpenWeatherMap (OWM) service.""" from .abstract_owm_sensor import AbstractOpenWeatherMapSensor from .const import ( - ATTR_API_THIS_DAY_FORECAST, + ATTR_API_FORECAST, DOMAIN, - ENTRY_FORECAST_COORDINATOR, ENTRY_NAME, ENTRY_WEATHER_COORDINATOR, FORECAST_MONITORED_CONDITIONS, @@ -11,7 +10,6 @@ from .const import ( MONITORED_CONDITIONS, WEATHER_SENSOR_TYPES, ) -from .forecast_update_coordinator import ForecastUpdateCoordinator from .weather_update_coordinator import WeatherUpdateCoordinator @@ -20,7 +18,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities): domain_data = hass.data[DOMAIN][config_entry.entry_id] name = domain_data[ENTRY_NAME] weather_coordinator = domain_data[ENTRY_WEATHER_COORDINATOR] - forecast_coordinator = domain_data[ENTRY_FORECAST_COORDINATOR] weather_sensor_types = WEATHER_SENSOR_TYPES forecast_sensor_types = FORECAST_SENSOR_TYPES @@ -46,7 +43,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): unique_id, sensor_type, forecast_sensor_types[sensor_type], - forecast_coordinator, + weather_coordinator, ) ) @@ -85,17 +82,18 @@ class OpenWeatherMapForecastSensor(AbstractOpenWeatherMapSensor): unique_id, sensor_type, sensor_configuration, - forecast_coordinator: ForecastUpdateCoordinator, + weather_coordinator: WeatherUpdateCoordinator, ): """Initialize the sensor.""" super().__init__( - name, unique_id, sensor_type, sensor_configuration, forecast_coordinator + name, unique_id, sensor_type, sensor_configuration, weather_coordinator ) - self._forecast_coordinator = forecast_coordinator + self._weather_coordinator = weather_coordinator @property def state(self): """Return the state of the device.""" - return self._forecast_coordinator.data[ATTR_API_THIS_DAY_FORECAST].get( - self._sensor_type, None - ) + forecasts = self._weather_coordinator.data.get(ATTR_API_FORECAST) + if forecasts is not None and len(forecasts) > 0: + return forecasts[0].get(self._sensor_type, None) + return None diff --git a/homeassistant/components/openweathermap/strings.json b/homeassistant/components/openweathermap/strings.json index 4fb415522e7..520cf1181ff 100644 --- a/homeassistant/components/openweathermap/strings.json +++ b/homeassistant/components/openweathermap/strings.json @@ -14,7 +14,7 @@ "language": "Language", "latitude": "[%key:common::config_flow::data::latitude%]", "longitude": "[%key:common::config_flow::data::longitude%]", - "mode": "Mode", + "mode": "[%key:common::config_flow::data::mode%]", "name": "Name of the integration" }, "description": "Set up OpenWeatherMap integration. To generate API key go to https://openweathermap.org/appid", @@ -27,7 +27,7 @@ "init": { "data": { "language": "Language", - "mode": "Mode" + "mode": "[%key:common::config_flow::data::mode%]" } } } diff --git a/homeassistant/components/openweathermap/translations/ca.json b/homeassistant/components/openweathermap/translations/ca.json index 9ec2b40e5d0..b3b1ebbb85e 100644 --- a/homeassistant/components/openweathermap/translations/ca.json +++ b/homeassistant/components/openweathermap/translations/ca.json @@ -4,9 +4,7 @@ "already_configured": "La ubicaci\u00f3 ja est\u00e0 configurada" }, "error": { - "auth": "La clau API no \u00e9s correcta.", "cannot_connect": "Ha fallat la connexi\u00f3", - "connection": "No s'ha pogut connectar amb l'API d'OWM", "invalid_api_key": "Clau API inv\u00e0lida" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/cs.json b/homeassistant/components/openweathermap/translations/cs.json index 7bb48cbb4e5..42383643be1 100644 --- a/homeassistant/components/openweathermap/translations/cs.json +++ b/homeassistant/components/openweathermap/translations/cs.json @@ -4,9 +4,7 @@ "already_configured": "Um\u00edst\u011bn\u00ed je ji\u017e nastaveno" }, "error": { - "auth": "Kl\u00ed\u010d API nen\u00ed spr\u00e1vn\u00fd.", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection": "Nelze se p\u0159ipojit k OpenWeatherMap API", "invalid_api_key": "Neplatn\u00fd kl\u00ed\u010d API" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/de.json b/homeassistant/components/openweathermap/translations/de.json index 964fdbb9419..35232fe04db 100644 --- a/homeassistant/components/openweathermap/translations/de.json +++ b/homeassistant/components/openweathermap/translations/de.json @@ -1,12 +1,9 @@ { "config": { - "error": { - "auth": "Der API-Schl\u00fcssel ist nicht korrekt.", - "connection": "Es kann keine Verbindung zur OWM-API hergestellt werden" - }, "step": { "user": { "data": { + "api_key": "API Key", "language": "Sprache", "latitude": "Breitengrad", "longitude": "L\u00e4ngengrad", diff --git a/homeassistant/components/openweathermap/translations/el.json b/homeassistant/components/openweathermap/translations/el.json index bdd4c34a586..9c703a704e8 100644 --- a/homeassistant/components/openweathermap/translations/el.json +++ b/homeassistant/components/openweathermap/translations/el.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "\u0397 \u03b5\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7 OpenWeatherMap \u03b3\u03b9\u03b1 \u03b1\u03c5\u03c4\u03ad\u03c2 \u03c4\u03b9\u03c2 \u03c3\u03c5\u03bd\u03c4\u03b5\u03c4\u03b1\u03b3\u03bc\u03ad\u03bd\u03b5\u03c2 \u03ad\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03c1\u03c5\u03b8\u03bc\u03b9\u03c3\u03c4\u03b5\u03af." }, - "error": { - "auth": "\u03a4\u03bf \u03ba\u03bb\u03b5\u03b9\u03b4\u03af API \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03c3\u03c9\u03c3\u03c4\u03cc.", - "connection": "\u0394\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae \u03b7 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7 \u03c3\u03c4\u03bf OWM API" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/openweathermap/translations/en.json b/homeassistant/components/openweathermap/translations/en.json index 1ff286e9a9f..57feaccf6b4 100644 --- a/homeassistant/components/openweathermap/translations/en.json +++ b/homeassistant/components/openweathermap/translations/en.json @@ -4,9 +4,7 @@ "already_configured": "Location is already configured" }, "error": { - "auth": "API key is not correct.", "cannot_connect": "Failed to connect", - "connection": "Can't connect to OWM API", "invalid_api_key": "Invalid API key" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/es.json b/homeassistant/components/openweathermap/translations/es.json index 318061a06a7..8a44668e8ac 100644 --- a/homeassistant/components/openweathermap/translations/es.json +++ b/homeassistant/components/openweathermap/translations/es.json @@ -4,9 +4,7 @@ "already_configured": "La ubicaci\u00f3n ya est\u00e1 configurada" }, "error": { - "auth": "La clave de API no es correcta.", "cannot_connect": "No se pudo conectar", - "connection": "No se puede conectar a la API de OWM", "invalid_api_key": "Clave API no v\u00e1lida" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/et.json b/homeassistant/components/openweathermap/translations/et.json index 6ae485f2350..26c688482fd 100644 --- a/homeassistant/components/openweathermap/translations/et.json +++ b/homeassistant/components/openweathermap/translations/et.json @@ -4,9 +4,7 @@ "already_configured": "Nende koordinaatidele on OpenWeatherMapi sidumine juba tehtud." }, "error": { - "auth": "API v\u00f5ti on vale.", "cannot_connect": "\u00dchendamine nurjus", - "connection": "OWM API-ga ei saa \u00fchendust luua", "invalid_api_key": "Vigane API v\u00f5ti" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/fr.json b/homeassistant/components/openweathermap/translations/fr.json index aaa7887c120..e5b55db1ed3 100644 --- a/homeassistant/components/openweathermap/translations/fr.json +++ b/homeassistant/components/openweathermap/translations/fr.json @@ -4,9 +4,7 @@ "already_configured": "L'int\u00e9gration OpenWeatherMap pour ces coordonn\u00e9es est d\u00e9j\u00e0 configur\u00e9e." }, "error": { - "auth": "La cl\u00e9 API n'est pas correcte.", "cannot_connect": "\u00c9chec de connexion", - "connection": "Impossible de se connecter \u00e0 l'API OWM", "invalid_api_key": "Cl\u00e9 API invalide" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/it.json b/homeassistant/components/openweathermap/translations/it.json index 9c4abbadb5b..ffe49a466dc 100644 --- a/homeassistant/components/openweathermap/translations/it.json +++ b/homeassistant/components/openweathermap/translations/it.json @@ -4,9 +4,7 @@ "already_configured": "La posizione \u00e8 gi\u00e0 configurata" }, "error": { - "auth": "La chiave API non \u00e8 corretta.", "cannot_connect": "Impossibile connettersi", - "connection": "Impossibile connettersi all'API OWM", "invalid_api_key": "Chiave API non valida" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/ko.json b/homeassistant/components/openweathermap/translations/ko.json index 12e76d85506..9560f447250 100644 --- a/homeassistant/components/openweathermap/translations/ko.json +++ b/homeassistant/components/openweathermap/translations/ko.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "\uc774\ub7ec\ud55c \uc88c\ud45c\uc5d0 \ub300\ud55c OpenWeatherMap \ud1b5\ud569\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4." }, - "error": { - "auth": "API \ud0a4\uac00 \uc62c\ubc14\ub974\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.", - "connection": "OWM API\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/openweathermap/translations/lb.json b/homeassistant/components/openweathermap/translations/lb.json index ebc63815e0f..bed28c80575 100644 --- a/homeassistant/components/openweathermap/translations/lb.json +++ b/homeassistant/components/openweathermap/translations/lb.json @@ -1,9 +1,11 @@ { "config": { + "abort": { + "already_configured": "Standuert ass scho konfigur\u00e9iert" + }, "error": { - "auth": "Api Schl\u00ebssel ass net korrekt.", "cannot_connect": "Feeler beim verbannen", - "connection": "Kann sech net mat der OWM API verbannen." + "invalid_api_key": "Ong\u00ebltegen API Schl\u00ebssel" }, "step": { "user": { diff --git a/homeassistant/components/openweathermap/translations/nb.json b/homeassistant/components/openweathermap/translations/nb.json index f62cc08ac81..121742a8dd1 100644 --- a/homeassistant/components/openweathermap/translations/nb.json +++ b/homeassistant/components/openweathermap/translations/nb.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "OpenWeatherMap-integrering for disse koordinatene er allerede konfigurert." }, - "error": { - "auth": "API-n\u00f8kkelen er ikke riktig." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/openweathermap/translations/nl.json b/homeassistant/components/openweathermap/translations/nl.json index 8eea3e7c649..04f3c503353 100644 --- a/homeassistant/components/openweathermap/translations/nl.json +++ b/homeassistant/components/openweathermap/translations/nl.json @@ -4,9 +4,8 @@ "already_configured": "OpenWeatherMap-integratie voor deze co\u00f6rdinaten is al geconfigureerd." }, "error": { - "auth": "API-sleutel is niet correct.", "cannot_connect": "Kan geen verbinding maken", - "connection": "Kan geen verbinding maken met OWM API" + "invalid_api_key": "Ongeldige API-sleutel" }, "step": { "user": { diff --git a/homeassistant/components/openweathermap/translations/no.json b/homeassistant/components/openweathermap/translations/no.json index 66bae75dd4b..7982628fe62 100644 --- a/homeassistant/components/openweathermap/translations/no.json +++ b/homeassistant/components/openweathermap/translations/no.json @@ -4,9 +4,7 @@ "already_configured": "Plasseringen er allerede konfigurert" }, "error": { - "auth": "API-n\u00f8kkelen er ikke korrekt.", "cannot_connect": "Tilkobling mislyktes", - "connection": "Kan ikke koble til OWM API", "invalid_api_key": "Ugyldig API-n\u00f8kkel" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/pl.json b/homeassistant/components/openweathermap/translations/pl.json index eabd8c7d1dd..b3f31831f09 100644 --- a/homeassistant/components/openweathermap/translations/pl.json +++ b/homeassistant/components/openweathermap/translations/pl.json @@ -4,9 +4,7 @@ "already_configured": "Lokalizacja jest ju\u017c skonfigurowana" }, "error": { - "auth": "Nieprawid\u0142owy klucz API", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z API OWM", "invalid_api_key": "Nieprawid\u0142owy klucz API" }, "step": { diff --git a/homeassistant/components/openweathermap/translations/pt.json b/homeassistant/components/openweathermap/translations/pt.json index fa7fdc63989..f736ec7e3cc 100644 --- a/homeassistant/components/openweathermap/translations/pt.json +++ b/homeassistant/components/openweathermap/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "error": { - "auth": "A chave da API n\u00e3o est\u00e1 correta.", - "connection": "N\u00e3o \u00e9 poss\u00edvel conectar \u00e0 API OWM" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/openweathermap/translations/ru.json b/homeassistant/components/openweathermap/translations/ru.json index c2e2fae5a2b..f113d8205f7 100644 --- a/homeassistant/components/openweathermap/translations/ru.json +++ b/homeassistant/components/openweathermap/translations/ru.json @@ -4,9 +4,7 @@ "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." }, "error": { - "auth": "\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a API OpenWeatherMap.", "invalid_api_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 API." }, "step": { diff --git a/homeassistant/components/openweathermap/translations/sv.json b/homeassistant/components/openweathermap/translations/sv.json index a6fe05a8346..108d4575e55 100644 --- a/homeassistant/components/openweathermap/translations/sv.json +++ b/homeassistant/components/openweathermap/translations/sv.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "OpenWeatherMap-integrationen f\u00f6r dessa koordinater \u00e4r redan konfigurerad." }, - "error": { - "auth": "API-nyckeln \u00e4r inte korrekt.", - "connection": "Kan inte ansluta till OWM API" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/openweathermap/translations/zh-Hant.json b/homeassistant/components/openweathermap/translations/zh-Hant.json index 60bc208400f..c14163b1d98 100644 --- a/homeassistant/components/openweathermap/translations/zh-Hant.json +++ b/homeassistant/components/openweathermap/translations/zh-Hant.json @@ -4,9 +4,7 @@ "already_configured": "\u5ea7\u6a19\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "auth": "API \u5bc6\u9470\u4e0d\u6b63\u78ba\u3002", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection": "\u7121\u6cd5\u9023\u7dda\u81f3 OWM API", "invalid_api_key": "API \u5bc6\u9470\u7121\u6548" }, "step": { diff --git a/homeassistant/components/openweathermap/weather.py b/homeassistant/components/openweathermap/weather.py index e1ec96e5d07..7908beb61d6 100644 --- a/homeassistant/components/openweathermap/weather.py +++ b/homeassistant/components/openweathermap/weather.py @@ -12,11 +12,9 @@ from .const import ( ATTR_API_WIND_SPEED, ATTRIBUTION, DOMAIN, - ENTRY_FORECAST_COORDINATOR, ENTRY_NAME, ENTRY_WEATHER_COORDINATOR, ) -from .forecast_update_coordinator import ForecastUpdateCoordinator from .weather_update_coordinator import WeatherUpdateCoordinator @@ -25,12 +23,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): domain_data = hass.data[DOMAIN][config_entry.entry_id] name = domain_data[ENTRY_NAME] weather_coordinator = domain_data[ENTRY_WEATHER_COORDINATOR] - forecast_coordinator = domain_data[ENTRY_FORECAST_COORDINATOR] unique_id = f"{config_entry.unique_id}" - owm_weather = OpenWeatherMapWeather( - name, unique_id, weather_coordinator, forecast_coordinator - ) + owm_weather = OpenWeatherMapWeather(name, unique_id, weather_coordinator) async_add_entities([owm_weather], False) @@ -43,13 +38,11 @@ class OpenWeatherMapWeather(WeatherEntity): name, unique_id, weather_coordinator: WeatherUpdateCoordinator, - forecast_coordinator: ForecastUpdateCoordinator, ): """Initialize the sensor.""" self._name = name self._unique_id = unique_id self._weather_coordinator = weather_coordinator - self._forecast_coordinator = forecast_coordinator @property def name(self): @@ -112,26 +105,19 @@ class OpenWeatherMapWeather(WeatherEntity): @property def forecast(self): """Return the forecast array.""" - return self._forecast_coordinator.data[ATTR_API_FORECAST] + return self._weather_coordinator.data[ATTR_API_FORECAST] @property def available(self): """Return True if entity is available.""" - return ( - self._weather_coordinator.last_update_success - and self._forecast_coordinator.last_update_success - ) + return self._weather_coordinator.last_update_success async def async_added_to_hass(self): """Connect to dispatcher listening for entity data notifications.""" self.async_on_remove( self._weather_coordinator.async_add_listener(self.async_write_ha_state) ) - self.async_on_remove( - self._forecast_coordinator.async_add_listener(self.async_write_ha_state) - ) async def async_update(self): """Get the latest data from OWM and updates the states.""" await self._weather_coordinator.async_request_refresh() - await self._forecast_coordinator.async_request_refresh() diff --git a/homeassistant/components/openweathermap/weather_update_coordinator.py b/homeassistant/components/openweathermap/weather_update_coordinator.py index 3c042ae1c80..40dddc2e90d 100644 --- a/homeassistant/components/openweathermap/weather_update_coordinator.py +++ b/homeassistant/components/openweathermap/weather_update_coordinator.py @@ -3,14 +3,23 @@ from datetime import timedelta import logging import async_timeout -from pyowm.exceptions.api_call_error import APICallError -from pyowm.exceptions.api_response_error import UnauthorizedError +from pyowm.commons.exceptions import APIRequestError, UnauthorizedError +from homeassistant.components.weather import ( + ATTR_FORECAST_CONDITION, + ATTR_FORECAST_PRECIPITATION, + ATTR_FORECAST_TEMP, + ATTR_FORECAST_TEMP_LOW, + ATTR_FORECAST_TIME, + ATTR_FORECAST_WIND_BEARING, + ATTR_FORECAST_WIND_SPEED, +) from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import ( ATTR_API_CLOUDS, ATTR_API_CONDITION, + ATTR_API_FORECAST, ATTR_API_HUMIDITY, ATTR_API_PRESSURE, ATTR_API_RAIN, @@ -22,6 +31,10 @@ from .const import ( ATTR_API_WIND_SPEED, CONDITION_CLASSES, DOMAIN, + FORECAST_MODE_DAILY, + FORECAST_MODE_HOURLY, + FORECAST_MODE_ONECALL_DAILY, + FORECAST_MODE_ONECALL_HOURLY, ) _LOGGER = logging.getLogger(__name__) @@ -32,11 +45,15 @@ WEATHER_UPDATE_INTERVAL = timedelta(minutes=10) class WeatherUpdateCoordinator(DataUpdateCoordinator): """Weather data update coordinator.""" - def __init__(self, owm, latitude, longitude, hass): + def __init__(self, owm, latitude, longitude, forecast_mode, hass): """Initialize coordinator.""" self._owm_client = owm self._latitude = latitude self._longitude = longitude + self._forecast_mode = forecast_mode + self._forecast_limit = None + if forecast_mode == FORECAST_MODE_DAILY: + self._forecast_limit = 15 super().__init__( hass, _LOGGER, name=DOMAIN, update_interval=WEATHER_UPDATE_INTERVAL @@ -48,47 +65,137 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator): try: weather_response = await self._get_owm_weather() data = self._convert_weather_response(weather_response) - except (APICallError, UnauthorizedError) as error: + except (APIRequestError, UnauthorizedError) as error: raise UpdateFailed(error) from error return data async def _get_owm_weather(self): - weather = await self.hass.async_add_executor_job( - self._owm_client.weather_at_coords, self._latitude, self._longitude + """Poll weather data from OWM.""" + if ( + self._forecast_mode == FORECAST_MODE_ONECALL_HOURLY + or self._forecast_mode == FORECAST_MODE_ONECALL_DAILY + ): + weather = await self.hass.async_add_executor_job( + self._owm_client.one_call, self._latitude, self._longitude + ) + else: + weather = await self.hass.async_add_executor_job( + self._get_legacy_weather_and_forecast + ) + + return weather + + def _get_legacy_weather_and_forecast(self): + """Get weather and forecast data from OWM.""" + interval = self._get_forecast_interval() + weather = self._owm_client.weather_at_coords(self._latitude, self._longitude) + forecast = self._owm_client.forecast_at_coords( + self._latitude, self._longitude, interval, self._forecast_limit ) - return weather.get_weather() + return LegacyWeather(weather.weather, forecast.forecast.weathers) + + def _get_forecast_interval(self): + """Get the correct forecast interval depending on the forecast mode.""" + interval = "daily" + if self._forecast_mode == FORECAST_MODE_HOURLY: + interval = "3h" + return interval def _convert_weather_response(self, weather_response): + """Format the weather response correctly.""" + current_weather = weather_response.current + forecast_weather = self._get_forecast_from_weather_response(weather_response) + return { - ATTR_API_TEMPERATURE: weather_response.get_temperature("celsius").get( - "temp" - ), - ATTR_API_PRESSURE: weather_response.get_pressure().get("press"), - ATTR_API_HUMIDITY: weather_response.get_humidity(), - ATTR_API_WIND_BEARING: weather_response.get_wind().get("deg"), - ATTR_API_WIND_SPEED: weather_response.get_wind().get("speed"), - ATTR_API_CLOUDS: weather_response.get_clouds(), - ATTR_API_RAIN: self._get_rain(weather_response.get_rain()), - ATTR_API_SNOW: self._get_snow(weather_response.get_snow()), - ATTR_API_WEATHER: weather_response.get_detailed_status(), - ATTR_API_CONDITION: self._get_condition( - weather_response.get_weather_code() - ), - ATTR_API_WEATHER_CODE: weather_response.get_weather_code(), + ATTR_API_TEMPERATURE: current_weather.temperature("celsius").get("temp"), + ATTR_API_PRESSURE: current_weather.pressure.get("press"), + ATTR_API_HUMIDITY: current_weather.humidity, + ATTR_API_WIND_BEARING: current_weather.wind().get("deg"), + ATTR_API_WIND_SPEED: current_weather.wind().get("speed"), + ATTR_API_CLOUDS: current_weather.clouds, + ATTR_API_RAIN: self._get_rain(current_weather.rain), + ATTR_API_SNOW: self._get_snow(current_weather.snow), + ATTR_API_WEATHER: current_weather.detailed_status, + ATTR_API_CONDITION: self._get_condition(current_weather.weather_code), + ATTR_API_WEATHER_CODE: current_weather.weather_code, + ATTR_API_FORECAST: forecast_weather, } + def _get_forecast_from_weather_response(self, weather_response): + forecast_arg = "forecast" + if self._forecast_mode == FORECAST_MODE_ONECALL_HOURLY: + forecast_arg = "forecast_hourly" + elif self._forecast_mode == FORECAST_MODE_ONECALL_DAILY: + forecast_arg = "forecast_daily" + return [ + self._convert_forecast(x) for x in getattr(weather_response, forecast_arg) + ] + + def _convert_forecast(self, entry): + forecast = { + ATTR_FORECAST_TIME: entry.reference_time("unix") * 1000, + ATTR_FORECAST_PRECIPITATION: self._calc_precipitation( + entry.rain, entry.snow + ), + ATTR_FORECAST_WIND_SPEED: entry.wind().get("speed"), + ATTR_FORECAST_WIND_BEARING: entry.wind().get("deg"), + ATTR_FORECAST_CONDITION: self._get_condition(entry.weather_code), + } + + temperature_dict = entry.temperature("celsius") + if "max" in temperature_dict and "min" in temperature_dict: + forecast[ATTR_FORECAST_TEMP] = entry.temperature("celsius").get("max") + forecast[ATTR_FORECAST_TEMP_LOW] = entry.temperature("celsius").get("min") + else: + forecast[ATTR_FORECAST_TEMP] = entry.temperature("celsius").get("temp") + + return forecast + @staticmethod def _get_rain(rain): + """Get rain data from weather data.""" + if "all" in rain: + return round(rain["all"], 0) if "1h" in rain: return round(rain["1h"], 0) return "not raining" @staticmethod def _get_snow(snow): + """Get snow data from weather data.""" if snow: - return round(snow, 0) + if "all" in snow: + return round(snow["all"], 0) + if "1h" in snow: + return round(snow["1h"], 0) + return "not snowing" return "not snowing" + @staticmethod + def _calc_precipitation(rain, snow): + """Calculate the precipitation.""" + rain_value = 0 + if WeatherUpdateCoordinator._get_rain(rain) != "not raining": + rain_value = WeatherUpdateCoordinator._get_rain(rain) + + snow_value = 0 + if WeatherUpdateCoordinator._get_snow(snow) != "not snowing": + snow_value = WeatherUpdateCoordinator._get_snow(snow) + + if round(rain_value + snow_value, 1) == 0: + return None + return round(rain_value + snow_value, 1) + @staticmethod def _get_condition(weather_code): + """Get weather condition from weather data.""" return [k for k, v in CONDITION_CLASSES.items() if weather_code in v][0] + + +class LegacyWeather: + """Class to harmonize weather data model for hourly, daily and One Call APIs.""" + + def __init__(self, current_weather, forecast): + """Initialize weather object.""" + self.current = current_weather + self.forecast = forecast diff --git a/homeassistant/components/ovo_energy/translations/ca.json b/homeassistant/components/ovo_energy/translations/ca.json index 1cb306cf2d3..4f8525bfd85 100644 --- a/homeassistant/components/ovo_energy/translations/ca.json +++ b/homeassistant/components/ovo_energy/translations/ca.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "El compte ja ha estat configurat", - "authorization_error": "Error d'autoritzaci\u00f3. Comprova les teves credencials.", "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "Ha fallat la connexi\u00f3", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { diff --git a/homeassistant/components/ovo_energy/translations/cs.json b/homeassistant/components/ovo_energy/translations/cs.json index 094bd102714..d8276248ad4 100644 --- a/homeassistant/components/ovo_energy/translations/cs.json +++ b/homeassistant/components/ovo_energy/translations/cs.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "\u00da\u010det je ji\u017e nastaven", - "authorization_error": "Chyba autorizace. Zkontrolujte sv\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje.", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { diff --git a/homeassistant/components/ovo_energy/translations/en.json b/homeassistant/components/ovo_energy/translations/en.json index d716d692d6a..160f47ae23f 100644 --- a/homeassistant/components/ovo_energy/translations/en.json +++ b/homeassistant/components/ovo_energy/translations/en.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Account is already configured", - "authorization_error": "Authorization error. Check your credentials.", "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect", "invalid_auth": "Invalid authentication" }, "step": { diff --git a/homeassistant/components/ovo_energy/translations/es.json b/homeassistant/components/ovo_energy/translations/es.json index 3508e5131ec..43f2d7e4541 100644 --- a/homeassistant/components/ovo_energy/translations/es.json +++ b/homeassistant/components/ovo_energy/translations/es.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "La cuenta ya est\u00e1 configurada", - "authorization_error": "Error de autorizaci\u00f3n. Comprueba tus credenciales.", "cannot_connect": "No se pudo conectar", - "connection_error": "No se ha podido conectar a OVO Energy.", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { diff --git a/homeassistant/components/ovo_energy/translations/et.json b/homeassistant/components/ovo_energy/translations/et.json index 8bf44aef094..bc3df1eaf44 100644 --- a/homeassistant/components/ovo_energy/translations/et.json +++ b/homeassistant/components/ovo_energy/translations/et.json @@ -3,7 +3,6 @@ "error": { "already_configured": "Konto on juba seadistatud", "cannot_connect": "\u00dchendus nurjus", - "connection_error": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamise viga" }, "step": { @@ -12,6 +11,7 @@ "password": "Salas\u00f5na", "username": "Kasutajanimi" }, + "description": "Oma energiatarbimisele juurdep\u00e4\u00e4su saamiseks seadista OVO Energy.", "title": "Lisa OVO Energy konto" } } diff --git a/homeassistant/components/ovo_energy/translations/fr.json b/homeassistant/components/ovo_energy/translations/fr.json index b900e75787f..86719e87df4 100644 --- a/homeassistant/components/ovo_energy/translations/fr.json +++ b/homeassistant/components/ovo_energy/translations/fr.json @@ -2,8 +2,8 @@ "config": { "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", + "invalid_auth": "Authentification invalide" }, "step": { "user": { diff --git a/homeassistant/components/ovo_energy/translations/it.json b/homeassistant/components/ovo_energy/translations/it.json index 968ff79da43..f0619e7d593 100644 --- a/homeassistant/components/ovo_energy/translations/it.json +++ b/homeassistant/components/ovo_energy/translations/it.json @@ -2,9 +2,8 @@ "config": { "error": { "already_configured": "L'account \u00e8 gi\u00e0 configurato", - "authorization_error": "Errore di autorizzazione. Controlla le tue credenziali.", "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi" + "invalid_auth": "Autenticazione non valida" }, "step": { "user": { diff --git a/homeassistant/components/ovo_energy/translations/ko.json b/homeassistant/components/ovo_energy/translations/ko.json index 7d6882c2bd3..26372afc28e 100644 --- a/homeassistant/components/ovo_energy/translations/ko.json +++ b/homeassistant/components/ovo_energy/translations/ko.json @@ -1,9 +1,7 @@ { "config": { "error": { - "already_configured": "\uacc4\uc815\uc740 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "authorization_error": "\uc778\uc99d \uc624\ub958\uc785\ub2c8\ub2e4. \uc790\uaca9 \uc99d\uba85\uc744 \ud655\uc778\ud558\uc2ed\uc2dc\uc624.", - "connection_error": "\uc5f0\uacb0 \uc2e4\ud328" + "already_configured": "\uacc4\uc815\uc740 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "step": { "user": { diff --git a/homeassistant/components/ovo_energy/translations/lb.json b/homeassistant/components/ovo_energy/translations/lb.json index 74d4f949b43..0e007924b6a 100644 --- a/homeassistant/components/ovo_energy/translations/lb.json +++ b/homeassistant/components/ovo_energy/translations/lb.json @@ -2,8 +2,8 @@ "config": { "error": { "already_configured": "Kont ass scho konfigur\u00e9iert", - "authorization_error": "Feeler bei der Autorisatioun. Iwwerpr\u00e9if deng Verbindungs Informatiounen.", - "connection_error": "Feeler beim verbannen" + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "user": { diff --git a/homeassistant/components/ovo_energy/translations/nl.json b/homeassistant/components/ovo_energy/translations/nl.json index a66b0083373..cf9f264a618 100644 --- a/homeassistant/components/ovo_energy/translations/nl.json +++ b/homeassistant/components/ovo_energy/translations/nl.json @@ -1,7 +1,8 @@ { "config": { "error": { - "already_configured": "Account is al geconfigureerd" + "already_configured": "Account is al geconfigureerd", + "invalid_auth": "Ongeldige authenticatie" }, "step": { "user": { diff --git a/homeassistant/components/ovo_energy/translations/no.json b/homeassistant/components/ovo_energy/translations/no.json index 4a5bce8f467..72b69e43b9b 100644 --- a/homeassistant/components/ovo_energy/translations/no.json +++ b/homeassistant/components/ovo_energy/translations/no.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Kontoen er allerede konfigurert", - "authorization_error": "Autoriseringsfeil. Sjekk legitimasjonsbeskrivelsen.", "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes", "invalid_auth": "Ugyldig godkjenning" }, "step": { @@ -13,8 +11,8 @@ "password": "Passord", "username": "Brukernavn" }, - "description": "Sett opp en OVO Energy-forekomst for \u00e5 f\u00e5 tilgang til energibruken din.", - "title": "Legg til OVO Energikonto" + "description": "Sett opp en OVO Energy-forekomst for \u00e5 f\u00e5 tilgang til effektbruken din", + "title": "Legg til OVO Energy-konto" } } } diff --git a/homeassistant/components/ovo_energy/translations/pl.json b/homeassistant/components/ovo_energy/translations/pl.json index 8fe24ae98f9..541df85dc28 100644 --- a/homeassistant/components/ovo_energy/translations/pl.json +++ b/homeassistant/components/ovo_energy/translations/pl.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "Konto jest ju\u017c skonfigurowane", - "authorization_error": "B\u0142\u0105d autoryzacji. Sprawd\u017a swoje po\u015bwiadczenia.", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { diff --git a/homeassistant/components/ovo_energy/translations/pt-BR.json b/homeassistant/components/ovo_energy/translations/pt-BR.json deleted file mode 100644 index 0a40f65af5e..00000000000 --- a/homeassistant/components/ovo_energy/translations/pt-BR.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "error": { - "connection_error": "Falha na conex\u00e3o" - } - } -} \ No newline at end of file diff --git a/homeassistant/components/ovo_energy/translations/pt.json b/homeassistant/components/ovo_energy/translations/pt.json index c49725f2fd4..3fbf1797b31 100644 --- a/homeassistant/components/ovo_energy/translations/pt.json +++ b/homeassistant/components/ovo_energy/translations/pt.json @@ -1,8 +1,7 @@ { "config": { "error": { - "already_configured": "Conta j\u00e1 configurada", - "connection_error": "Falha na liga\u00e7\u00e3o" + "already_configured": "Conta j\u00e1 configurada" }, "step": { "user": { diff --git a/homeassistant/components/ovo_energy/translations/ru.json b/homeassistant/components/ovo_energy/translations/ru.json index 5993f408e20..08f2ce89b0d 100644 --- a/homeassistant/components/ovo_energy/translations/ru.json +++ b/homeassistant/components/ovo_energy/translations/ru.json @@ -2,9 +2,7 @@ "config": { "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.", - "authorization_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { diff --git a/homeassistant/components/ovo_energy/translations/zh-Hant.json b/homeassistant/components/ovo_energy/translations/zh-Hant.json index 91a6f9ab90e..a6ba2f8b624 100644 --- a/homeassistant/components/ovo_energy/translations/zh-Hant.json +++ b/homeassistant/components/ovo_energy/translations/zh-Hant.json @@ -2,9 +2,7 @@ "config": { "error": { "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "authorization_error": "\u8a8d\u8b49\u932f\u8aa4\u3002\u8acb\u78ba\u8a8d\u6191\u8b49\u3002", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { diff --git a/homeassistant/components/owntracks/translations/bg.json b/homeassistant/components/owntracks/translations/bg.json index 5e86cd92b4b..1e6cc45107a 100644 --- a/homeassistant/components/owntracks/translations/bg.json +++ b/homeassistant/components/owntracks/translations/bg.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\n\n \u0412 Android \u043e\u0442\u0432\u043e\u0440\u0435\u0442\u0435 [\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u0442\u043e OwnTracks]({android_url}), \u043f\u0440\u0435\u043c\u0438\u043d\u0435\u0442\u0435 \u043a\u044a\u043c Preferences - > Connection. \u041f\u0440\u043e\u043c\u0435\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438: \n - Mode: Private HTTP\n - Host: {webhook_url} \n - Identification: \n - Username: ` ` \n - Device ID: ` ` \n\n \u0412 iOS \u043e\u0442\u0432\u043e\u0440\u0435\u0442\u0435 [\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u0442\u043e OwnTracks]({ios_url}), \u0434\u043e\u043a\u043e\u0441\u043d\u0435\u0442\u0435 (i) \u0438\u043a\u043e\u043d\u0430\u0442\u0430 \u0432 \u0433\u043e\u0440\u043d\u0438\u044f \u043b\u044f\u0432 \u044a\u0433\u044a\u043b - > Settings. \u041f\u0440\u043e\u043c\u0435\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438: \n - Mode: HTTP \n - URL: {webhook_url} \n - Turn on authentication \n - UserID: ` ` \n\n {secret} \n \n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f." }, diff --git a/homeassistant/components/owntracks/translations/ca.json b/homeassistant/components/owntracks/translations/ca.json index c7cf0bb457a..236614d0619 100644 --- a/homeassistant/components/owntracks/translations/ca.json +++ b/homeassistant/components/owntracks/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "create_entry": { diff --git a/homeassistant/components/owntracks/translations/cs.json b/homeassistant/components/owntracks/translations/cs.json index dcac60be3b1..d242a1275f1 100644 --- a/homeassistant/components/owntracks/translations/cs.json +++ b/homeassistant/components/owntracks/translations/cs.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "one_instance_allowed": "Povolena je pouze jedna instance.", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "create_entry": { - "default": "\n\nV syst\u00e9mu Android otev\u0159ete aplikaci [OwnTracks]({android_url}) a p\u0159ejd\u011bte na P\u0159edvolby -> P\u0159ipojen\u00ed. Zm\u011b\u0148te n\u00e1sleduj\u00edc\u00ed nastaven\u00ed: \n - Re\u017eim: Soukrom\u00e9 HTTP \n - Hostitel: {webhook_url} \n - Identifikace: \n - U\u017eivatelsk\u00e9 jm\u00e9no: ` ' \n - ID za\u0159\u00edzen\u00ed: ` ' \n\nV aplikaci iOS otev\u0159ete [aplikaci OwnTracks]({ios_url}), klepn\u011bte na ikonu (i) vlevo naho\u0159e - > Nastaven\u00ed. Zm\u011b\u0148te n\u00e1sleduj\u00edc\u00ed nastaven\u00ed: \n - Re\u017eim: HTTP \n - URL: {webhook_url} \n - Zapn\u011bte ov\u011b\u0159ov\u00e1n\u00ed \n - ID u\u017eivatele: ` ' \n\n {secret} \n \n V\u00edce informac\u00ed naleznete v [dokumentaci]({docs_url})." + "default": "\n\nV syst\u00e9mu Android otev\u0159ete aplikaci [OwnTracks]({android_url}) a p\u0159ejd\u011bte na P\u0159edvolby -> P\u0159ipojen\u00ed. Zm\u011b\u0148te n\u00e1sleduj\u00edc\u00ed nastaven\u00ed: \n - Re\u017eim: Soukrom\u00e9 HTTP \n - Hostitel: {webhook_url} \n - Identifikace: \n - U\u017eivatelsk\u00e9 jm\u00e9no: `''` \n - ID za\u0159\u00edzen\u00ed: `''`\n\nV syst\u00e9mu iOS otev\u0159ete [aplikaci OwnTracks]({ios_url}), klepn\u011bte na ikonu (i) vlevo naho\u0159e -> Nastaven\u00ed. Zm\u011b\u0148te n\u00e1sleduj\u00edc\u00ed nastaven\u00ed: \n - Re\u017eim: HTTP \n - URL: {webhook_url} \n - Zapn\u011bte ov\u011b\u0159ov\u00e1n\u00ed \n - ID u\u017eivatele: `''` \n\n{secret}\n \nV\u00edce informac\u00ed naleznete v [dokumentaci]({docs_url})." }, "step": { "user": { - "description": "Opravdu chcete nastavit slu\u017ebu OwnTracks?", - "title": "Nastavit OwnTracks" + "description": "Opravdu chcete nastavit OwnTracks?", + "title": "Nastaven\u00ed OwnTracks" } } } diff --git a/homeassistant/components/owntracks/translations/da.json b/homeassistant/components/owntracks/translations/da.json index 83e99a166cd..809183c22ea 100644 --- a/homeassistant/components/owntracks/translations/da.json +++ b/homeassistant/components/owntracks/translations/da.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning" - }, "create_entry": { "default": "\n\nP\u00e5 Android skal du \u00e5bne [OwnTracks-appen]({android_url}), g\u00e5 til indstillinger -> forbindelse. Skift f\u00f8lgende indstillinger: \n - Tilstand: Privat HTTP\n - V\u00e6rt: {webhook_url}\n - Identifikation:\n - Brugernavn: ` ` \n - Enheds-id: ` ` \n\nP\u00e5 iOS skal du \u00e5bne [OwnTracks-appen]({ios_url}), tryk p\u00e5 (i) ikonet \u00f8verst til venstre -> indstillinger. Skift f\u00f8lgende indstillinger: \n - Tilstand: HTTP\n - URL: {webhook_url}\n - Aktiver godkendelse \n - Bruger ID: ` ` \n\n {secret}\n \n Se [dokumentationen]({docs_url}) for at f\u00e5 flere oplysninger." }, diff --git a/homeassistant/components/owntracks/translations/de.json b/homeassistant/components/owntracks/translations/de.json index 15f9de8ee70..9d832cc264a 100644 --- a/homeassistant/components/owntracks/translations/de.json +++ b/homeassistant/components/owntracks/translations/de.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Nur eine einzige Instanz ist notwendig." - }, "create_entry": { "default": "\n\n\u00d6ffnen unter Android [die OwnTracks-App]({android_url}) und gehe zu {android_url} - > Verbindung. \u00c4nder die folgenden Einstellungen: \n - Modus: Privates HTTP \n - Host: {webhook_url} \n - Identifizierung: \n - Benutzername: `''` \n - Ger\u00e4te-ID: `''` \n\n\u00d6ffnen unter iOS [die OwnTracks-App]({ios_url}) und tippe auf das Symbol (i) oben links - > Einstellungen. \u00c4nder die folgenden Einstellungen: \n - Modus: HTTP \n - URL: {webhook_url} \n - Aktivieren Sie die Authentifizierung \n - UserID: `''`\n\n {secret} \n \n Weitere Informationen findest du in der [Dokumentation]({docs_url})." }, diff --git a/homeassistant/components/owntracks/translations/en.json b/homeassistant/components/owntracks/translations/en.json index 9090cea70f2..870b7cdbe5c 100644 --- a/homeassistant/components/owntracks/translations/en.json +++ b/homeassistant/components/owntracks/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Only a single instance is necessary.", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "create_entry": { diff --git a/homeassistant/components/owntracks/translations/es-419.json b/homeassistant/components/owntracks/translations/es-419.json index 35ad2389693..c6ddb0c4d1f 100644 --- a/homeassistant/components/owntracks/translations/es-419.json +++ b/homeassistant/components/owntracks/translations/es-419.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "\n\n En Android, abra [la aplicaci\u00f3n OwnTracks] ( {android_url} ), vaya a preferencias - > conexi\u00f3n. Cambia las siguientes configuraciones: \n - Modo: HTTP privado \n - Anfitri\u00f3n: {webhook_url} \n - Identificaci\u00f3n: \n - Nombre de usuario: ` ` \n - ID del dispositivo: ` ` \n\n En iOS, abra [la aplicaci\u00f3n OwnTracks] ( {ios_url} ), toque el icono (i) en la parte superior izquierda - > configuraci\u00f3n. Cambia las siguientes configuraciones: \n - Modo: HTTP \n - URL: {webhook_url} \n - Activar autenticaci\u00f3n \n - ID de usuario: ` ` \n\n {secret} \n \n Consulte [la documentaci\u00f3n] ( {docs_url} ) para obtener m\u00e1s informaci\u00f3n." }, diff --git a/homeassistant/components/owntracks/translations/es.json b/homeassistant/components/owntracks/translations/es.json index 08b6fb5ec10..1832e701559 100644 --- a/homeassistant/components/owntracks/translations/es.json +++ b/homeassistant/components/owntracks/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Solo es necesaria una instancia.", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "create_entry": { diff --git a/homeassistant/components/owntracks/translations/et.json b/homeassistant/components/owntracks/translations/et.json index e59e01bef78..16ef569d9a4 100644 --- a/homeassistant/components/owntracks/translations/et.json +++ b/homeassistant/components/owntracks/translations/et.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Lubatud on ainult \u00fcks sidumine.", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "create_entry": { @@ -9,7 +8,8 @@ }, "step": { "user": { - "description": "Kas soovid OwnTracks'i seadistada?" + "description": "Kas soovid OwnTracks'i seadistada?", + "title": "Seadista OwnTracks" } } } diff --git a/homeassistant/components/owntracks/translations/fr.json b/homeassistant/components/owntracks/translations/fr.json index ba894ff43e7..0e753a455e0 100644 --- a/homeassistant/components/owntracks/translations/fr.json +++ b/homeassistant/components/owntracks/translations/fr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "create_entry": { diff --git a/homeassistant/components/owntracks/translations/hu.json b/homeassistant/components/owntracks/translations/hu.json index ab6cc91324a..b6bb7593906 100644 --- a/homeassistant/components/owntracks/translations/hu.json +++ b/homeassistant/components/owntracks/translations/hu.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Csak egyetlen konfigur\u00e1ci\u00f3 sz\u00fcks\u00e9ges." - }, "create_entry": { "default": "\n\nAndroidon, nyisd meg [az OwnTracks appot]({android_url}), menj a preferences -> connectionre. V\u00e1ltoztasd meg a al\u00e1bbi be\u00e1ll\u00edt\u00e1sokat:\n - Mode: Private HTTP\n - Host: {webhook_url}\n - Identification:\n - Username: ``\n - Device ID: ``\n\niOS-en, nyisd meg [az OwnTracks appot]({ios_url}), kattints az (i) ikonra bal oldalon fel\u00fcl -> settings. V\u00e1ltoztasd meg az al\u00e1bbi be\u00e1ll\u00edt\u00e1sokat:\n - Mode: HTTP\n - URL: {webhook_url}\n - Turn on authentication\n - UserID: ``\n\n{secret}\n\nN\u00e9zd meg [a dokument\u00e1ci\u00f3t]({docs_url}) tov\u00e1bbi inform\u00e1ci\u00f3k\u00e9rt." }, diff --git a/homeassistant/components/owntracks/translations/it.json b/homeassistant/components/owntracks/translations/it.json index 60485d590b2..50d6c30777c 100644 --- a/homeassistant/components/owntracks/translations/it.json +++ b/homeassistant/components/owntracks/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "\u00c8 necessaria una sola istanza.", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "create_entry": { diff --git a/homeassistant/components/owntracks/translations/ko.json b/homeassistant/components/owntracks/translations/ko.json index c1a5ce50e52..3cde37528c2 100644 --- a/homeassistant/components/owntracks/translations/ko.json +++ b/homeassistant/components/owntracks/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "\n\nAndroid \uc778 \uacbd\uc6b0, [OwnTracks \uc571]({android_url}) \uc744 \uc5f4\uace0 preferences -> connection \uc73c\ub85c \uc774\ub3d9\ud558\uc5ec \ub2e4\uc74c\uacfc \uac19\uc774 \uc124\uc815\ud574\uc8fc\uc138\uc694:\n - Mode: Private HTTP\n - Host: {webhook_url}\n - Identification:\n - Username: `''`\n - Device ID: `''`\n\niOS \uc778 \uacbd\uc6b0, [OwnTracks \uc571]({ios_url}) \uc744 \uc5f4\uace0 \uc67c\ucabd \uc0c1\ub2e8\uc758 (i) \uc544\uc774\ucf58\uc744 \ud0ed\ud558\uc5ec \uc124\uc815\uc73c\ub85c \uc774\ub3d9\ud558\uc5ec \ub2e4\uc74c\uacfc \uac19\uc774 \uc124\uc815\ud574\uc8fc\uc138\uc694:\n - Mode: HTTP\n - URL: {webhook_url}\n - Turn on authentication\n - UserID: `''`\n\n{secret} \n \n\uc790\uc138\ud55c \uc815\ubcf4\ub294 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/owntracks/translations/lb.json b/homeassistant/components/owntracks/translations/lb.json index 4c9cba9e6ca..f2e9ea664d3 100644 --- a/homeassistant/components/owntracks/translations/lb.json +++ b/homeassistant/components/owntracks/translations/lb.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { - "default": "\n\nOp Android, an [der OwnTracks App]({android_url}), g\u00e9i an Preferences -> Connection. \u00c4nnert folgend Astellungen:\n- Mode: Private HTTP\n- Host {webhool_url}\n- Identification:\n - Username: ``\n - Device ID: ``\n\nOp IOS, an [der OwnTracks App]({ios_url}), klick op (i) Ikon uewen l\u00e9nks -> Settings. \u00c4nnert folgend Astellungen:\n- Mode: HTTP\n- URL: {webhool_url}\n- Turn on authentication:\n- UserID: ``\n\n{secret}\n\nKuckt w.e.g. [Dokumentatioun]({docs_url}) fir m\u00e9i Informatiounen." + "default": "\n\nOp Android, an [der OwnTracks App]({android_url}), g\u00e9i an Preferences -> Connection. \u00c4nnert folgend Astellungen:\n- Mode: Private HTTP\n- Host {webhook_url}\n- Identification:\n - Username: ``\n - Device ID: ``\n\nOp IOS, an [der OwnTracks App]({ios_url}), klick op (i) Ikon uewen l\u00e9nks -> Settings. \u00c4nnert folgend Astellungen:\n- Mode: HTTP\n- URL: {webhook_url}\n- Turn on authentication:\n- UserID: ``\n\n{secret}\n\nKuck w.e.g. [Dokumentatioun]({docs_url}) fir m\u00e9i Informatiounen." }, "step": { "user": { diff --git a/homeassistant/components/owntracks/translations/nl.json b/homeassistant/components/owntracks/translations/nl.json index f239ef1558c..2d97724661c 100644 --- a/homeassistant/components/owntracks/translations/nl.json +++ b/homeassistant/components/owntracks/translations/nl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/owntracks/translations/no.json b/homeassistant/components/owntracks/translations/no.json index 4be99b4d371..923fbab2440 100644 --- a/homeassistant/components/owntracks/translations/no.json +++ b/homeassistant/components/owntracks/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "create_entry": { diff --git a/homeassistant/components/owntracks/translations/pl.json b/homeassistant/components/owntracks/translations/pl.json index bc9be84b702..c4499800eda 100644 --- a/homeassistant/components/owntracks/translations/pl.json +++ b/homeassistant/components/owntracks/translations/pl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "create_entry": { @@ -9,8 +8,8 @@ }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 OwnTracks?", - "title": "Konfiguracja OwnTracks" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", + "title": "Konfiguracja OwnTracks" } } } diff --git a/homeassistant/components/owntracks/translations/pt-BR.json b/homeassistant/components/owntracks/translations/pt-BR.json index e8d19233bbd..af1c939be36 100644 --- a/homeassistant/components/owntracks/translations/pt-BR.json +++ b/homeassistant/components/owntracks/translations/pt-BR.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "\n\n No Android, abra [o aplicativo OwnTracks] ( {android_url} ), v\u00e1 para prefer\u00eancias - > conex\u00e3o. Altere as seguintes configura\u00e7\u00f5es: \n - Modo: HTTP privado \n - Anfitri\u00e3o: {webhook_url} \n - Identifica\u00e7\u00e3o: \n - Nome de usu\u00e1rio: ` \n - ID do dispositivo: ` ` \n\n No iOS, abra o aplicativo OwnTracks ( {ios_url} ), toque no \u00edcone (i) no canto superior esquerdo - > configura\u00e7\u00f5es. Altere as seguintes configura\u00e7\u00f5es: \n - Modo: HTTP \n - URL: {webhook_url} \n - Ativar a autentica\u00e7\u00e3o \n - UserID: ` ` \n\n {secret} \n \n Veja [a documenta\u00e7\u00e3o] ( {docs_url} ) para mais informa\u00e7\u00f5es." }, diff --git a/homeassistant/components/owntracks/translations/pt.json b/homeassistant/components/owntracks/translations/pt.json index 8aa3b52e9cc..dbc8db55d63 100644 --- a/homeassistant/components/owntracks/translations/pt.json +++ b/homeassistant/components/owntracks/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "\n\n No Android, abra [o aplicativo OwnTracks] ( {android_url} ), v\u00e1 para prefer\u00eancias - > conex\u00e3o. Altere as seguintes configura\u00e7\u00f5es: \n - Modo: HTTP privado \n - Anfitri\u00e3o: {webhook_url} \n - Identifica\u00e7\u00e3o: \n - Nome de usu\u00e1rio: ` \n - ID do dispositivo: ` ` \n\n No iOS, abra [o aplicativo OwnTracks] ( {ios_url} ), toque no \u00edcone (i) no canto superior esquerdo - > configura\u00e7\u00f5es. Altere as seguintes configura\u00e7\u00f5es: \n - Modo: HTTP \n - URL: {webhook_url} \n - Ativar autentica\u00e7\u00e3o \n - UserID: ` ` \n\n {secret} \n \n Veja [a documenta\u00e7\u00e3o] ( {docs_url} ) para mais informa\u00e7\u00f5es." }, diff --git a/homeassistant/components/owntracks/translations/ru.json b/homeassistant/components/owntracks/translations/ru.json index c04394820f9..bc38694d2a8 100644 --- a/homeassistant/components/owntracks/translations/ru.json +++ b/homeassistant/components/owntracks/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "create_entry": { diff --git a/homeassistant/components/owntracks/translations/sl.json b/homeassistant/components/owntracks/translations/sl.json index f3909591bef..9c75e9a9537 100644 --- a/homeassistant/components/owntracks/translations/sl.json +++ b/homeassistant/components/owntracks/translations/sl.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "\n\n V Androidu odprite aplikacijo OwnTracks ( {android_url} ) in pojdite na {android_url} nastavitve - > povezave. Spremenite naslednje nastavitve: \n - Na\u010din: zasebni HTTP \n - gostitelj: {webhook_url} \n - Identifikacija: \n - Uporabni\u0161ko ime: ` ` \n - ID naprave: ` ` \n\n V iOS-ju odprite aplikacijo OwnTracks ( {ios_url} ), tapnite ikono (i) v zgornjem levem kotu - > nastavitve. Spremenite naslednje nastavitve: \n - na\u010din: HTTP \n - URL: {webhook_url} \n - Vklopite preverjanje pristnosti \n - UserID: ` ` \n\n {secret} \n \n Za ve\u010d informacij si oglejte [dokumentacijo] ( {docs_url} )." }, diff --git a/homeassistant/components/owntracks/translations/sv.json b/homeassistant/components/owntracks/translations/sv.json index de605d6b52f..fd2162f153b 100644 --- a/homeassistant/components/owntracks/translations/sv.json +++ b/homeassistant/components/owntracks/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "\n\n P\u00e5 Android, \u00f6ppna [OwnTracks-appen]({android_url}), g\u00e5 till inst\u00e4llningar -> anslutning. \u00c4ndra f\u00f6ljande inst\u00e4llningar: \n - L\u00e4ge: Privat HTTP \n - V\u00e4rden: {webhook_url}\n - Identifiering: \n - Anv\u00e4ndarnamn: ``\n - Enhets-ID: `` \n\n P\u00e5 IOS, \u00f6ppna [OwnTracks-appen]({ios_url}), tryck p\u00e5 (i) ikonen i \u00f6vre v\u00e4nstra h\u00f6rnet -> inst\u00e4llningarna. \u00c4ndra f\u00f6ljande inst\u00e4llningar: \n - L\u00e4ge: HTTP \n - URL: {webhook_url}\n - Sl\u00e5 p\u00e5 autentisering \n - UserID: `` \n\n {secret} \n \n Se [dokumentationen]({docs_url}) f\u00f6r mer information." }, diff --git a/homeassistant/components/owntracks/translations/uk.json b/homeassistant/components/owntracks/translations/uk.json index 8f4cdebbcd4..f1f31864242 100644 --- a/homeassistant/components/owntracks/translations/uk.json +++ b/homeassistant/components/owntracks/translations/uk.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "\u041f\u043e\u0442\u0440\u0456\u0431\u043d\u043e \u043b\u0438\u0448\u0435 \u043e\u0434\u0438\u043d \u0435\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440." - }, "step": { "user": { "description": "\u0412\u0438 \u0432\u043f\u0435\u0432\u043d\u0435\u043d\u0456, \u0449\u043e \u0445\u043e\u0447\u0435\u0442\u0435 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u0442\u0438 OwnTracks?", diff --git a/homeassistant/components/owntracks/translations/zh-Hans.json b/homeassistant/components/owntracks/translations/zh-Hans.json index fe1dc22d92f..6954b838d04 100644 --- a/homeassistant/components/owntracks/translations/zh-Hans.json +++ b/homeassistant/components/owntracks/translations/zh-Hans.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "one_instance_allowed": "\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u662f\u5fc5\u9700\u7684\u3002" - }, "create_entry": { "default": "\n\n\u5728 Android \u8bbe\u5907\u4e0a\uff0c\u6253\u5f00 [OwnTracks APP]({android_url})\uff0c\u524d\u5f80 Preferences -> Connection\u3002\u4fee\u6539\u4ee5\u4e0b\u8bbe\u5b9a\uff1a\n - Mode: Private HTTP\n - Host: {webhook_url}\n - Identification:\n - Username: ``\n - Device ID: ``\n\n\u5728 iOS \u8bbe\u5907\u4e0a\uff0c\u6253\u5f00 [OwnTracks APP]({ios_url})\uff0c\u70b9\u51fb\u5de6\u4e0a\u89d2\u7684 (i) \u56fe\u6807-> Settings\u3002\u4fee\u6539\u4ee5\u4e0b\u8bbe\u5b9a\uff1a\n - Mode: HTTP\n - URL: {webhook_url}\n - Turn on authentication\n - UserID: ``\n\n{secret}\n\n\u8bf7\u53c2\u9605[\u6587\u6863]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u591a\u4fe1\u606f\u3002" }, diff --git a/homeassistant/components/owntracks/translations/zh-Hant.json b/homeassistant/components/owntracks/translations/zh-Hant.json index 4d9871ffae2..b89f1472478 100644 --- a/homeassistant/components/owntracks/translations/zh-Hant.json +++ b/homeassistant/components/owntracks/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u7269\u4ef6\u5373\u53ef\u3002", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "create_entry": { diff --git a/homeassistant/components/ozw/__init__.py b/homeassistant/components/ozw/__init__.py index f57d737bf36..5706b75efb8 100644 --- a/homeassistant/components/ozw/__init__.py +++ b/homeassistant/components/ozw/__init__.py @@ -20,6 +20,7 @@ from openzwavemqtt.models.value import OZWValue import voluptuous as vol from homeassistant.components import mqtt +from homeassistant.components.hassio.handler import HassioAPIError from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.device_registry import async_get_registry as get_dev_reg @@ -27,6 +28,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send from . import const from .const import ( + CONF_INTEGRATION_CREATED_ADDON, DATA_UNSUBSCRIBE, DOMAIN, MANAGER, @@ -265,6 +267,22 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): return True +async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Remove a config entry.""" + if not entry.data.get(CONF_INTEGRATION_CREATED_ADDON): + return + + try: + await hass.components.hassio.async_stop_addon("core_zwave") + except HassioAPIError as err: + _LOGGER.error("Failed to stop the OpenZWave add-on: %s", err) + return + try: + await hass.components.hassio.async_uninstall_addon("core_zwave") + except HassioAPIError as err: + _LOGGER.error("Failed to uninstall the OpenZWave add-on: %s", err) + + async def async_handle_remove_node(hass: HomeAssistant, node: OZWNode): """Handle the removal of a Z-Wave node, removing all traces in device/entity registry.""" dev_registry = await get_dev_reg(hass) diff --git a/homeassistant/components/ozw/config_flow.py b/homeassistant/components/ozw/config_flow.py index 3153324322e..1c0ccdefa70 100644 --- a/homeassistant/components/ozw/config_flow.py +++ b/homeassistant/components/ozw/config_flow.py @@ -1,10 +1,26 @@ """Config flow for ozw integration.""" -from homeassistant import config_entries +import logging +import voluptuous as vol + +from homeassistant import config_entries +from homeassistant.core import callback +from homeassistant.data_entry_flow import AbortFlow + +from .const import CONF_INTEGRATION_CREATED_ADDON from .const import DOMAIN # pylint:disable=unused-import +_LOGGER = logging.getLogger(__name__) + +CONF_ADDON_DEVICE = "device" +CONF_ADDON_NETWORK_KEY = "network_key" +CONF_NETWORK_KEY = "network_key" +CONF_USB_PATH = "usb_path" +CONF_USE_ADDON = "use_addon" TITLE = "OpenZWave" +ON_SUPERVISOR_SCHEMA = vol.Schema({vol.Optional(CONF_USE_ADDON, default=False): bool}) + class DomainConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow for ozw.""" @@ -12,13 +28,156 @@ class DomainConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH + def __init__(self): + """Set up flow instance.""" + self.addon_config = None + self.network_key = None + self.usb_path = None + self.use_addon = False + # If we install the add-on we should uninstall it on entry remove. + self.integration_created_addon = False + async def async_step_user(self, user_input=None): """Handle the initial step.""" if self._async_current_entries(): return self.async_abort(reason="single_instance_allowed") + + # Currently all flow results need the MQTT integration. + # This will change when we have the direct MQTT client connection. + # When that is implemented, move this check to _async_use_mqtt_integration. if "mqtt" not in self.hass.config.components: return self.async_abort(reason="mqtt_required") - if user_input is not None: - return self.async_create_entry(title=TITLE, data={}) - return self.async_show_form(step_id="user") + if not self.hass.components.hassio.is_hassio(): + return self._async_use_mqtt_integration() + + return await self.async_step_on_supervisor() + + def _async_create_entry_from_vars(self): + """Return a config entry for the flow.""" + return self.async_create_entry( + title=TITLE, + data={ + CONF_USB_PATH: self.usb_path, + CONF_NETWORK_KEY: self.network_key, + CONF_USE_ADDON: self.use_addon, + CONF_INTEGRATION_CREATED_ADDON: self.integration_created_addon, + }, + ) + + @callback + def _async_use_mqtt_integration(self): + """Handle logic when using the MQTT integration. + + This is the entry point for the logic that is needed + when this integration will depend on the MQTT integration. + """ + return self._async_create_entry_from_vars() + + async def async_step_on_supervisor(self, user_input=None): + """Handle logic when on Supervisor host.""" + if user_input is None: + return self.async_show_form( + step_id="on_supervisor", data_schema=ON_SUPERVISOR_SCHEMA + ) + if not user_input[CONF_USE_ADDON]: + return self._async_create_entry_from_vars() + + self.use_addon = True + + if await self._async_is_addon_running(): + return self._async_create_entry_from_vars() + + if await self._async_is_addon_installed(): + return await self.async_step_start_addon() + + return await self.async_step_install_addon() + + async def async_step_install_addon(self): + """Install OpenZWave add-on.""" + try: + await self.hass.components.hassio.async_install_addon("core_zwave") + except self.hass.components.hassio.HassioAPIError as err: + _LOGGER.error("Failed to install OpenZWave add-on: %s", err) + return self.async_abort(reason="addon_install_failed") + self.integration_created_addon = True + + return await self.async_step_start_addon() + + async def async_step_start_addon(self, user_input=None): + """Ask for config and start OpenZWave add-on.""" + if self.addon_config is None: + self.addon_config = await self._async_get_addon_config() + + errors = {} + + if user_input is not None: + self.network_key = user_input[CONF_NETWORK_KEY] + self.usb_path = user_input[CONF_USB_PATH] + + new_addon_config = {CONF_ADDON_DEVICE: self.usb_path} + if self.network_key: + new_addon_config[CONF_ADDON_NETWORK_KEY] = self.network_key + + if new_addon_config != self.addon_config: + await self._async_set_addon_config(new_addon_config) + + try: + await self.hass.components.hassio.async_start_addon("core_zwave") + except self.hass.components.hassio.HassioAPIError as err: + _LOGGER.error("Failed to start OpenZWave add-on: %s", err) + errors["base"] = "addon_start_failed" + else: + return self._async_create_entry_from_vars() + + self.usb_path = self.addon_config.get(CONF_ADDON_DEVICE, "") + self.network_key = self.addon_config.get(CONF_ADDON_NETWORK_KEY, "") + + data_schema = vol.Schema( + { + vol.Required(CONF_USB_PATH, default=self.usb_path): str, + vol.Optional(CONF_NETWORK_KEY, default=self.network_key): str, + } + ) + + return self.async_show_form( + step_id="start_addon", data_schema=data_schema, errors=errors + ) + + async def _async_get_addon_info(self): + """Return and cache OpenZWave add-on info.""" + try: + addon_info = await self.hass.components.hassio.async_get_addon_info( + "core_zwave" + ) + except self.hass.components.hassio.HassioAPIError as err: + _LOGGER.error("Failed to get OpenZWave add-on info: %s", err) + raise AbortFlow("addon_info_failed") from err + + return addon_info + + async def _async_is_addon_running(self): + """Return True if OpenZWave add-on is running.""" + addon_info = await self._async_get_addon_info() + return addon_info["state"] == "started" + + async def _async_is_addon_installed(self): + """Return True if OpenZWave add-on is installed.""" + addon_info = await self._async_get_addon_info() + return addon_info["version"] is not None + + async def _async_get_addon_config(self): + """Get OpenZWave add-on config.""" + addon_info = await self._async_get_addon_info() + return addon_info["options"] + + async def _async_set_addon_config(self, config): + """Set OpenZWave add-on config.""" + options = {"options": config} + try: + await self.hass.components.hassio.async_set_addon_options( + "core_zwave", options + ) + except self.hass.components.hassio.HassioAPIError as err: + _LOGGER.error("Failed to set OpenZWave add-on config: %s", err) + raise AbortFlow("addon_set_config_failed") from err diff --git a/homeassistant/components/ozw/const.py b/homeassistant/components/ozw/const.py index 8e5007a8419..160b251eeca 100644 --- a/homeassistant/components/ozw/const.py +++ b/homeassistant/components/ozw/const.py @@ -10,6 +10,9 @@ from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN DOMAIN = "ozw" DATA_UNSUBSCRIBE = "unsubscribe" + +CONF_INTEGRATION_CREATED_ADDON = "integration_created_addon" + PLATFORMS = [ BINARY_SENSOR_DOMAIN, COVER_DOMAIN, diff --git a/homeassistant/components/ozw/manifest.json b/homeassistant/components/ozw/manifest.json index 6402f611c74..fa25f984076 100644 --- a/homeassistant/components/ozw/manifest.json +++ b/homeassistant/components/ozw/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/ozw", "requirements": [ - "python-openzwave-mqtt==1.2.2" + "python-openzwave-mqtt==1.3.2" ], "after_dependencies": [ "mqtt" diff --git a/homeassistant/components/ozw/strings.json b/homeassistant/components/ozw/strings.json index 88f8911db0d..52317b3d6a8 100644 --- a/homeassistant/components/ozw/strings.json +++ b/homeassistant/components/ozw/strings.json @@ -1,13 +1,25 @@ { "config": { "step": { - "user": { - "title": "Confirm set up" + "on_supervisor": { + "title": "Select connection method", + "description": "Do you want to use the OpenZWave Supervisor add-on?", + "data": {"use_addon": "Use the OpenZWave Supervisor add-on"} + }, + "start_addon": { + "title": "Enter the OpenZWave add-on configuration", + "data": {"usb_path": "[%key:common::config_flow::data::usb_path%]", "network_key": "Network Key"} } }, "abort": { + "addon_info_failed": "Failed to get OpenZWave add-on info.", + "addon_install_failed": "Failed to install the OpenZWave add-on.", + "addon_set_config_failed": "Failed to set OpenZWave configuration.", "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", "mqtt_required": "The MQTT integration is not set up" + }, + "error": { + "addon_start_failed": "Failed to start the OpenZWave add-on. Check the configuration." } } } diff --git a/homeassistant/components/ozw/translations/ca.json b/homeassistant/components/ozw/translations/ca.json index 3a1fdb29ba1..6010da17b7b 100644 --- a/homeassistant/components/ozw/translations/ca.json +++ b/homeassistant/components/ozw/translations/ca.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "No s'ha pogut obtenir la informaci\u00f3 del complement OpenZWave.", + "addon_install_failed": "No s'ha pogut instal\u00b7lar el complement OpenZWave.", + "addon_set_config_failed": "No s'ha pogut establir la configuraci\u00f3 d'OpenZWave.", "mqtt_required": "La integraci\u00f3 MQTT no est\u00e0 configurada", - "one_instance_allowed": "La integraci\u00f3 nom\u00e9s admet una inst\u00e0ncia Z-Wave", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, + "error": { + "addon_start_failed": "No s'ha pogut iniciar el complement OpenZWave. Comprova la configuraci\u00f3." + }, "step": { - "user": { - "title": "Confirmaci\u00f3 de configuraci\u00f3" + "on_supervisor": { + "data": { + "use_addon": "Utilitza el complement OpenZWave Supervisor" + }, + "description": "Voleu utilitzar el complement OpenZWave Supervisor?", + "title": "Selecciona el m\u00e8tode de connexi\u00f3" + }, + "start_addon": { + "data": { + "network_key": "Clau de xarxa", + "usb_path": "Ruta del port USB del dispositiu" + }, + "title": "Introdueix la configuraci\u00f3 del complement OpenZWave" } } } diff --git a/homeassistant/components/ozw/translations/cs.json b/homeassistant/components/ozw/translations/cs.json index fa169785628..621e48bab7e 100644 --- a/homeassistant/components/ozw/translations/cs.json +++ b/homeassistant/components/ozw/translations/cs.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "Nepoda\u0159ilo se z\u00edskat informace o dopl\u0148ku OpenZWave.", + "addon_install_failed": "Instalace dopl\u0148ku OpenZWave se nezda\u0159ila.", + "addon_set_config_failed": "Nepoda\u0159ilo se nastavit OpenZWave.", "mqtt_required": "Integrace MQTT nen\u00ed nastavena", - "one_instance_allowed": "Integrace podporuje pouze jednu instanci Z-Wave", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, + "error": { + "addon_start_failed": "Spu\u0161t\u011bn\u00ed dopl\u0148ku OpenZWave se nezda\u0159ilo. Zkontrolujte konfiguraci." + }, "step": { - "user": { - "title": "Potvr\u010fte nastaven\u00ed" + "on_supervisor": { + "data": { + "use_addon": "Pou\u017e\u00edt dopln\u011bk OpenZWave pro Supervisor" + }, + "description": "Chcete pou\u017e\u00edt dopln\u011bk OpenZWave pro Supervisor?", + "title": "Vyberte metodu p\u0159ipojen\u00ed" + }, + "start_addon": { + "data": { + "network_key": "S\u00ed\u0165ov\u00fd kl\u00ed\u010d", + "usb_path": "Cesta k USB za\u0159\u00edzen\u00ed" + }, + "title": "Zadejte konfiguraci dopl\u0148ku OpenZWave" } } } diff --git a/homeassistant/components/ozw/translations/de.json b/homeassistant/components/ozw/translations/de.json index 79393cbf865..81a2390cc8b 100644 --- a/homeassistant/components/ozw/translations/de.json +++ b/homeassistant/components/ozw/translations/de.json @@ -1,13 +1,7 @@ { "config": { "abort": { - "mqtt_required": "Die MQTT-Integration ist nicht eingerichtet", - "one_instance_allowed": "Die Integration unterst\u00fctzt nur eine Z-Wave-Instanz" - }, - "step": { - "user": { - "title": "Einrichtung best\u00e4tigen" - } + "mqtt_required": "Die MQTT-Integration ist nicht eingerichtet" } } } \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/en.json b/homeassistant/components/ozw/translations/en.json index 4e41ee58d11..e028e1923ae 100644 --- a/homeassistant/components/ozw/translations/en.json +++ b/homeassistant/components/ozw/translations/en.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "Failed to get OpenZWave add-on info.", + "addon_install_failed": "Failed to install the OpenZWave add-on.", + "addon_set_config_failed": "Failed to set OpenZWave configuration.", "mqtt_required": "The MQTT integration is not set up", - "one_instance_allowed": "The integration only supports one Z-Wave instance", "single_instance_allowed": "Already configured. Only a single configuration possible." }, + "error": { + "addon_start_failed": "Failed to start the OpenZWave add-on. Check the configuration." + }, "step": { - "user": { - "title": "Confirm set up" + "on_supervisor": { + "data": { + "use_addon": "Use the OpenZWave Supervisor add-on" + }, + "description": "Do you want to use the OpenZWave Supervisor add-on?", + "title": "Select connection method" + }, + "start_addon": { + "data": { + "network_key": "Network Key", + "usb_path": "USB Device Path" + }, + "title": "Enter the OpenZWave add-on configuration" } } } diff --git a/homeassistant/components/ozw/translations/es.json b/homeassistant/components/ozw/translations/es.json index 2f76c540105..8d39e611601 100644 --- a/homeassistant/components/ozw/translations/es.json +++ b/homeassistant/components/ozw/translations/es.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "No se pudo obtener la informaci\u00f3n del complemento de OpenZWave.", + "addon_install_failed": "No se pudo instalar el complemento de OpenZWave.", + "addon_set_config_failed": "No se pudo establecer la configuraci\u00f3n de OpenZWave.", "mqtt_required": "La integraci\u00f3n de MQTT no est\u00e1 configurada", - "one_instance_allowed": "La integraci\u00f3n solo admite una instancia de Z-Wave", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, + "error": { + "addon_start_failed": "No se pudo iniciar el complemento OpenZWave. Verifica la configuraci\u00f3n." + }, "step": { - "user": { - "title": "Confirmar configuraci\u00f3n" + "on_supervisor": { + "data": { + "use_addon": "Usar el complemento de supervisor de OpenZWave" + }, + "description": "\u00bfQuiere utilizar el complemento de Supervisor de OpenZWave?", + "title": "Selecciona el m\u00e9todo de conexi\u00f3n" + }, + "start_addon": { + "data": { + "network_key": "Clave de red", + "usb_path": "Ruta del dispositivo USB" + }, + "title": "Introduce la configuraci\u00f3n del complemento OpenZWave" } } } diff --git a/homeassistant/components/ozw/translations/et.json b/homeassistant/components/ozw/translations/et.json index 16196205aec..180e2a51542 100644 --- a/homeassistant/components/ozw/translations/et.json +++ b/homeassistant/components/ozw/translations/et.json @@ -1,8 +1,30 @@ { "config": { "abort": { + "addon_info_failed": "OpenZWave'i lisandmooduli teabe hankimine nurjus.", + "addon_install_failed": "OpenZWave'i lisandmooduli paigaldamine nurjus.", + "addon_set_config_failed": "OpenZWave'i konfiguratsiooni seadistamine eba\u00f5nnestus.", "mqtt_required": "MQTT sidumine pole seadistatud", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + }, + "error": { + "addon_start_failed": "OpenZWave'i lisandmooduli k\u00e4ivitamine nurjus. Kontrolli s\u00e4tteid." + }, + "step": { + "on_supervisor": { + "data": { + "use_addon": "Kasuta OpenZWave Supervisori lisandmoodulit" + }, + "description": "Kas soovid kasutada OpenZWave'i halduri lisandmoodulit?", + "title": "Vali \u00fchendusviis" + }, + "start_addon": { + "data": { + "network_key": "V\u00f5rgu v\u00f5ti", + "usb_path": "USB seadme rada" + }, + "title": "Sisesta OpenZWave'i lisandmooduli seaded" + } } } } \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/fi.json b/homeassistant/components/ozw/translations/fi.json deleted file mode 100644 index 471c885a8b4..00000000000 --- a/homeassistant/components/ozw/translations/fi.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "config": { - "step": { - "user": { - "title": "Vahvista m\u00e4\u00e4ritt\u00e4minen" - } - } - } -} \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/fr.json b/homeassistant/components/ozw/translations/fr.json index 0c6c1e82da5..cbf9bfb6bd4 100644 --- a/homeassistant/components/ozw/translations/fr.json +++ b/homeassistant/components/ozw/translations/fr.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "Impossible d\u2019obtenir des informations de l'add-on OpenZWave.", + "addon_install_failed": "\u00c9chec de l\u2019installation de l'add-on OpenZWave.", + "addon_set_config_failed": "\u00c9chec de la configuration OpenZWave.", "mqtt_required": "L'int\u00e9gration MQTT n'est pas configur\u00e9e", - "one_instance_allowed": "L'int\u00e9gration ne prend en charge qu'une seule instance Z-Wave", "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, + "error": { + "addon_start_failed": "\u00c9chec du d\u00e9marrage de l'add-on OpenZWave. V\u00e9rifiez la configuration." + }, "step": { - "user": { - "title": "Confirmer la configuration" + "on_supervisor": { + "data": { + "use_addon": "Utiliser l'add-on OpenZWave Supervisor" + }, + "description": "Souhaitez-vous utiliser l'add-on OpenZWave Supervisor ?", + "title": "S\u00e9lectionner la m\u00e9thode de connexion" + }, + "start_addon": { + "data": { + "network_key": "Cl\u00e9 r\u00e9seau", + "usb_path": "Chemin du p\u00e9riph\u00e9rique USB" + }, + "title": "Entrez dans la configuration de l'add-on OpenZWave" } } } diff --git a/homeassistant/components/ozw/translations/it.json b/homeassistant/components/ozw/translations/it.json index f97be82b374..e03c71ae709 100644 --- a/homeassistant/components/ozw/translations/it.json +++ b/homeassistant/components/ozw/translations/it.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "Impossibile ottenere le informazioni sul componente aggiuntivo OpenZWave.", + "addon_install_failed": "Impossibile installare il componente aggiuntivo OpenZWave.", + "addon_set_config_failed": "Impossibile impostare la configurazione di OpenZWave.", "mqtt_required": "L'integrazione MQTT non \u00e8 impostata", - "one_instance_allowed": "L'integrazione supporta solo un'istanza Z-Wave", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, + "error": { + "addon_start_failed": "Impossibile avviare il componente aggiuntivo OpenZWave. Controlla la configurazione." + }, "step": { - "user": { - "title": "Confermare la configurazione" + "on_supervisor": { + "data": { + "use_addon": "Usa il componente aggiuntivo OpenZWave Supervisor" + }, + "description": "Vuoi usare il componente aggiuntivo OpenZWave Supervisor?", + "title": "Seleziona il metodo di connessione" + }, + "start_addon": { + "data": { + "network_key": "Chiave di rete", + "usb_path": "Percorso del dispositivo USB" + }, + "title": "Accedi alla configurazione dell'add-on OpenZWave" } } } diff --git a/homeassistant/components/ozw/translations/ko.json b/homeassistant/components/ozw/translations/ko.json index 2412e162c3c..98b965d5dd2 100644 --- a/homeassistant/components/ozw/translations/ko.json +++ b/homeassistant/components/ozw/translations/ko.json @@ -1,13 +1,7 @@ { "config": { "abort": { - "mqtt_required": "MQTT \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\uac00 \uc124\uc815\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4", - "one_instance_allowed": "\uc774 \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\ub294 \ud558\ub098\uc758 Z-Wave \uc778\uc2a4\ud134\uc2a4\ub9cc \uc9c0\uc6d0\ud569\ub2c8\ub2e4" - }, - "step": { - "user": { - "title": "\uc124\uc815 \ub0b4\uc6a9 \ud655\uc778\ud558\uae30" - } + "mqtt_required": "MQTT \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\uac00 \uc124\uc815\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4" } } } \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/lb.json b/homeassistant/components/ozw/translations/lb.json index 9b2a5e577c2..f97f026d38b 100644 --- a/homeassistant/components/ozw/translations/lb.json +++ b/homeassistant/components/ozw/translations/lb.json @@ -2,13 +2,7 @@ "config": { "abort": { "mqtt_required": "MQTT Integratioun ass net ageriicht", - "one_instance_allowed": "D'Integratioun \u00ebnnerst\u00ebtzt n\u00ebmmen 1 Z-Wave Instanz", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." - }, - "step": { - "user": { - "title": "Installatioun konfirm\u00e9ieren" - } } } } \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/nl.json b/homeassistant/components/ozw/translations/nl.json index 19119b9d9e2..4497654e7f3 100644 --- a/homeassistant/components/ozw/translations/nl.json +++ b/homeassistant/components/ozw/translations/nl.json @@ -2,13 +2,7 @@ "config": { "abort": { "mqtt_required": "De [%%] integratie is niet ingesteld", - "one_instance_allowed": "De integratie ondersteunt, maar \u00e9\u00e9n Z-Wave-exemplaar", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." - }, - "step": { - "user": { - "title": "Bevestig de instelling" - } } } } \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/no.json b/homeassistant/components/ozw/translations/no.json index c046b4b4ed2..04c7cf2d50c 100644 --- a/homeassistant/components/ozw/translations/no.json +++ b/homeassistant/components/ozw/translations/no.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "Kunne ikke hente OpenZWave-tilleggsinfo", + "addon_install_failed": "Kunne ikke installere OpenZWave-tillegget", + "addon_set_config_failed": "Kunne ikke angi OpenZWave-konfigurasjon", "mqtt_required": "MQTT-integrasjonen er ikke satt opp", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, + "error": { + "addon_start_failed": "Kunne ikke starte OpenZWave-tillegget. Sjekk konfigurasjonen." + }, "step": { - "user": { - "title": "Bekreft oppsett" + "on_supervisor": { + "data": { + "use_addon": "Bruk OpenZWave Supervisor-tillegget" + }, + "description": "\u00d8nsker du \u00e5 bruke OpenZWave Supervisor-tillegget?", + "title": "Velg tilkoblingsmetode" + }, + "start_addon": { + "data": { + "network_key": "Nettverksn\u00f8kkel", + "usb_path": "USB enhetsbane" + }, + "title": "Angi OpenZWave-tilleggskonfigurasjonen" } } } diff --git a/homeassistant/components/ozw/translations/pl.json b/homeassistant/components/ozw/translations/pl.json index 21cdbbc0faf..f63c4dd10b6 100644 --- a/homeassistant/components/ozw/translations/pl.json +++ b/homeassistant/components/ozw/translations/pl.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "Nie uda\u0142o si\u0119 pobra\u0107 informacji o dodatku OpenZWave", + "addon_install_failed": "Nie uda\u0142o si\u0119 zainstalowa\u0107 dodatku OpenZWave", + "addon_set_config_failed": "Nie uda\u0142o si\u0119 ustawi\u0107 konfiguracji OpenZWave", "mqtt_required": "Integracja MQTT nie jest skonfigurowana", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, + "error": { + "addon_start_failed": "Nie uda\u0142o si\u0119 uruchomi\u0107 dodatku OpenZWave. Sprawd\u017a konfiguracj\u0119." + }, "step": { - "user": { - "title": "Potwierd\u017a konfiguracj\u0119" + "on_supervisor": { + "data": { + "use_addon": "U\u017cyj dodatku OpenZWave Supervisor" + }, + "description": "Czy chcesz u\u017cy\u0107 dodatku OpenZWave Supervisor?", + "title": "Wybierz metod\u0119 po\u0142\u0105czenia" + }, + "start_addon": { + "data": { + "network_key": "Klucz sieci", + "usb_path": "\u015acie\u017cka urz\u0105dzenia USB" + }, + "title": "Wprowad\u017a konfiguracj\u0119 dodatku OpenZWave" } } } diff --git a/homeassistant/components/ozw/translations/pt-BR.json b/homeassistant/components/ozw/translations/pt-BR.json deleted file mode 100644 index f08cdc09053..00000000000 --- a/homeassistant/components/ozw/translations/pt-BR.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "config": { - "step": { - "user": { - "title": "Confirme a configura\u00e7\u00e3o" - } - } - } -} \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/ru.json b/homeassistant/components/ozw/translations/ru.json index 71f21f9eb17..b7a582faa08 100644 --- a/homeassistant/components/ozw/translations/ru.json +++ b/homeassistant/components/ozw/translations/ru.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 OpenZWave.", + "addon_install_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c OpenZWave.", + "addon_set_config_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e OpenZWave.", "mqtt_required": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f MQTT \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430.", - "one_instance_allowed": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 Z-Wave.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, + "error": { + "addon_start_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c OpenZWave. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + }, "step": { - "user": { - "title": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438" + "on_supervisor": { + "data": { + "use_addon": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 Supervisor OpenZWave" + }, + "description": "\u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 Supervisor OpenZWave?", + "title": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f" + }, + "start_addon": { + "data": { + "network_key": "\u041a\u043b\u044e\u0447 \u0441\u0435\u0442\u0438", + "usb_path": "\u041f\u0443\u0442\u044c \u043a USB-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443" + }, + "title": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f OpenZWave" } } } diff --git a/homeassistant/components/ozw/translations/sl.json b/homeassistant/components/ozw/translations/sl.json index 43c78f930f2..03b6d975c2d 100644 --- a/homeassistant/components/ozw/translations/sl.json +++ b/homeassistant/components/ozw/translations/sl.json @@ -1,13 +1,7 @@ { "config": { "abort": { - "mqtt_required": "Integracija MQTT ni nastavljena", - "one_instance_allowed": "Integracija podpira samo en primerek Z-Wave" - }, - "step": { - "user": { - "title": "Potrdite nastavitev" - } + "mqtt_required": "Integracija MQTT ni nastavljena" } } } \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/sv.json b/homeassistant/components/ozw/translations/sv.json deleted file mode 100644 index 68b50437725..00000000000 --- a/homeassistant/components/ozw/translations/sv.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "config": { - "step": { - "user": { - "title": "Bekr\u00e4fta inst\u00e4llningen" - } - } - } -} \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/zh-Hans.json b/homeassistant/components/ozw/translations/zh-Hans.json index a3b0a71d63c..cf0c8771863 100644 --- a/homeassistant/components/ozw/translations/zh-Hans.json +++ b/homeassistant/components/ozw/translations/zh-Hans.json @@ -1,13 +1,7 @@ { "config": { "abort": { - "mqtt_required": "\u672a\u8bbe\u7f6e MQTT \u96c6\u6210", - "one_instance_allowed": "\u7ec4\u4ef6\u53ea\u652f\u6301\u4e00\u4e2a Z-Wave \u5b9e\u4f8b" - }, - "step": { - "user": { - "title": "\u786e\u8ba4\u8bbe\u7f6e" - } + "mqtt_required": "\u672a\u8bbe\u7f6e MQTT \u96c6\u6210" } } } \ No newline at end of file diff --git a/homeassistant/components/ozw/translations/zh-Hant.json b/homeassistant/components/ozw/translations/zh-Hant.json index d9967bddae1..13fcadde01f 100644 --- a/homeassistant/components/ozw/translations/zh-Hant.json +++ b/homeassistant/components/ozw/translations/zh-Hant.json @@ -1,13 +1,29 @@ { "config": { "abort": { + "addon_info_failed": "\u53d6\u5f97 OpenZWave add-on \u8cc7\u8a0a\u5931\u6557\u3002", + "addon_install_failed": "OpenZWave add-on \u5b89\u88dd\u5931\u6557\u3002", + "addon_set_config_failed": "OpenZWave add-on \u8a2d\u5b9a\u5931\u6557\u3002", "mqtt_required": "MQTT \u6574\u5408\u5c1a\u672a\u8a2d\u5b9a", - "one_instance_allowed": "\u6574\u5408\u50c5\u652f\u63f4\u4e00\u7d44 Z-Wave \u5be6\u4f8b", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, + "error": { + "addon_start_failed": "OpenZWave add-on \u555f\u52d5\u5931\u6557\uff0c\u8acb\u6aa2\u67e5\u8a2d\u5b9a\u3002" + }, "step": { - "user": { - "title": "\u78ba\u8a8d\u8a2d\u5b9a" + "on_supervisor": { + "data": { + "use_addon": "\u4f7f\u7528 OpenZWave Supervisor add-on" + }, + "description": "\u662f\u5426\u8981\u4f7f\u7528 OpenZWave Supervisor add-on\uff1f", + "title": "\u9078\u64c7\u9023\u7dda\u985e\u578b" + }, + "start_addon": { + "data": { + "network_key": "\u7db2\u8def\u5bc6\u9470", + "usb_path": "USB \u8a2d\u5099\u8def\u5f91" + }, + "title": "\u8acb\u8f38\u5165 OpenZWave \u8a2d\u5b9a\u3002" } } } diff --git a/homeassistant/components/panasonic_viera/strings.json b/homeassistant/components/panasonic_viera/strings.json index 54cfa41421d..13e3d428df9 100644 --- a/homeassistant/components/panasonic_viera/strings.json +++ b/homeassistant/components/panasonic_viera/strings.json @@ -1,5 +1,4 @@ { - "title": "Panasonic Viera", "config": { "step": { "user": { diff --git a/homeassistant/components/panasonic_viera/translations/ca.json b/homeassistant/components/panasonic_viera/translations/ca.json index a367f62233a..37971cb4068 100644 --- a/homeassistant/components/panasonic_viera/translations/ca.json +++ b/homeassistant/components/panasonic_viera/translations/ca.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", "cannot_connect": "Ha fallat la connexi\u00f3", - "not_connected": "La connexi\u00f3 remota amb el teu televisor Panasonic Viera ha fallat. Consulta els registres per a m\u00e9s informaci\u00f3.", "unknown": "Error inesperat" }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "invalid_pin_code": "El Codi PIN introdu\u00eft no \u00e9s v\u00e0lid", - "not_connected": "No s'ha pogut establir una connexi\u00f3 remota amb el televisor Panasonic Viera" + "invalid_pin_code": "El Codi PIN introdu\u00eft no \u00e9s v\u00e0lid" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "Configuraci\u00f3 del televisor" } } - }, - "title": "Televisor Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/cs.json b/homeassistant/components/panasonic_viera/translations/cs.json index 3013c1830ad..5b54dd5c0c5 100644 --- a/homeassistant/components/panasonic_viera/translations/cs.json +++ b/homeassistant/components/panasonic_viera/translations/cs.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "not_connected": "Vzd\u00e1len\u00e9 p\u0159ipojen\u00ed k televizi Panasonic Viera bylo ztraceno. Dal\u0161\u00ed informace najdete v log\u00e1ch.", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "invalid_pin_code": "Zadan\u00fd PIN k\u00f3d je neplatn\u00fd", - "not_connected": "Nelze nav\u00e1zat vzd\u00e1len\u00e9 p\u0159ipojen\u00ed k televizi Panasonic Viera" + "invalid_pin_code": "Zadan\u00fd PIN k\u00f3d je neplatn\u00fd" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "Nastaven\u00ed televize" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/de.json b/homeassistant/components/panasonic_viera/translations/de.json index 082b86b719a..cac04acb87a 100644 --- a/homeassistant/components/panasonic_viera/translations/de.json +++ b/homeassistant/components/panasonic_viera/translations/de.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Dieser Panasonic Viera TV ist bereits konfiguriert.", - "not_connected": "Die Fernverbindung mit Ihrem Panasonic Viera-Fernseher wurde unterbrochen. Weitere Informationen finden Sie in den Logs.", "unknown": "Ein unbekannter Fehler ist aufgetreten. Weitere Informationen finden Sie in den Logs." }, "error": { - "invalid_pin_code": "Der von Ihnen eingegebene PIN-Code war ung\u00fcltig", - "not_connected": "Es konnte keine Remoteverbindung mit Ihrem Panasonic Viera TV hergestellt werden" + "invalid_pin_code": "Der von Ihnen eingegebene PIN-Code war ung\u00fcltig" }, "step": { "pairing": { @@ -26,6 +24,5 @@ "title": "Richten Sie Ihr Fernsehger\u00e4t ein" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/en.json b/homeassistant/components/panasonic_viera/translations/en.json index 76f4139ed17..f4f7438e32e 100644 --- a/homeassistant/components/panasonic_viera/translations/en.json +++ b/homeassistant/components/panasonic_viera/translations/en.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "Device is already configured", "cannot_connect": "Failed to connect", - "not_connected": "The remote connection with your Panasonic Viera TV was lost. Check the logs for more information.", "unknown": "Unexpected error" }, "error": { "cannot_connect": "Failed to connect", - "invalid_pin_code": "The PIN Code you entered was invalid", - "not_connected": "Could not establish a remote connection with your Panasonic Viera TV" + "invalid_pin_code": "The PIN Code you entered was invalid" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "Setup your TV" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/es-419.json b/homeassistant/components/panasonic_viera/translations/es-419.json index d396fc58856..d727293f698 100644 --- a/homeassistant/components/panasonic_viera/translations/es-419.json +++ b/homeassistant/components/panasonic_viera/translations/es-419.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Esta televisi\u00f3n Panasonic Viera ya est\u00e1 configurada.", - "not_connected": "Se perdi\u00f3 la conexi\u00f3n remota con su televisi\u00f3n Panasonic Viera. Consulte los registros para obtener m\u00e1s informaci\u00f3n.", "unknown": "Un error desconocido ocurri\u00f3. Consulte los registros para obtener m\u00e1s informaci\u00f3n." }, "error": { - "invalid_pin_code": "El c\u00f3digo PIN que ingres\u00f3 no es v\u00e1lido", - "not_connected": "No se pudo establecer una conexi\u00f3n remota con su televisi\u00f3n Panasonic Viera" + "invalid_pin_code": "El c\u00f3digo PIN que ingres\u00f3 no es v\u00e1lido" }, "step": { "pairing": { @@ -26,6 +24,5 @@ "title": "Configurar su televisi\u00f3n" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/es.json b/homeassistant/components/panasonic_viera/translations/es.json index e806b9ce806..cb8021f36d5 100644 --- a/homeassistant/components/panasonic_viera/translations/es.json +++ b/homeassistant/components/panasonic_viera/translations/es.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado", "cannot_connect": "No se pudo conectar", - "not_connected": "La conexi\u00f3n remota con su televisor Panasonic Viera se perdi\u00f3. Compruebe los registros para obtener m\u00e1s informaci\u00f3n.", "unknown": "Error inesperado" }, "error": { "cannot_connect": "No se pudo conectar", - "invalid_pin_code": "El c\u00f3digo PIN que ha introducido no es v\u00e1lido", - "not_connected": "No se pudo establecer una conexi\u00f3n remota con su televisor Panasonic Viera" + "invalid_pin_code": "El c\u00f3digo PIN que ha introducido no es v\u00e1lido" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "Configura tu televisi\u00f3n" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/et.json b/homeassistant/components/panasonic_viera/translations/et.json index 133f1151198..0f90c89ed2f 100644 --- a/homeassistant/components/panasonic_viera/translations/et.json +++ b/homeassistant/components/panasonic_viera/translations/et.json @@ -6,23 +6,25 @@ "unknown": "Tundmatu viga" }, "error": { - "cannot_connect": "\u00dchendamine nurjus" + "cannot_connect": "\u00dchendamine nurjus", + "invalid_pin_code": "Sisestatud PIN kood oli vale" }, "step": { "pairing": { "data": { "pin": "PIN kood" }, - "description": "Sisesta teleris kuvatud PIN kood" + "description": "Sisesta teleris kuvatud PIN kood", + "title": "Sidumine" }, "user": { "data": { "host": "IP aadress", "name": "Nimi" }, - "description": "Sisesta oma Panasonic Viera TV IP-aadress" + "description": "Sisesta oma Panasonic Viera TV IP-aadress", + "title": "Teleri seadistamine" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/fi.json b/homeassistant/components/panasonic_viera/translations/fi.json index 22e861af227..9d0059fbb14 100644 --- a/homeassistant/components/panasonic_viera/translations/fi.json +++ b/homeassistant/components/panasonic_viera/translations/fi.json @@ -23,6 +23,5 @@ "title": "Television m\u00e4\u00e4ritt\u00e4minen" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/fr.json b/homeassistant/components/panasonic_viera/translations/fr.json index 9f8c9b672e5..18add07074b 100644 --- a/homeassistant/components/panasonic_viera/translations/fr.json +++ b/homeassistant/components/panasonic_viera/translations/fr.json @@ -2,12 +2,12 @@ "config": { "abort": { "already_configured": "Ce t\u00e9l\u00e9viseur Panasonic Viera est d\u00e9j\u00e0 configur\u00e9.", - "not_connected": "La connexion \u00e0 distance avec votre t\u00e9l\u00e9viseur Panasonic Viera a \u00e9t\u00e9 perdue. Consultez les journaux pour plus d'informations.", + "cannot_connect": "\u00c9chec de connexion", "unknown": "Une erreur inconnue est survenue. Veuillez consulter les journaux pour obtenir plus de d\u00e9tails." }, "error": { - "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" + "cannot_connect": "\u00c9chec de connexion", + "invalid_pin_code": "Le code PIN que vous avez entr\u00e9 n'est pas valide" }, "step": { "pairing": { @@ -26,6 +26,5 @@ "title": "Configurer votre t\u00e9l\u00e9viseur" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/it.json b/homeassistant/components/panasonic_viera/translations/it.json index 5f1e5508b60..d5fa6b49fe2 100644 --- a/homeassistant/components/panasonic_viera/translations/it.json +++ b/homeassistant/components/panasonic_viera/translations/it.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "cannot_connect": "Impossibile connettersi", - "not_connected": "La connessione remota con la TV Panasonic Viera \u00e8 andata persa. Controllare i registri per ulteriori informazioni.", "unknown": "Errore imprevisto" }, "error": { "cannot_connect": "Impossibile connettersi", - "invalid_pin_code": "Il Codice PIN inserito non \u00e8 valido", - "not_connected": "Impossibile stabilire una connessione remota con la TV Panasonic Viera" + "invalid_pin_code": "Il Codice PIN inserito non \u00e8 valido" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "Configura la tua TV" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/ko.json b/homeassistant/components/panasonic_viera/translations/ko.json index 3e9c948c1c5..fc2fd7827ab 100644 --- a/homeassistant/components/panasonic_viera/translations/ko.json +++ b/homeassistant/components/panasonic_viera/translations/ko.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "\uc774 Panasonic Viera TV \ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "not_connected": "Panasonic Viera TV \uc640\uc758 \uc6d0\uaca9 \uc5f0\uacb0\uc774 \ub04a\uc5b4\uc84c\uc2b5\ub2c8\ub2e4. \uc790\uc138\ud55c \uc815\ubcf4\ub294 \ub85c\uadf8\ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694.", "unknown": "\uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uc785\ub2c8\ub2e4. \uc790\uc138\ud55c \uc815\ubcf4\ub294 \ub85c\uadf8\ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694" }, "error": { - "invalid_pin_code": "\uc785\ub825\ud55c PIN \ucf54\ub4dc\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "not_connected": "Panasonic Viera TV \uc5d0 \uc6d0\uaca9\uc73c\ub85c \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4" + "invalid_pin_code": "\uc785\ub825\ud55c PIN \ucf54\ub4dc\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "step": { "pairing": { @@ -26,6 +24,5 @@ "title": "TV \uc124\uc815\ud558\uae30" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/lb.json b/homeassistant/components/panasonic_viera/translations/lb.json index 256c47b6986..a92bbc5175c 100644 --- a/homeassistant/components/panasonic_viera/translations/lb.json +++ b/homeassistant/components/panasonic_viera/translations/lb.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "Apparat ass scho konfigur\u00e9iert", "cannot_connect": "Feeler beim verbannen", - "not_connected": "Verbindung mam Panasonic Viera TV as \u00ebnnerbrach. Kuck Log fir w\u00e9ider Informatiounen.", "unknown": "Onerwaarte Feeler." }, "error": { "cannot_connect": "Feeler beim verbannen", - "invalid_pin_code": "PIN Code ass ong\u00eblteg", - "not_connected": "Konnt keng Verbindung mam Panasonic Viera TV ariichten" + "invalid_pin_code": "PIN Code ass ong\u00eblteg" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "Fernseh ariichten" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/nl.json b/homeassistant/components/panasonic_viera/translations/nl.json index 792ecc75cd6..96757370bed 100644 --- a/homeassistant/components/panasonic_viera/translations/nl.json +++ b/homeassistant/components/panasonic_viera/translations/nl.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "Deze Panasonic Viera TV is al geconfigureerd.", "cannot_connect": "Kan geen verbinding maken", - "not_connected": "De externe verbinding met uw Panasonic Viera-tv was verbroken. Controleer de logs voor meer informatie.", "unknown": "Er is een onbekende fout opgetreden. Controleer de logs voor meer informatie." }, "error": { "cannot_connect": "Kan geen verbinding maken", - "invalid_pin_code": "De ingevoerde pincode is ongeldig", - "not_connected": "Kon geen externe verbinding met uw Panasonic Viera TV tot stand brengen" + "invalid_pin_code": "De ingevoerde pincode is ongeldig" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "Uw tv instellen" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/no.json b/homeassistant/components/panasonic_viera/translations/no.json index 365787e755c..7efa1e31765 100644 --- a/homeassistant/components/panasonic_viera/translations/no.json +++ b/homeassistant/components/panasonic_viera/translations/no.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "Enheten er allerede konfigurert", "cannot_connect": "Tilkobling mislyktes", - "not_connected": "Fjerntilkoblingen med din Panasonic Viera TV gikk tapt. Sjekk loggene for mer informasjon.", "unknown": "Uventet feil" }, "error": { "cannot_connect": "Tilkobling mislyktes", - "invalid_pin_code": "PIN-kode du skrev inn var ugyldig", - "not_connected": "Kunne ikke opprette en ekstern tilkobling med Panasonic Viera TV" + "invalid_pin_code": "PIN-kode du skrev inn var ugyldig" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "Sett opp TV-en din" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/pl.json b/homeassistant/components/panasonic_viera/translations/pl.json index 7d507ac6cda..a5ae663cc52 100644 --- a/homeassistant/components/panasonic_viera/translations/pl.json +++ b/homeassistant/components/panasonic_viera/translations/pl.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "not_connected": "Zdalne po\u0142\u0105czenie z telewizorem Panasonic Viera zosta\u0142o utracone. Sprawd\u017a logi, aby uzyska\u0107 wi\u0119cej informacji.", "unknown": "Nieoczekiwany b\u0142\u0105d" }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "invalid_pin_code": "Podany kod PIN jest nieprawid\u0142owy", - "not_connected": "Nie uda\u0142o si\u0119 nawi\u0105za\u0107 zdalnego po\u0142\u0105czenia z telewizorem Panasonic Viera" + "invalid_pin_code": "Podany kod PIN jest nieprawid\u0142owy" }, "step": { "pairing": { @@ -25,9 +23,8 @@ "name": "Nazwa" }, "description": "Wprowad\u017a adres IP telewizora Panasonic Viera", - "title": "Skonfiguruj telewizor" + "title": "Konfiguracja telewizora" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/pt-BR.json b/homeassistant/components/panasonic_viera/translations/pt-BR.json index 6e85a695b08..ae60c2dcdba 100644 --- a/homeassistant/components/panasonic_viera/translations/pt-BR.json +++ b/homeassistant/components/panasonic_viera/translations/pt-BR.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Esta TV Panasonic Viera j\u00e1 est\u00e1 configurada.", - "not_connected": "A conex\u00e3o remota com a sua TV Panasonic Viera foi perdida. Verifique os logs para obter mais informa\u00e7\u00f5es." + "already_configured": "Esta TV Panasonic Viera j\u00e1 est\u00e1 configurada." }, "step": { "user": { @@ -10,6 +9,5 @@ "title": "Configure sua TV" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/pt.json b/homeassistant/components/panasonic_viera/translations/pt.json index e9d63f1114f..1e4f4cadc23 100644 --- a/homeassistant/components/panasonic_viera/translations/pt.json +++ b/homeassistant/components/panasonic_viera/translations/pt.json @@ -15,6 +15,5 @@ "title": "Configure a sua TV" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/ru.json b/homeassistant/components/panasonic_viera/translations/ru.json index af3381cc881..e4bbd87bb3f 100644 --- a/homeassistant/components/panasonic_viera/translations/ru.json +++ b/homeassistant/components/panasonic_viera/translations/ru.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "not_connected": "\u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440\u043e\u043c Panasonic Viera \u0431\u044b\u043b\u043e \u043f\u043e\u0442\u0435\u0440\u044f\u043d\u043e. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043b\u043e\u0433\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "invalid_pin_code": "\u0412\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 PIN-\u043a\u043e\u0434 \u043d\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d.", - "not_connected": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440\u043e\u043c." + "invalid_pin_code": "\u0412\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 PIN-\u043a\u043e\u0434 \u043d\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d." }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443" } } - }, - "title": "Panasonic Viera TV" + } } \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/sl.json b/homeassistant/components/panasonic_viera/translations/sl.json index f81d28d6dfc..2049e7de245 100644 --- a/homeassistant/components/panasonic_viera/translations/sl.json +++ b/homeassistant/components/panasonic_viera/translations/sl.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Ta televizor Panasonic Viera je \u017ee konfiguriran.", - "not_connected": "Oddaljena povezava s televizorjem Panasonic Viera je bila prekinjena. Za ve\u010d informacij preverite dnevnike.", "unknown": "Pri\u0161lo je do neznane napake. Za ve\u010d informacij preverite dnevnike." }, "error": { - "invalid_pin_code": "Koda PIN, ki ste jo vnesli, je neveljavna", - "not_connected": "Oddaljene povezave s TV Panasonic Viera ni bilo mogo\u010de vzpostaviti" + "invalid_pin_code": "Koda PIN, ki ste jo vnesli, je neveljavna" }, "step": { "pairing": { @@ -26,6 +24,5 @@ "title": "Nastavite televizor" } } - }, - "title": "Panasonic Viera" + } } \ 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 00000000000..254f6df9327 --- /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/panasonic_viera/translations/zh-Hant.json b/homeassistant/components/panasonic_viera/translations/zh-Hant.json index 7052ba44682..5ac554d2694 100644 --- a/homeassistant/components/panasonic_viera/translations/zh-Hant.json +++ b/homeassistant/components/panasonic_viera/translations/zh-Hant.json @@ -3,13 +3,11 @@ "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "not_connected": "\u8207 Panasonic Viera \u96fb\u8996\u9060\u7aef\u9023\u7dda\u65b7\u7dda\uff0c\u8acb\u53c3\u95b1\u65e5\u8a8c\u4ee5\u7372\u5f97\u66f4\u8a73\u7d30\u8cc7\u8a0a\u3002", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "invalid_pin_code": "\u6240\u8f38\u5165\u7684 PIN \u78bc\u7121\u6548", - "not_connected": "\u7121\u6cd5\u8207 Panasonic Viera \u96fb\u8996\u5efa\u7acb\u9060\u7aef\u9023\u7dda" + "invalid_pin_code": "\u6240\u8f38\u5165\u7684 PIN \u78bc\u7121\u6548" }, "step": { "pairing": { @@ -28,6 +26,5 @@ "title": "\u8a2d\u5b9a\u96fb\u8996" } } - }, - "title": "Panasonic Viera" + } } \ No newline at end of file diff --git a/homeassistant/components/pi4ioe5v9xxxx/manifest.json b/homeassistant/components/pi4ioe5v9xxxx/manifest.json index 749c5d095a0..f399c52859d 100644 --- a/homeassistant/components/pi4ioe5v9xxxx/manifest.json +++ b/homeassistant/components/pi4ioe5v9xxxx/manifest.json @@ -3,6 +3,5 @@ "name": "pi4ioe5v9xxxx IO Expander", "documentation": "https://www.home-assistant.io/integrations/pi4ioe5v9xxxx", "requirements": ["pi4ioe5v9xxxx==0.0.2"], - "dependencies": [], "codeowners": ["@antonverburg"] } diff --git a/homeassistant/components/pi_hole/strings.json b/homeassistant/components/pi_hole/strings.json index 3bb5289777d..75af03dc3a5 100644 --- a/homeassistant/components/pi_hole/strings.json +++ b/homeassistant/components/pi_hole/strings.json @@ -6,7 +6,7 @@ "host": "[%key:common::config_flow::data::host%]", "port": "[%key:common::config_flow::data::port%]", "name": "[%key:common::config_flow::data::name%]", - "location": "Location", + "location": "[%key:common::config_flow::data::location%]", "api_key": "[%key:common::config_flow::data::api_key%]", "ssl": "[%key:common::config_flow::data::ssl%]", "verify_ssl": "[%key:common::config_flow::data::verify_ssl%]" diff --git a/homeassistant/components/pi_hole/translations/de.json b/homeassistant/components/pi_hole/translations/de.json index f8149d83b19..f74c5acb635 100644 --- a/homeassistant/components/pi_hole/translations/de.json +++ b/homeassistant/components/pi_hole/translations/de.json @@ -11,6 +11,7 @@ "data": { "api_key": "API-Schl\u00fcssel (optional)", "host": "Host", + "location": "Org", "name": "Name", "port": "Port", "ssl": "SSL verwenden", diff --git a/homeassistant/components/pi_hole/translations/et.json b/homeassistant/components/pi_hole/translations/et.json index a53eca7e3ed..c68d52c0c10 100644 --- a/homeassistant/components/pi_hole/translations/et.json +++ b/homeassistant/components/pi_hole/translations/et.json @@ -11,6 +11,7 @@ "data": { "api_key": "API v\u00f5ti", "host": "", + "location": "Asukoht", "name": "Nimi", "port": "", "ssl": "Kasuatb SSL serti", diff --git a/homeassistant/components/pi_hole/translations/lb.json b/homeassistant/components/pi_hole/translations/lb.json index 39dcf3e2a6f..cd3b65a2098 100644 --- a/homeassistant/components/pi_hole/translations/lb.json +++ b/homeassistant/components/pi_hole/translations/lb.json @@ -14,7 +14,7 @@ "location": "Standuert", "name": "Numm", "port": "Port", - "ssl": "SSL benotzen", + "ssl": "Benotzt ee SSL Zertifikat", "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" } } diff --git a/homeassistant/components/pi_hole/translations/nl.json b/homeassistant/components/pi_hole/translations/nl.json index 6aaf75ada4a..24da024acae 100644 --- a/homeassistant/components/pi_hole/translations/nl.json +++ b/homeassistant/components/pi_hole/translations/nl.json @@ -9,9 +9,13 @@ "step": { "user": { "data": { + "api_key": "API-sleutel", + "host": "Host", "location": "Locatie", "name": "Naam", - "port": "Poort" + "port": "Poort", + "ssl": "Maakt gebruik van een SSL-certificaat", + "verify_ssl": "SSL-certificaat verifi\u00ebren" } } } diff --git a/homeassistant/components/pioneer/media_player.py b/homeassistant/components/pioneer/media_player.py index a04b79e3188..e573bf0929c 100644 --- a/homeassistant/components/pioneer/media_player.py +++ b/homeassistant/components/pioneer/media_player.py @@ -203,7 +203,7 @@ class PioneerDevice(MediaPlayerEntity): @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/plaato/strings.json b/homeassistant/components/plaato/strings.json index 568cd3ce38e..087cee13683 100644 --- a/homeassistant/components/plaato/strings.json +++ b/homeassistant/components/plaato/strings.json @@ -8,7 +8,7 @@ }, "abort": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Plaato Airlock." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup the webhook feature in Plaato Airlock.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/plaato/translations/bg.json b/homeassistant/components/plaato/translations/bg.json index d8339e1100a..dc86bb69256 100644 --- a/homeassistant/components/plaato/translations/bg.json +++ b/homeassistant/components/plaato/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 Plaato Airlock.", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u0441\u044a\u0431\u0438\u0442\u0438\u044f \u0434\u043e Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0442\u0430 webhook \u0432 Plaato Airlock. \n\n \u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: \n\n - URL: ` {webhook_url} ` \n - Method: POST \n\n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438." }, diff --git a/homeassistant/components/plaato/translations/ca.json b/homeassistant/components/plaato/translations/ca.json index 91a781b0748..1dbe125d50d 100644 --- a/homeassistant/components/plaato/translations/ca.json +++ b/homeassistant/components/plaato/translations/ca.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de Plaato Airlock.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar esdeveniments a Home Assistant, haur\u00e0s de configurar l'opci\u00f3 webhook de Plaato Airlock.\n\nCompleta la seg\u00fcent informaci\u00f3:\n\n- URL: `{webhook_url}` \n- M\u00e8tode: POST \n\nConsulta la [documentaci\u00f3]({docs_url}) per a m\u00e9s detalls." diff --git a/homeassistant/components/plaato/translations/cs.json b/homeassistant/components/plaato/translations/cs.json index c93dcb60b8a..582a3e3a180 100644 --- a/homeassistant/components/plaato/translations/cs.json +++ b/homeassistant/components/plaato/translations/cs.json @@ -1,13 +1,13 @@ { "config": { "abort": { - "not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy z Plaato Airlock.", - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "step": { "user": { - "description": "Chcete za\u010d\u00edt nastavovat?" + "description": "Chcete za\u010d\u00edt nastavovat?", + "title": "Nastaven\u00ed Plaato Webhook" } } } diff --git a/homeassistant/components/plaato/translations/da.json b/homeassistant/components/plaato/translations/da.json index 88b047a2a45..720b6bb4d4a 100644 --- a/homeassistant/components/plaato/translations/da.json +++ b/homeassistant/components/plaato/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage meddelelser fra Plaato Airlock.", - "one_instance_allowed": "Kun en enkelt instans er n\u00f8dvendig." - }, "create_entry": { "default": "For at sende h\u00e6ndelser til Home Assistant skal du konfigurere webhook-funktionen i Plaato Airlock.\n\n Udfyld f\u00f8lgende oplysninger: \n\n - Webadresse: `{webhook_url}`\n - Metode: POST\n \nSe [dokumentationen]({docs_url}) for yderligere oplysninger." }, diff --git a/homeassistant/components/plaato/translations/de.json b/homeassistant/components/plaato/translations/de.json index ec4c3b87d9c..f97fe4875f7 100644 --- a/homeassistant/components/plaato/translations/de.json +++ b/homeassistant/components/plaato/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Deine Home-Assistant-Instanz muss aus dem Internet erreichbar sein, um Nachrichten von Plaato Airlock zu erhalten.", - "one_instance_allowed": "Nur eine einzige Instanz ist notwendig." - }, "create_entry": { "default": "Um Ereignisse an Home Assistant zu senden, muss das Webhook Feature in Plaato Airlock konfiguriert werden.\n\n F\u00fcge die folgenden Informationen ein: \n\n - URL: ` {webhook_url} ` \n - Methode: POST \n \n Weitere Informationen finden sich in der [Dokumentation]({docs_url})." }, diff --git a/homeassistant/components/plaato/translations/en.json b/homeassistant/components/plaato/translations/en.json index c083402859b..6f25c15583c 100644 --- a/homeassistant/components/plaato/translations/en.json +++ b/homeassistant/components/plaato/translations/en.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Plaato Airlock.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup the webhook feature in Plaato Airlock.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/plaato/translations/es-419.json b/homeassistant/components/plaato/translations/es-419.json index 96dae84b853..bec5228b88a 100644 --- a/homeassistant/components/plaato/translations/es-419.json +++ b/homeassistant/components/plaato/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "La instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes de Plaato Airlock.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar eventos a Home Assistant, deber\u00e1 configurar la funci\u00f3n de webhook en Plaato Airlock. \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: `{webhook_url}` \n - M\u00e9todo: POST \n\n Consulte [la documentaci\u00f3n]({docs_url}) para obtener m\u00e1s detalles." }, diff --git a/homeassistant/components/plaato/translations/es.json b/homeassistant/components/plaato/translations/es.json index f7d0716b766..0f030e56b4e 100644 --- a/homeassistant/components/plaato/translations/es.json +++ b/homeassistant/components/plaato/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Tu instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Plaato Airlock.", - "one_instance_allowed": "S\u00f3lo se necesita una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar eventos a Home Assistant, necesitar\u00e1s configurar la funci\u00f3n de webhook en Plaato Airlock.\n\nCompleta la siguiente informaci\u00f3n:\n\n- URL: `{webhook_url}`\n- M\u00e9todo: POST\n\nEcha un vistazo a [la documentaci\u00f3n]({docs_url}) para m\u00e1s detalles." diff --git a/homeassistant/components/plaato/translations/et.json b/homeassistant/components/plaato/translations/et.json index 49e67883440..75c7a2182ef 100644 --- a/homeassistant/components/plaato/translations/et.json +++ b/homeassistant/components/plaato/translations/et.json @@ -1,12 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Lubatud on ainult \u00fcks sidumine.", - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." + }, + "create_entry": { + "default": "S\u00fcndmuste saatmiseks Home Assistantile pead seadistama Plaatoo Airlock'i veebihaagi. \n\n Sisesta j\u00e4rgmine teave: \n\n - URL: \" {webhook_url} \" \n - Meetod: POST \n \n Lisateavet leiad [documentation] ( {docs_url} )." }, "step": { "user": { - "description": "Kas alustan seadistamist?" + "description": "Kas alustan seadistamist?", + "title": "Plaato Webhooki seadistamine" } } } diff --git a/homeassistant/components/plaato/translations/fr.json b/homeassistant/components/plaato/translations/fr.json index cd8d46fa0c4..bc442a04c60 100644 --- a/homeassistant/components/plaato/translations/fr.json +++ b/homeassistant/components/plaato/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance de Home Assistant doit \u00eatre accessible depuis Internet pour recevoir les messages de Plaato Airlock.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez configurer la fonction Webhook dans Plaato Airlock. \n\n Remplissez les informations suivantes: \n\n - URL: ` {webhook_url} ` \n - M\u00e9thode: POST \n\n Voir [la documentation] ( {docs_url} ) pour plus de d\u00e9tails." diff --git a/homeassistant/components/plaato/translations/hr.json b/homeassistant/components/plaato/translations/hr.json index b1ab00551e4..0ad8469354c 100644 --- a/homeassistant/components/plaato/translations/hr.json +++ b/homeassistant/components/plaato/translations/hr.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Va\u0161 Home Assistant mora biti dostupan s interneta za primanje poruka od Plaato Airlocka.", - "one_instance_allowed": "Potrebna je samo jedna instanca." - }, "create_entry": { "default": "Za slanje doga\u0111aja kod ku\u0107nog pomo\u0107nika, morat \u0107ete postaviti zna\u010dajku webhook u Plaato Airlock.\n\nIspunite sljede\u0107e informacije:\n\n-URL: ' {webhook_url} '\n-Metoda: POST\n\nZa dodatne detalje pogledajte [dokumentaciju] ({docs_url})." }, diff --git a/homeassistant/components/plaato/translations/it.json b/homeassistant/components/plaato/translations/it.json index ab0b3179cb5..ad289fa758f 100644 --- a/homeassistant/components/plaato/translations/it.json +++ b/homeassistant/components/plaato/translations/it.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi da Plaato Airlook.", - "one_instance_allowed": "\u00c8 necessaria solo una singola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare eventi a Home Assistant, dovrai impostare la funzione webhook in Plaato Airlock. \n\n Inserisci le seguenti informazioni: \n\n - URL: `{webhook_url}` \n - Metodo: POST \n\n Vedi [la documentazione]({docs_url}) per ulteriori dettagli." diff --git a/homeassistant/components/plaato/translations/ko.json b/homeassistant/components/plaato/translations/ko.json index 10694fa470c..6eeb6a9c061 100644 --- a/homeassistant/components/plaato/translations/ko.json +++ b/homeassistant/components/plaato/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Plaato Airlock \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\ub824\uba74 Plaato Airlock \uc5d0\uc11c \uc6f9 \ud6c5\uc744 \uc124\uc815\ud574\uc57c\ud569\ub2c8\ub2e4.\n\n\ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694:\n\n - URL: `{webhook_url}`\n - Method: POST\n \n \uc790\uc138\ud55c \uc815\ubcf4\ub294 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/plaato/translations/lb.json b/homeassistant/components/plaato/translations/lb.json index 61fa40ebb5a..993a1fb6458 100644 --- a/homeassistant/components/plaato/translations/lb.json +++ b/homeassistant/components/plaato/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir Plaato Airlock Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { @@ -10,7 +8,7 @@ }, "step": { "user": { - "description": "S\u00e9cher fir Plaato Airlock anzeriichten?", + "description": "Soll den Ariichtungs Prozess gestart ginn?", "title": "Plaato Webhook ariichten" } } diff --git a/homeassistant/components/plaato/translations/nl.json b/homeassistant/components/plaato/translations/nl.json index ac7b62e27b2..6545a659427 100644 --- a/homeassistant/components/plaato/translations/nl.json +++ b/homeassistant/components/plaato/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Uw Home Assistant-instantie moet via internet toegankelijk zijn om berichten van de Plateo Airlock te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/plaato/translations/no.json b/homeassistant/components/plaato/translations/no.json index 4d9cb64d357..1e2da1bfb12 100644 --- a/homeassistant/components/plaato/translations/no.json +++ b/homeassistant/components/plaato/translations/no.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta meldinger fra Plaato Airlock.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du sette opp webhook-funksjonen i Plaato Airlock. \n\n Fyll ut f\u00f8lgende informasjon: \n\n - URL: `{webhook_url}` \n - Metode: POST \n\n Se [dokumentasjonen]({docs_url}) for ytterligere detaljer." diff --git a/homeassistant/components/plaato/translations/pl.json b/homeassistant/components/plaato/translations/pl.json index 8f61cb7bc8b..0abb0df4142 100644 --- a/homeassistant/components/plaato/translations/pl.json +++ b/homeassistant/components/plaato/translations/pl.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Twoja instancja Home Assistant musi by\u0107 dost\u0119pna z Internetu, aby otrzymywa\u0107 wiadomo\u015bci z Plaato Airlock", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant, musisz skonfigurowa\u0107 webhook w Plaato Airlock. \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}), by pozna\u0107 szczeg\u00f3\u0142y." diff --git a/homeassistant/components/plaato/translations/pt-BR.json b/homeassistant/components/plaato/translations/pt-BR.json index d03486ceb31..01c296e59ac 100644 --- a/homeassistant/components/plaato/translations/pt-BR.json +++ b/homeassistant/components/plaato/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia Home Assistant precisa estar acess\u00edvel pela internet para receber mensagens da Plaato Airlock.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, voc\u00ea precisar\u00e1 configurar o recurso de webhook na Plaato Airlock.\n\nPreencha as seguintes informa\u00e7\u00f5es:\n\n- URL: `{webhook_url}`\n- M\u00e9todo: POST\n\nVeja [a documenta\u00e7\u00e3o]({docs_url}) para mais detalhes." }, diff --git a/homeassistant/components/plaato/translations/ru.json b/homeassistant/components/plaato/translations/ru.json index af53b848d8c..99e28ac9e04 100644 --- a/homeassistant/components/plaato/translations/ru.json +++ b/homeassistant/components/plaato/translations/ru.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 Plaato Airlock.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Webhook \u0434\u043b\u044f Plaato Airlock.\n\n\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\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 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438." diff --git a/homeassistant/components/plaato/translations/sl.json b/homeassistant/components/plaato/translations/sl.json index 63707d54c6c..af6dd165225 100644 --- a/homeassistant/components/plaato/translations/sl.json +++ b/homeassistant/components/plaato/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Va\u0161 Home Assistant mora biti dostopen prek interneta, da boste lahko prejemali Plaato sporo\u010dila.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "\u010ce \u017eelite dogodke poslati Home Assistant-u, morate v Plaato Airlock-u nastaviti funkcijo webhook. \n\n Izpolnite naslednje podatke: \n\n - URL: ` {webhook_url} ` \n - Metoda: POST \n\n Za podrobnosti glejte [dokumentacija] ( {docs_url} )." }, diff --git a/homeassistant/components/plaato/translations/sv.json b/homeassistant/components/plaato/translations/sv.json index e349d5fba28..25e86261699 100644 --- a/homeassistant/components/plaato/translations/sv.json +++ b/homeassistant/components/plaato/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant instans m\u00e5ste vara \u00e5tkomlig genom internet f\u00f6r att ta emot meddelanden ifr\u00e5n Plaato Airlock.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du konfigurera webhook funktionen i Plaato Airlock.\n\n Fyll i f\u00f6ljande information:\n \n- URL: `{webhook_url}`\n- Method: POST\n\nSe [dokumentation]({docs_url}) f\u00f6r mer information." }, diff --git a/homeassistant/components/plaato/translations/zh-Hans.json b/homeassistant/components/plaato/translations/zh-Hans.json index 8d5c25babfa..d6843dd6abe 100644 --- a/homeassistant/components/plaato/translations/zh-Hans.json +++ b/homeassistant/components/plaato/translations/zh-Hans.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u53ef\u4ece\u4e92\u8054\u7f51\u8bbf\u95ee\u4ee5\u63a5\u6536Plaato Airlock\u6d88\u606f\u3002" - }, "step": { "user": { "description": "\u4f60\u786e\u5b9a\u8981\u8bbe\u7f6ePlaato Airlock\u5417\uff1f", diff --git a/homeassistant/components/plaato/translations/zh-Hant.json b/homeassistant/components/plaato/translations/zh-Hant.json index a93067bd3f4..dbfe2075e2d 100644 --- a/homeassistant/components/plaato/translations/zh-Hant.json +++ b/homeassistant/components/plaato/translations/zh-Hant.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u8a2d\u5099\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 Plaato Airlock \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u65bc Plaato Airlock \u5167\u8a2d\u5b9a webhook \u529f\u80fd\u3002\n\n\u8acb\u586b\u5beb\u4e0b\u5217\u8cc7\u8a0a\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n\n\u8acb\u53c3\u95b1 [\u6587\u4ef6]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u8a73\u7d30\u8cc7\u6599\u3002" diff --git a/homeassistant/components/plant/manifest.json b/homeassistant/components/plant/manifest.json index 7318b222e45..8cb632c5bb7 100644 --- a/homeassistant/components/plant/manifest.json +++ b/homeassistant/components/plant/manifest.json @@ -3,6 +3,6 @@ "name": "Plant Monitor", "documentation": "https://www.home-assistant.io/integrations/plant", "after_dependencies": ["recorder"], - "codeowners": ["@ChristianKuehnel"], + "codeowners": [], "quality_scale": "internal" } diff --git a/homeassistant/components/plex/manifest.json b/homeassistant/components/plex/manifest.json index c459f97a966..5bfbc4932ab 100644 --- a/homeassistant/components/plex/manifest.json +++ b/homeassistant/components/plex/manifest.json @@ -4,9 +4,9 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/plex", "requirements": [ - "plexapi==4.1.1", - "plexauth==0.0.6", - "plexwebsocket==0.0.12" + "plexapi==4.2.0", + "plexauth==0.0.6", + "plexwebsocket==0.0.12" ], "dependencies": ["http"], "after_dependencies": ["sonos"], diff --git a/homeassistant/components/plex/translations/cs.json b/homeassistant/components/plex/translations/cs.json index bef1271888f..de85391a7d9 100644 --- a/homeassistant/components/plex/translations/cs.json +++ b/homeassistant/components/plex/translations/cs.json @@ -37,6 +37,9 @@ "title": "Plex Media Server" }, "user_advanced": { + "data": { + "setup_method": "Metoda nastaven\u00ed" + }, "title": "Plex Media Server" } } diff --git a/homeassistant/components/plex/translations/et.json b/homeassistant/components/plex/translations/et.json index 2f780bc73be..d815a092bca 100644 --- a/homeassistant/components/plex/translations/et.json +++ b/homeassistant/components/plex/translations/et.json @@ -1,13 +1,19 @@ { "config": { "abort": { + "all_configured": "K\u00f5ik lingitud serverid on juba seadistatud", "already_configured": "Plex-i server on juba h\u00e4\u00e4lestatud", "already_in_progress": "Seadistamine on juba k\u00e4imas", "reauth_successful": "Taastuvastamine oli edukas", + "token_request_timeout": "Tuvastusstringi hankimise ajal\u00f5pp", "unknown": "Tundmatu viga" }, "error": { - "host_or_token": "Pead esitama v\u00e4hemalt \u00fche hosti v\u00f5i ligip\u00e4\u00e4suloa" + "faulty_credentials": "API autoriseerimine nurjus.", + "host_or_token": "Pead esitama v\u00e4hemalt \u00fche hosti v\u00f5i ligip\u00e4\u00e4suloa", + "no_servers": "Plex kontol pole seotud servereid", + "not_found": "Plexi serverit ei leitud", + "ssl_error": "Kontrolli SSL sertifikaati" }, "flow_title": "", "step": { @@ -16,8 +22,40 @@ "host": "", "port": "", "ssl": "Kasutab SSL serti", + "token": "Luba (valikuline)", "verify_ssl": "Kontrolli SSL sertifikaati" - } + }, + "title": "Plexi k\u00e4sitsi seadistamine" + }, + "select_server": { + "data": { + "server": "" + }, + "description": "Saadaval on mitu serverit, vali \u00fcks:", + "title": "Vali Plex'i server" + }, + "user": { + "description": "Plexi serveri linkimiseks mine lehele [plex.tv] (https://plex.tv).", + "title": "" + }, + "user_advanced": { + "data": { + "setup_method": "Seadistusmeetod" + }, + "title": "" + } + } + }, + "options": { + "step": { + "plex_mp_settings": { + "data": { + "ignore_new_shared_users": "Eira uusi hallatud / jagatud kasutajaid", + "ignore_plex_web_clients": "Eira Plex Web'i kliente", + "monitored_users": "J\u00e4lgitavad kasutajad", + "use_episode_art": "Kasuta jao kujundust" + }, + "description": "Plex Media Players'i valikud" } } } diff --git a/homeassistant/components/plex/translations/fr.json b/homeassistant/components/plex/translations/fr.json index 685eab31bfd..63a2413316e 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/plex/translations/lb.json b/homeassistant/components/plex/translations/lb.json index eda0cb04b03..916bcbc9042 100644 --- a/homeassistant/components/plex/translations/lb.json +++ b/homeassistant/components/plex/translations/lb.json @@ -3,10 +3,10 @@ "abort": { "all_configured": "All verbonne Server sinn scho konfigur\u00e9iert", "already_configured": "D\u00ebse Plex Server ass scho konfigur\u00e9iert", - "already_in_progress": "Plex g\u00ebtt konfigur\u00e9iert", + "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaang.", "reauth_successful": "Erfollegr\u00e4ich re-authentifiz\u00e9iert", "token_request_timeout": "Z\u00e4it Iwwerschreidung beim kr\u00e9ien vum Jeton", - "unknown": "Onbekannte Feeler opgetrueden" + "unknown": "Onerwaarte Feeler" }, "error": { "faulty_credentials": "Feeler bei der Autorisatioun, iwwerpr\u00e9if de Jeton", @@ -21,7 +21,7 @@ "data": { "host": "Apparat", "port": "Port", - "ssl": "SSL benotzen", + "ssl": "Benotzt ee SSL Zertifikat", "token": "Jeton (Optionell)", "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" }, diff --git a/homeassistant/components/plex/translations/nl.json b/homeassistant/components/plex/translations/nl.json index 218e11ac76d..00c2b30c490 100644 --- a/homeassistant/components/plex/translations/nl.json +++ b/homeassistant/components/plex/translations/nl.json @@ -9,15 +9,22 @@ }, "error": { "faulty_credentials": "Autorisatie mislukt", + "host_or_token": "Moet ten minste \u00e9\u00e9n host of token verstrekken.", "no_servers": "Geen servers gekoppeld aan account", - "not_found": "Plex-server niet gevonden" + "not_found": "Plex-server niet gevonden", + "ssl_error": "SSL-certificaatprobleem" }, "flow_title": "{name} ({host})", "step": { "manual_setup": { "data": { - "port": "Poort" - } + "host": "Host", + "port": "Poort", + "ssl": "Maakt gebruik van een SSL-certificaat", + "token": "Token (optioneel)", + "verify_ssl": "Controleer het SSL-certificaat" + }, + "title": "Handmatige Plex-configuratie" }, "select_server": { "data": { @@ -27,9 +34,13 @@ "title": "Selecteer Plex server" }, "user": { + "description": "Ga verder naar [plex.tv] (https://plex.tv) om een Plex-server te koppelen.", "title": "Plex Media Server" }, "user_advanced": { + "data": { + "setup_method": "Installatiemethode" + }, "title": "Plex Media Server" } } @@ -39,6 +50,8 @@ "plex_mp_settings": { "data": { "ignore_new_shared_users": "Negeer nieuwe beheerde/gedeelde gebruikers", + "ignore_plex_web_clients": "Negeer Plex-webclients", + "monitored_users": "Gecontroleerde gebruikers", "use_episode_art": "Gebruik aflevering kunst" }, "description": "Opties voor Plex-mediaspelers" diff --git a/homeassistant/components/plex/translations/pl.json b/homeassistant/components/plex/translations/pl.json index 10e8ef6dc53..bd3e45da688 100644 --- a/homeassistant/components/plex/translations/pl.json +++ b/homeassistant/components/plex/translations/pl.json @@ -25,7 +25,7 @@ "token": "Token dost\u0119pu (opcjonalnie)", "verify_ssl": "Weryfikacja certyfikatu SSL" }, - "title": "Manualna konfiguracja Plex" + "title": "R\u0119czna konfiguracja Plex" }, "select_server": { "data": { diff --git a/homeassistant/components/plex/translations/zh-Hans.json b/homeassistant/components/plex/translations/zh-Hans.json index 614f83e3cc0..9cc02584789 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/plugwise/binary_sensor.py b/homeassistant/components/plugwise/binary_sensor.py index 67dcc10a289..2ba85326265 100644 --- a/homeassistant/components/plugwise/binary_sensor.py +++ b/homeassistant/components/plugwise/binary_sensor.py @@ -33,24 +33,23 @@ async def async_setup_entry(hass, config_entry, async_add_entities): all_devices = api.get_all_devices() for dev_id, device_properties in all_devices.items(): - if device_properties["class"] != "heater_central": - continue + if device_properties["class"] == "heater_central": + data = api.get_device_data(dev_id) - data = api.get_device_data(dev_id) - for binary_sensor, dummy in BINARY_SENSOR_MAP.items(): - if binary_sensor not in data: - continue + for binary_sensor in BINARY_SENSOR_MAP: + if binary_sensor not in data: + continue - entities.append( - PwBinarySensor( - api, - coordinator, - device_properties["name"], - binary_sensor, - dev_id, - device_properties["class"], + entities.append( + PwBinarySensor( + api, + coordinator, + device_properties["name"], + dev_id, + binary_sensor, + device_properties["class"], + ) ) - ) async_add_entities(entities, True) @@ -58,7 +57,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class PwBinarySensor(SmileSensor, BinarySensorEntity): """Representation of a Plugwise binary_sensor.""" - def __init__(self, api, coordinator, name, binary_sensor, dev_id, model): + def __init__(self, api, coordinator, name, dev_id, binary_sensor, model): """Set up the Plugwise API.""" super().__init__(api, coordinator, name, dev_id, binary_sensor) @@ -74,11 +73,6 @@ class PwBinarySensor(SmileSensor, BinarySensorEntity): """Return true if the binary sensor is on.""" return self._is_on - @property - def icon(self): - """Return the icon to use in the frontend.""" - return self._icon - @callback def _async_process_data(self): """Update the entity.""" @@ -95,16 +89,10 @@ class PwBinarySensor(SmileSensor, BinarySensorEntity): self._is_on = data[self._binary_sensor] - self._state = STATE_OFF + self._state = STATE_ON if self._is_on else STATE_OFF if self._binary_sensor == "dhw_state": - self._icon = FLOW_OFF_ICON + self._icon = FLOW_ON_ICON if self._is_on else FLOW_OFF_ICON if self._binary_sensor == "slave_boiler_state": - self._icon = IDLE_ICON - if self._is_on: - self._state = STATE_ON - if self._binary_sensor == "dhw_state": - self._icon = FLOW_ON_ICON - if self._binary_sensor == "slave_boiler_state": - self._icon = FLAME_ICON + self._icon = FLAME_ICON if self._is_on else IDLE_ICON self.async_write_ha_state() diff --git a/homeassistant/components/plugwise/config_flow.py b/homeassistant/components/plugwise/config_flow.py index 364f58007c6..6fd7cde44bc 100644 --- a/homeassistant/components/plugwise/config_flow.py +++ b/homeassistant/components/plugwise/config_flow.py @@ -5,7 +5,15 @@ from Plugwise_Smile.Smile import Smile import voluptuous as vol from homeassistant import config_entries, core, exceptions -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL +from homeassistant.const import ( + CONF_BASE, + CONF_HOST, + CONF_NAME, + CONF_PASSWORD, + CONF_PORT, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) from homeassistant.core import callback from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.typing import DiscoveryInfoType @@ -28,14 +36,21 @@ def _base_gw_schema(discovery_info): base_gw_schema[vol.Required(CONF_HOST)] = str base_gw_schema[vol.Optional(CONF_PORT, default=DEFAULT_PORT)] = int - base_gw_schema[vol.Required(CONF_PASSWORD)] = str + base_gw_schema.update( + { + vol.Required( + CONF_USERNAME, default="smile", description={"suggested_value": "smile"} + ): str, + vol.Required(CONF_PASSWORD): str, + } + ) return vol.Schema(base_gw_schema) async def validate_gw_input(hass: core.HomeAssistant, data): """ - Validate the user input allows us to connect to the gateray. + Validate whether the user input allows us to connect to the gateray. Data has the keys from _base_gw_schema() with values provided by the user. """ @@ -45,6 +60,7 @@ async def validate_gw_input(hass: core.HomeAssistant, data): host=data[CONF_HOST], password=data[CONF_PASSWORD], port=data[CONF_PORT], + username=data[CONF_USERNAME], timeout=30, websession=websession, ) @@ -89,7 +105,7 @@ class PlugwiseConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): self.context["title_placeholders"] = { CONF_HOST: discovery_info[CONF_HOST], CONF_PORT: discovery_info.get(CONF_PORT, DEFAULT_PORT), - "name": _name, + CONF_NAME: _name, } return await self.async_step_user() @@ -111,12 +127,12 @@ class PlugwiseConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): api = await validate_gw_input(self.hass, user_input) except CannotConnect: - errors["base"] = "cannot_connect" + errors[CONF_BASE] = "cannot_connect" except InvalidAuth: - errors["base"] = "invalid_auth" + errors[CONF_BASE] = "invalid_auth" except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected exception") - errors["base"] = "unknown" + errors[CONF_BASE] = "unknown" if not errors: await self.async_set_unique_id( api.smile_hostname or api.gateway_id, raise_on_progress=False diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 056606307e5..5c0cf2b097a 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -1,53 +1,53 @@ """Constant for Plugwise component.""" DOMAIN = "plugwise" -SENSOR_PLATFORMS = ["sensor"] +SENSOR_PLATFORMS = ["sensor", "switch"] ALL_PLATFORMS = ["binary_sensor", "climate", "sensor", "switch"] # Sensor mapping +SENSOR_MAP_DEVICE_CLASS = 2 +SENSOR_MAP_ICON = 3 SENSOR_MAP_MODEL = 0 SENSOR_MAP_UOM = 1 -SENSOR_MAP_DEVICE_CLASS = 2 # Default directives -DEFAULT_NAME = "Smile" -DEFAULT_USERNAME = "smile" -DEFAULT_TIMEOUT = 10 -DEFAULT_PORT = 80 DEFAULT_MIN_TEMP = 4 DEFAULT_MAX_TEMP = 30 -DEFAULT_SCAN_INTERVAL = {"thermostat": 60, "power": 10} +DEFAULT_NAME = "Smile" +DEFAULT_PORT = 80 +DEFAULT_USERNAME = "smile" +DEFAULT_SCAN_INTERVAL = {"power": 10, "stretch": 60, "thermostat": 60} +DEFAULT_TIMEOUT = 60 # Configuration directives -CONF_MIN_TEMP = "min_temp" -CONF_MAX_TEMP = "max_temp" -CONF_THERMOSTAT = "thermostat" -CONF_POWER = "power" -CONF_HEATER = "heater" -CONF_SOLAR = "solar" +CONF_BASE = "base" CONF_GAS = "gas" +CONF_MAX_TEMP = "max_temp" +CONF_MIN_TEMP = "min_temp" +CONF_POWER = "power" +CONF_THERMOSTAT = "thermostat" ATTR_ILLUMINANCE = "illuminance" -UNIT_LUMEN = "lm" -CURRENT_HVAC_DHW = "hot_water" +UNIT_LUMEN = "lm" DEVICE_STATE = "device_state" -SCHEDULE_ON = "true" SCHEDULE_OFF = "false" +SCHEDULE_ON = "true" COOL_ICON = "mdi:snowflake" FLAME_ICON = "mdi:fire" -IDLE_ICON = "mdi:circle-off-outline" FLOW_OFF_ICON = "mdi:water-pump-off" FLOW_ON_ICON = "mdi:water-pump" +IDLE_ICON = "mdi:circle-off-outline" +SWITCH_ICON = "mdi:electric-switch" -UNDO_UPDATE_LISTENER = "undo_update_listener" COORDINATOR = "coordinator" - +UNDO_UPDATE_LISTENER = "undo_update_listener" ZEROCONF_MAP = { "smile": "P1", "smile_thermo": "Anna", "smile_open_therm": "Adam", + "stretch": "Stretch", } diff --git a/homeassistant/components/plugwise/gateway.py b/homeassistant/components/plugwise/gateway.py index 610fff18e4b..5ba6eda2770 100644 --- a/homeassistant/components/plugwise/gateway.py +++ b/homeassistant/components/plugwise/gateway.py @@ -10,7 +10,13 @@ import async_timeout import voluptuous as vol from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL +from homeassistant.const import ( + CONF_HOST, + CONF_PASSWORD, + CONF_PORT, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import device_registry as dr @@ -26,6 +32,8 @@ from .const import ( COORDINATOR, DEFAULT_PORT, DEFAULT_SCAN_INTERVAL, + DEFAULT_TIMEOUT, + DEFAULT_USERNAME, DOMAIN, SENSOR_PLATFORMS, UNDO_UPDATE_LISTENER, @@ -42,6 +50,7 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: api = Smile( host=entry.data[CONF_HOST], + username=entry.data.get(CONF_USERNAME, DEFAULT_USERNAME), password=entry.data[CONF_PASSWORD], port=entry.data.get(CONF_PORT, DEFAULT_PORT), timeout=30, @@ -56,15 +65,15 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: raise ConfigEntryNotReady except Smile.InvalidAuthentication: - _LOGGER.error("Invalid Smile ID") + _LOGGER.error("Invalid username or Smile ID") return False except Smile.PlugwiseError as err: - _LOGGER.error("Error while communicating to device") + _LOGGER.error("Error while communicating to device %s", api.smile_name) raise ConfigEntryNotReady from err except asyncio.TimeoutError as err: - _LOGGER.error("Timeout while connecting to Smile") + _LOGGER.error("Timeout while connecting to Smile %s", api.smile_name) raise ConfigEntryNotReady from err update_interval = timedelta( @@ -76,7 +85,7 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_update_data(): """Update data via API endpoint.""" try: - async with async_timeout.timeout(10): + async with async_timeout.timeout(DEFAULT_TIMEOUT): await api.full_update_device() return True except Smile.XMLDataMissingError as err: @@ -85,7 +94,7 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: coordinator = DataUpdateCoordinator( hass, _LOGGER, - name="Smile", + name=f"Smile {api.smile_name}", update_method=async_update_data, update_interval=update_interval, ) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 483153c6709..578f1bc7f7e 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -116,26 +116,30 @@ ENERGY_SENSOR_MAP = { DEVICE_CLASS_POWER, ], "electricity_produced_off_peak_point": [ - "Current Consumed Power (off peak)", + "Current Produced Power (off peak)", POWER_WATT, DEVICE_CLASS_POWER, ], "electricity_produced_peak_point": [ - "Current Consumed Power", + "Current Produced Power", POWER_WATT, DEVICE_CLASS_POWER, ], "electricity_produced_off_peak_cumulative": [ - "Cumulative Consumed Power (off peak)", + "Cumulative Produced Power (off peak)", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, ], "electricity_produced_peak_cumulative": [ - "Cumulative Consumed Power", + "Cumulative Produced Power", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, ], - "gas_consumed_interval": ["Current Consumed Gas", VOLUME_CUBIC_METERS, None], + "gas_consumed_interval": [ + "Current Consumed Gas Interval", + VOLUME_CUBIC_METERS, + None, + ], "gas_consumed_cumulative": ["Cumulative Consumed Gas", VOLUME_CUBIC_METERS, None], "net_electricity_point": ["Current net Power", POWER_WATT, DEVICE_CLASS_POWER], "net_electricity_cumulative": [ @@ -242,6 +246,7 @@ class SmileSensor(SmileGateway): self._sensor = sensor self._dev_class = None + self._icon = None self._state = None self._unit_of_measurement = None @@ -261,9 +266,14 @@ class SmileSensor(SmileGateway): """Device class of this entity.""" return self._dev_class + @property + def icon(self): + """Return the icon of this entity.""" + return self._icon + @property def state(self): - """Device class of this entity.""" + """Return the state of this entity.""" return self._state @property @@ -273,7 +283,7 @@ class SmileSensor(SmileGateway): class PwThermostatSensor(SmileSensor, Entity): - """Thermostat and climate sensor entities.""" + """Thermostat (or generic) sensor devices.""" def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): """Set up the Plugwise API.""" @@ -296,10 +306,8 @@ class PwThermostatSensor(SmileSensor, Entity): if data.get(self._sensor) is not None: measurement = data[self._sensor] - if self._sensor == "battery" or self._sensor == "valve_position": - measurement = measurement * 100 if self._unit_of_measurement == PERCENTAGE: - measurement = int(measurement) + measurement = int(measurement * 100) self._state = measurement self._icon = CUSTOM_ICONS.get(self._sensor, self._icon) @@ -307,7 +315,7 @@ class PwThermostatSensor(SmileSensor, Entity): class PwAuxDeviceSensor(SmileSensor, Entity): - """Auxiliary sensor entities for the heating/cooling device.""" + """Auxiliary Device Sensors.""" def __init__(self, api, coordinator, name, dev_id, sensor): """Set up the Plugwise API.""" @@ -315,12 +323,6 @@ class PwAuxDeviceSensor(SmileSensor, Entity): self._cooling_state = False self._heating_state = False - self._icon = None - - @property - def icon(self): - """Return the icon to use in the frontend.""" - return self._icon @callback def _async_process_data(self): @@ -380,7 +382,7 @@ class PwPowerSensor(SmileSensor, Entity): if data.get(self._sensor) is not None: measurement = data[self._sensor] if self._unit_of_measurement == ENERGY_KILO_WATT_HOUR: - measurement = int(measurement / 1000) + measurement = round((measurement / 1000), 1) self._state = measurement self._icon = CUSTOM_ICONS.get(self._sensor, self._icon) diff --git a/homeassistant/components/plugwise/strings.json b/homeassistant/components/plugwise/strings.json index 4e6ea18017b..2ed6721bab3 100644 --- a/homeassistant/components/plugwise/strings.json +++ b/homeassistant/components/plugwise/strings.json @@ -20,11 +20,12 @@ }, "user_gateway": { "title": "Connect to the Smile", - "description": "Please enter:", + "description": "Please enter", "data": { "password": "Smile ID", "host": "[%key:common::config_flow::data::ip%]", - "port": "[%key:common::config_flow::data::port%]" + "port": "[%key:common::config_flow::data::port%]", + "username" : "Smile Username" } } }, diff --git a/homeassistant/components/plugwise/switch.py b/homeassistant/components/plugwise/switch.py index d7b45f4999a..8221bc2cb57 100644 --- a/homeassistant/components/plugwise/switch.py +++ b/homeassistant/components/plugwise/switch.py @@ -7,7 +7,7 @@ from Plugwise_Smile.Smile import Smile from homeassistant.components.switch import SwitchEntity from homeassistant.core import callback -from .const import COORDINATOR, DOMAIN +from .const import COORDINATOR, DOMAIN, SWITCH_ICON from .gateway import SmileGateway _LOGGER = logging.getLogger(__name__) @@ -19,12 +19,27 @@ async def async_setup_entry(hass, config_entry, async_add_entities): coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR] entities = [] + switch_classes = ["plug", "switch_group"] + all_devices = api.get_all_devices() for dev_id, device_properties in all_devices.items(): - if "plug" in device_properties["types"]: - model = "Metered Switch" + members = None + model = None + + if any( + switch_class in device_properties["types"] + for switch_class in switch_classes + ): + if "plug" in device_properties["types"]: + model = "Metered Switch" + if "switch_group" in device_properties["types"]: + members = device_properties["members"] + model = "Switch Group" + entities.append( - PwSwitch(api, coordinator, device_properties["name"], dev_id, model) + PwSwitch( + api, coordinator, device_properties["name"], dev_id, members, model + ) ) async_add_entities(entities, True) @@ -33,13 +48,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class PwSwitch(SmileGateway, SwitchEntity): """Representation of a Plugwise plug.""" - def __init__(self, api, coordinator, name, dev_id, model): + def __init__(self, api, coordinator, name, dev_id, members, model): """Set up the Plugwise API.""" super().__init__(api, coordinator, name, dev_id) + self._members = members self._model = model self._is_on = False + self._icon = SWITCH_ICON self._unique_id = f"{dev_id}-plug" @@ -48,10 +65,18 @@ class PwSwitch(SmileGateway, SwitchEntity): """Return true if device is on.""" return self._is_on + @property + def icon(self): + """Return the icon of this entity.""" + return self._icon + async def async_turn_on(self, **kwargs): """Turn the device on.""" try: - if await self._api.set_relay_state(self._dev_id, "on"): + state_on = await self._api.set_relay_state( + self._dev_id, self._members, "on" + ) + if state_on: self._is_on = True self.async_write_ha_state() except Smile.PlugwiseError: @@ -60,7 +85,10 @@ class PwSwitch(SmileGateway, SwitchEntity): async def async_turn_off(self, **kwargs): """Turn the device off.""" try: - if await self._api.set_relay_state(self._dev_id, "off"): + state_off = await self._api.set_relay_state( + self._dev_id, self._members, "off" + ) + if state_off: self._is_on = False self.async_write_ha_state() except Smile.PlugwiseError: @@ -69,8 +97,6 @@ class PwSwitch(SmileGateway, SwitchEntity): @callback def _async_process_data(self): """Update the data from the Plugs.""" - _LOGGER.debug("Update switch called") - data = self._api.get_device_data(self._dev_id) if not data: diff --git a/homeassistant/components/plugwise/translations/ca.json b/homeassistant/components/plugwise/translations/ca.json index d5fc2b7d398..ee580d2786e 100644 --- a/homeassistant/components/plugwise/translations/ca.json +++ b/homeassistant/components/plugwise/translations/ca.json @@ -12,10 +12,7 @@ "step": { "user": { "data": { - "flow_type": "Tipus de connexi\u00f3", - "host": "Adre\u00e7a IP", - "password": "ID de Smile", - "port": "Port" + "flow_type": "Tipus de connexi\u00f3" }, "description": "Producte:", "title": "Tipus de Plugwise" @@ -24,9 +21,10 @@ "data": { "host": "Adre\u00e7a IP", "password": "ID de Smile", - "port": "Port" + "port": "Port", + "username": "Nom d'usuari de Smile" }, - "description": "Introdueix:", + "description": "Introdueix", "title": "Connexi\u00f3 amb Smile" } } diff --git a/homeassistant/components/plugwise/translations/cs.json b/homeassistant/components/plugwise/translations/cs.json index 03cc31e3cab..c1c193e04a2 100644 --- a/homeassistant/components/plugwise/translations/cs.json +++ b/homeassistant/components/plugwise/translations/cs.json @@ -8,12 +8,11 @@ "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, + "flow_title": "Smile: {name}", "step": { "user": { "data": { - "flow_type": "Typ p\u0159ipojen\u00ed", - "host": "IP adresa", - "port": "Port" + "flow_type": "Typ p\u0159ipojen\u00ed" }, "description": "Produkt:", "title": "Typ Plugwise" @@ -21,9 +20,11 @@ "user_gateway": { "data": { "host": "IP adresa", - "port": "Port" + "password": "Smile ID", + "port": "Port", + "username": "U\u017eivatelsk\u00e9 jm\u00e9no Smile" }, - "description": "Pros\u00edm zadejte:", + "description": "Pros\u00edm zadejte", "title": "P\u0159ipojen\u00ed k Smile" } } diff --git a/homeassistant/components/plugwise/translations/de.json b/homeassistant/components/plugwise/translations/de.json index 43ea3c8e3b5..e2e01eb1df7 100644 --- a/homeassistant/components/plugwise/translations/de.json +++ b/homeassistant/components/plugwise/translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Service ist bereits konfiguriert" + }, "error": { "cannot_connect": "Verbindung fehlgeschlagen, versuchen Sie es erneut", "unknown": "Unerwarteter Fehler" @@ -8,12 +11,9 @@ "step": { "user": { "data": { - "flow_type": "Verbindungstyp", - "host": "Smile IP-Adresse", - "password": "Smile ID" + "flow_type": "Verbindungstyp" }, - "description": "Details", - "title": "Stellen Sie eine Verbindung zu Smile her" + "description": "Details" }, "user_gateway": { "data": { diff --git a/homeassistant/components/plugwise/translations/el.json b/homeassistant/components/plugwise/translations/el.json index 1636ae0bef1..2645c74dce6 100644 --- a/homeassistant/components/plugwise/translations/el.json +++ b/homeassistant/components/plugwise/translations/el.json @@ -1,13 +1,4 @@ { - "config": { - "step": { - "user": { - "data": { - "port": "\u0391\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2 \u03b8\u03cd\u03c1\u03b1\u03c2 \u03c7\u03b1\u03bc\u03cc\u03b3\u03b5\u03bb\u03bf\u03c5" - } - } - } - }, "options": { "step": { "init": { diff --git a/homeassistant/components/plugwise/translations/en.json b/homeassistant/components/plugwise/translations/en.json index 20f84d94aff..7f2f20e1947 100644 --- a/homeassistant/components/plugwise/translations/en.json +++ b/homeassistant/components/plugwise/translations/en.json @@ -12,10 +12,7 @@ "step": { "user": { "data": { - "flow_type": "Connection type", - "host": "IP Address", - "password": "Smile ID", - "port": "Port" + "flow_type": "Connection type" }, "description": "Product:", "title": "Plugwise type" @@ -24,9 +21,10 @@ "data": { "host": "IP Address", "password": "Smile ID", - "port": "Port" + "port": "Port", + "username": "Smile Username" }, - "description": "Please enter:", + "description": "Please enter", "title": "Connect to the Smile" } } diff --git a/homeassistant/components/plugwise/translations/es.json b/homeassistant/components/plugwise/translations/es.json index b436fbbfa09..8f3ce70cb88 100644 --- a/homeassistant/components/plugwise/translations/es.json +++ b/homeassistant/components/plugwise/translations/es.json @@ -12,10 +12,7 @@ "step": { "user": { "data": { - "flow_type": "Tipo de conexi\u00f3n", - "host": "Direcci\u00f3n IP de Smile", - "password": "ID Smile", - "port": "Puerto" + "flow_type": "Tipo de conexi\u00f3n" }, "description": "Detalles", "title": "Conectarse a Smile" @@ -24,7 +21,8 @@ "data": { "host": "Direcci\u00f3n IP", "password": "ID Smile", - "port": "Puerto" + "port": "Puerto", + "username": "Nombre de usuario Smile" }, "description": "Por favor introduce:", "title": "Conectarse a Smile" diff --git a/homeassistant/components/plugwise/translations/et.json b/homeassistant/components/plugwise/translations/et.json index 4b8c5870511..8ea77f78104 100644 --- a/homeassistant/components/plugwise/translations/et.json +++ b/homeassistant/components/plugwise/translations/et.json @@ -8,20 +8,21 @@ "invalid_auth": "Tuvastamine nurjus", "unknown": "Tundmatu viga" }, + "flow_title": "", "step": { "user": { "data": { - "flow_type": "\u00dchenduse t\u00fc\u00fcp", - "host": "IP aadress", - "password": "Smile ID", - "port": "Smile pordi number" - } + "flow_type": "\u00dchenduse t\u00fc\u00fcp" + }, + "description": "Toode:", + "title": "Plugwise t\u00fc\u00fcp" }, "user_gateway": { "data": { "host": "IP aadress", "password": "Smile ID", - "port": "Port" + "port": "Port", + "username": "Smile kasutajanimi" }, "description": "Palun sisesta:", "title": "Loo \u00fchendus Smile-ga" diff --git a/homeassistant/components/plugwise/translations/fr.json b/homeassistant/components/plugwise/translations/fr.json index fe4b88ab0f1..2fdc3502571 100644 --- a/homeassistant/components/plugwise/translations/fr.json +++ b/homeassistant/components/plugwise/translations/fr.json @@ -12,9 +12,16 @@ "step": { "user": { "data": { - "host": "Adresse IP de Smile", + "flow_type": "Type de connexion" + }, + "description": "Veuillez saisir :", + "title": "Se connecter \u00e0 Smile" + }, + "user_gateway": { + "data": { + "host": "Adresse IP", "password": "ID Smile", - "port": "Num\u00e9ro de port Smile" + "port": "Port" }, "description": "Veuillez saisir :", "title": "Se connecter \u00e0 Smile" diff --git a/homeassistant/components/plugwise/translations/it.json b/homeassistant/components/plugwise/translations/it.json index 4896ac69b1b..18851d055a5 100644 --- a/homeassistant/components/plugwise/translations/it.json +++ b/homeassistant/components/plugwise/translations/it.json @@ -12,10 +12,7 @@ "step": { "user": { "data": { - "flow_type": "Tipo di connessione", - "host": "Indirizzo IP", - "password": "ID Smile", - "port": "Porta" + "flow_type": "Tipo di connessione" }, "description": "Prodotto:", "title": "Tipo di Plugwise" @@ -24,9 +21,10 @@ "data": { "host": "Indirizzo IP", "password": "ID Smile", - "port": "Porta" + "port": "Porta", + "username": "Nome utente Smile" }, - "description": "Si prega di inserire:", + "description": "Si prega di inserire", "title": "Connettiti allo Smile" } } diff --git a/homeassistant/components/plugwise/translations/ko.json b/homeassistant/components/plugwise/translations/ko.json index 04fcb738285..4af12098b7f 100644 --- a/homeassistant/components/plugwise/translations/ko.json +++ b/homeassistant/components/plugwise/translations/ko.json @@ -11,11 +11,6 @@ "flow_title": "Smile: {name}", "step": { "user": { - "data": { - "host": "Smile IP \uc8fc\uc18c", - "password": "Smile ID", - "port": "\uc2a4\ub9c8\uc77c \ud3ec\ud2b8 \ubc88\ud638" - }, "description": "\uc138\ubd80 \uc815\ubcf4", "title": "Smile \uc5d0 \uc5f0\uacb0\ud558\uae30" } diff --git a/homeassistant/components/plugwise/translations/lb.json b/homeassistant/components/plugwise/translations/lb.json index b4983f2775b..4ce9f8b0145 100644 --- a/homeassistant/components/plugwise/translations/lb.json +++ b/homeassistant/components/plugwise/translations/lb.json @@ -12,12 +12,18 @@ "step": { "user": { "data": { - "host": "IP Adresse", + "flow_type": "Typ vun der Verbindung" + }, + "description": "Produkt:", + "title": "Typ vu Plugwise" + }, + "user_gateway": { + "data": { + "host": "IP Adress", "password": "Smile ID", "port": "Port" }, - "description": "Detailler", - "title": "Mat Smile verbannen" + "title": "Mam Smile verbannen" } } }, diff --git a/homeassistant/components/plugwise/translations/nl.json b/homeassistant/components/plugwise/translations/nl.json index be80bb0bdd5..001bbbe6d5e 100644 --- a/homeassistant/components/plugwise/translations/nl.json +++ b/homeassistant/components/plugwise/translations/nl.json @@ -11,10 +11,7 @@ "step": { "user": { "data": { - "flow_type": "Verbindingstype", - "host": "Smile IP-adres", - "password": "Smile-ID", - "port": "Poort" + "flow_type": "Verbindingstype" }, "description": "Details", "title": "Maak verbinding met de Smile" diff --git a/homeassistant/components/plugwise/translations/no.json b/homeassistant/components/plugwise/translations/no.json index a648ef739cc..f8e128a0d27 100644 --- a/homeassistant/components/plugwise/translations/no.json +++ b/homeassistant/components/plugwise/translations/no.json @@ -12,10 +12,7 @@ "step": { "user": { "data": { - "flow_type": "Tilkoblingstype", - "host": "IP adresse", - "password": "", - "port": "Port" + "flow_type": "Tilkoblingstype" }, "description": "Produkt:", "title": "" @@ -24,9 +21,10 @@ "data": { "host": "IP adresse", "password": "Smile ID", - "port": "Port" + "port": "Port", + "username": "Smile brukernavn" }, - "description": "Vennligst skriv inn:", + "description": "Vennligst skriv inn", "title": "Koble til Smile" } } diff --git a/homeassistant/components/plugwise/translations/pl.json b/homeassistant/components/plugwise/translations/pl.json index 41559a38a67..0e6d3b16d4f 100644 --- a/homeassistant/components/plugwise/translations/pl.json +++ b/homeassistant/components/plugwise/translations/pl.json @@ -12,10 +12,7 @@ "step": { "user": { "data": { - "flow_type": "Typ po\u0142\u0105czenia", - "host": "Adres IP", - "password": "Identyfikator Smile", - "port": "Port" + "flow_type": "Typ po\u0142\u0105czenia" }, "description": "Wybierz produkt:", "title": "Wybierz typ Plugwise" @@ -24,7 +21,8 @@ "data": { "host": "Adres IP", "password": "Identyfikator Smile", - "port": "Port" + "port": "Port", + "username": "Nazwa u\u017cytkownika" }, "description": "Wprowad\u017a:", "title": "Po\u0142\u0105czenie ze Smile" diff --git a/homeassistant/components/plugwise/translations/ru.json b/homeassistant/components/plugwise/translations/ru.json index 7bbf48491b1..8a59d492e66 100644 --- a/homeassistant/components/plugwise/translations/ru.json +++ b/homeassistant/components/plugwise/translations/ru.json @@ -12,10 +12,7 @@ "step": { "user": { "data": { - "flow_type": "\u0422\u0438\u043f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f", - "host": "IP-\u0430\u0434\u0440\u0435\u0441", - "password": "ID \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430", - "port": "\u041f\u043e\u0440\u0442" + "flow_type": "\u0422\u0438\u043f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f" }, "description": "\u041f\u0440\u043e\u0434\u0443\u043a\u0442:", "title": "\u0422\u0438\u043f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Plugwise" @@ -24,7 +21,8 @@ "data": { "host": "IP-\u0430\u0434\u0440\u0435\u0441", "password": "Smile ID", - "port": "\u041f\u043e\u0440\u0442" + "port": "\u041f\u043e\u0440\u0442", + "username": "\u041b\u043e\u0433\u0438\u043d Smile" }, "description": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u0432\u0435\u0434\u0438\u0442\u0435:", "title": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a Smile" diff --git a/homeassistant/components/plugwise/translations/sv.json b/homeassistant/components/plugwise/translations/sv.json new file mode 100644 index 00000000000..acbb205a11f --- /dev/null +++ b/homeassistant/components/plugwise/translations/sv.json @@ -0,0 +1,13 @@ +{ + "config": { + "step": { + "user_gateway": { + "data": { + "host": "IP address", + "port": "Port" + }, + "description": "V\u00e4nligen ange:" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/plugwise/translations/zh-Hant.json b/homeassistant/components/plugwise/translations/zh-Hant.json index e4f603c18da..62e186ab61a 100644 --- a/homeassistant/components/plugwise/translations/zh-Hant.json +++ b/homeassistant/components/plugwise/translations/zh-Hant.json @@ -12,10 +12,7 @@ "step": { "user": { "data": { - "flow_type": "\u9023\u7dda\u985e\u578b", - "host": "IP \u4f4d\u5740", - "password": "Smile ID", - "port": "\u901a\u8a0a\u57e0" + "flow_type": "\u9023\u7dda\u985e\u578b" }, "description": "\u7522\u54c1\uff1a", "title": "Plugwise \u985e\u578b" @@ -24,9 +21,10 @@ "data": { "host": "IP \u4f4d\u5740", "password": "Smile ID", - "port": "\u901a\u8a0a\u57e0" + "port": "\u901a\u8a0a\u57e0", + "username": "Smile \u4f7f\u7528\u8005\u540d\u7a31" }, - "description": "\u8acb\u8f38\u5165\u8cc7\u8a0a\uff1a", + "description": "\u8acb\u8f38\u5165\uff1a", "title": "\u9023\u7dda\u81f3 Smile" } } diff --git a/homeassistant/components/plum_lightpad/translations/nl.json b/homeassistant/components/plum_lightpad/translations/nl.json index 42978a06b37..7f0f85b7326 100644 --- a/homeassistant/components/plum_lightpad/translations/nl.json +++ b/homeassistant/components/plum_lightpad/translations/nl.json @@ -2,6 +2,16 @@ "config": { "abort": { "already_configured": "Account is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden" + }, + "step": { + "user": { + "data": { + "password": "Wachtwoord" + } + } } } } \ No newline at end of file diff --git a/homeassistant/components/point/translations/et.json b/homeassistant/components/point/translations/et.json index d019b687733..7a26d227c8e 100644 --- a/homeassistant/components/point/translations/et.json +++ b/homeassistant/components/point/translations/et.json @@ -4,16 +4,25 @@ "already_setup": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", "authorize_url_fail": "Tundmatu viga tuvastamise URL-i loomisel.", "authorize_url_timeout": "Tuvastamise URL'i loomise ajal\u00f5pp.", + "external_setup": "Point on teisest voost edukalt seadistatud.", "no_flows": "Osis pole seadistatud. Palun vaata dokumentatsiooni." }, "create_entry": { "default": "Tuvastamine \u00f5nnestus" }, "error": { + "follow_link": "Enne Esita nupu vajutamist j\u00e4rgi linki ja autendi", "no_token": "Vigane juurdep\u00e4\u00e4sut\u00f5end" }, "step": { + "auth": { + "description": "J\u00e4rgi seda linki [link] ( {authorization_url} ) ja ** Luba** juurdep\u00e4\u00e4s oma Minut'i kontole, siis tule tagasi ja vajuta allolevat nuppu ** Esita **.\n\n [Link]({authorization_url})", + "title": "Autendi Point" + }, "user": { + "data": { + "flow_impl": "Teenuse pakkuja" + }, "description": "Kas alustan seadistamist?", "title": "Vali tuvastusmeetod" } diff --git a/homeassistant/components/point/translations/lb.json b/homeassistant/components/point/translations/lb.json index c2059f2d94f..ccdc9db4fff 100644 --- a/homeassistant/components/point/translations/lb.json +++ b/homeassistant/components/point/translations/lb.json @@ -1,11 +1,11 @@ { "config": { "abort": { - "already_setup": "Dir k\u00ebnnt n\u00ebmmen een eenzegen Point Kont konfigur\u00e9ieren.", + "already_setup": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech.", "authorize_url_fail": "Onbekannte Feeler beim gener\u00e9ieren vun der Autorisatiouns URL.", "authorize_url_timeout": "Z\u00e4it Iwwerschreidung beim gener\u00e9ieren vun der Autorisatiouns URL.", "external_setup": "Point gouf vun engem anere Floss erfollegr\u00e4ich konfigur\u00e9iert.", - "no_flows": "Dir musst Point konfigur\u00e9ieren, ier Dir d\u00ebs Authentifiz\u00e9ierung k\u00ebnnt benotzen.[Liest w.e.g. d'Instruktioune](https://www.home-assistant.io/components/point/)." + "no_flows": "Komponent net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun." }, "create_entry": { "default": "Erfollegr\u00e4ich authentifiz\u00e9iert" diff --git a/homeassistant/components/poolsense/translations/cs.json b/homeassistant/components/poolsense/translations/cs.json index 85669bbd566..d4d94bd7334 100644 --- a/homeassistant/components/poolsense/translations/cs.json +++ b/homeassistant/components/poolsense/translations/cs.json @@ -12,7 +12,8 @@ "email": "E-mail", "password": "Heslo" }, - "description": "Chcete za\u010d\u00edt nastavovat?" + "description": "Chcete za\u010d\u00edt nastavovat?", + "title": "PoolSense" } } } diff --git a/homeassistant/components/poolsense/translations/et.json b/homeassistant/components/poolsense/translations/et.json index ae00a14e035..4e1dc8db1ff 100644 --- a/homeassistant/components/poolsense/translations/et.json +++ b/homeassistant/components/poolsense/translations/et.json @@ -12,7 +12,8 @@ "email": "E-post", "password": "Salas\u00f5na" }, - "description": "Kas alustan seadistamist?" + "description": "Kas alustan seadistamist?", + "title": "" } } } diff --git a/homeassistant/components/poolsense/translations/fr.json b/homeassistant/components/poolsense/translations/fr.json index cd9949baa64..0a9fac75005 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/poolsense/translations/lb.json b/homeassistant/components/poolsense/translations/lb.json index 724cd804cc0..4d7065e6380 100644 --- a/homeassistant/components/poolsense/translations/lb.json +++ b/homeassistant/components/poolsense/translations/lb.json @@ -12,6 +12,7 @@ "email": "E-Mail", "password": "Passwuert" }, + "description": "Soll den Ariichtungs Prozess gestart ginn?", "title": "PoolSense" } } diff --git a/homeassistant/components/poolsense/translations/nl.json b/homeassistant/components/poolsense/translations/nl.json new file mode 100644 index 00000000000..7482a0bbe7c --- /dev/null +++ b/homeassistant/components/poolsense/translations/nl.json @@ -0,0 +1,17 @@ +{ + "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "invalid_auth": "Ongeldige authenticatie" + }, + "step": { + "user": { + "data": { + "password": "Wachtwoord" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/powerwall/translations/et.json b/homeassistant/components/powerwall/translations/et.json index 17b06492a40..996b0ea4b30 100644 --- a/homeassistant/components/powerwall/translations/et.json +++ b/homeassistant/components/powerwall/translations/et.json @@ -5,13 +5,15 @@ }, "error": { "cannot_connect": "\u00dchenduse loomine nurjus. Proovi uuesti", - "unknown": "Ootamatu t\u00f5rge" + "unknown": "Ootamatu t\u00f5rge", + "wrong_version": "Teie Powerwall kasutab tarkvaraversiooni, mida ei toetata. Kaaluge tarkvara uuendamist v\u00f5i probleemist teavitamist, et see saaks lahendatud." }, "step": { "user": { "data": { "ip_address": "IP aadress" - } + }, + "title": "Powerwalliga \u00fchendamine" } } } diff --git a/homeassistant/components/powerwall/translations/lb.json b/homeassistant/components/powerwall/translations/lb.json index 1722daf7479..6a4a9d04bb1 100644 --- a/homeassistant/components/powerwall/translations/lb.json +++ b/homeassistant/components/powerwall/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "Powerwall ass scho konfigur\u00e9iert" + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "unknown": "Onerwaarte Feeler", "wrong_version": "Deng Powerwall benotzt eng Software Versioun d\u00e9i net \u00ebnnerst\u00ebtzt ass. Betruecht een Upgrade ze maachen oder d\u00ebst ze mellen, sou dass et ka gel\u00e9ist ginn." }, diff --git a/homeassistant/components/profiler/__init__.py b/homeassistant/components/profiler/__init__.py index 518e448d4ec..c8f6c9fd1a2 100644 --- a/homeassistant/components/profiler/__init__.py +++ b/homeassistant/components/profiler/__init__.py @@ -1,20 +1,47 @@ """The profiler integration.""" import asyncio import cProfile +from datetime import timedelta +import logging import time +from guppy import hpy +import objgraph from pyprof2calltree import convert import voluptuous as vol from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, ServiceCall +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.service import async_register_admin_service from homeassistant.helpers.typing import ConfigType from .const import DOMAIN SERVICE_START = "start" +SERVICE_MEMORY = "memory" +SERVICE_START_LOG_OBJECTS = "start_log_objects" +SERVICE_STOP_LOG_OBJECTS = "stop_log_objects" +SERVICE_DUMP_LOG_OBJECTS = "dump_log_objects" + +SERVICES = ( + SERVICE_START, + SERVICE_MEMORY, + SERVICE_START_LOG_OBJECTS, + SERVICE_STOP_LOG_OBJECTS, + SERVICE_DUMP_LOG_OBJECTS, +) + +DEFAULT_SCAN_INTERVAL = timedelta(seconds=30) + CONF_SECONDS = "seconds" +CONF_SCAN_INTERVAL = "scan_interval" +CONF_TYPE = "type" + +LOG_INTERVAL_SUB = "log_interval_subscription" + +_LOGGER = logging.getLogger(__name__) async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: @@ -26,11 +53,52 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): """Set up Profiler from a config entry.""" lock = asyncio.Lock() + domain_data = hass.data[DOMAIN] = {} 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 def _async_start_log_objects(call: ServiceCall): + if LOG_INTERVAL_SUB in domain_data: + domain_data[LOG_INTERVAL_SUB]() + + hass.components.persistent_notification.async_create( + "Object growth logging has started. See [the logs](/config/logs) to track the growth of new objects.", + title="Object growth logging started", + notification_id="profile_object_logging", + ) + await hass.async_add_executor_job(_log_objects) + domain_data[LOG_INTERVAL_SUB] = async_track_time_interval( + hass, _log_objects, call.data[CONF_SCAN_INTERVAL] + ) + + async def _async_stop_log_objects(call: ServiceCall): + if LOG_INTERVAL_SUB not in domain_data: + return + + hass.components.persistent_notification.async_dismiss("profile_object_logging") + domain_data.pop(LOG_INTERVAL_SUB)() + + def _dump_log_objects(call: ServiceCall): + obj_type = call.data[CONF_TYPE] + + _LOGGER.critical( + "%s objects in memory: %s", + obj_type, + objgraph.by_type(obj_type), + ) + + hass.components.persistent_notification.create( + f"Objects with type {obj_type} have been dumped to the log. See [the logs](/config/logs) to review the repr of the objects.", + title="Object dump completed", + notification_id="profile_object_dump", + ) + async_register_admin_service( hass, DOMAIN, @@ -41,19 +109,63 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ), ) + 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)} + ), + ) + + async_register_admin_service( + hass, + DOMAIN, + SERVICE_START_LOG_OBJECTS, + _async_start_log_objects, + schema=vol.Schema( + { + vol.Optional( + CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL + ): cv.time_period + } + ), + ) + + async_register_admin_service( + hass, + DOMAIN, + SERVICE_STOP_LOG_OBJECTS, + _async_stop_log_objects, + schema=vol.Schema({}), + ) + + async_register_admin_service( + hass, + DOMAIN, + SERVICE_DUMP_LOG_OBJECTS, + _dump_log_objects, + schema=vol.Schema({vol.Required(CONF_TYPE): str}), + ) + return True async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unload a config entry.""" - hass.services.async_remove(domain=DOMAIN, service=SERVICE_START) + for service in SERVICES: + hass.services.async_remove(domain=DOMAIN, service=service) + if LOG_INTERVAL_SUB in hass.data[DOMAIN]: + hass.data[DOMAIN][LOG_INTERVAL_SUB]() + hass.data.pop(DOMAIN) return True 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 +186,36 @@ 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) + + +def _log_objects(*_): + _LOGGER.critical("Memory Growth: %s", objgraph.growth(limit=100)) diff --git a/homeassistant/components/profiler/manifest.json b/homeassistant/components/profiler/manifest.json index e740a083c77..b448e3d1793 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", "objgraph==3.4.1"], + "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 7033e988fc5..f0b04e9e002 100644 --- a/homeassistant/components/profiler/services.yaml +++ b/homeassistant/components/profiler/services.yaml @@ -4,3 +4,23 @@ 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 +start_log_objects: + description: Start logging growth of objects in memory + fields: + scan_interval: + description: The number of seconds between logging objects. + example: 60.0 +stop_log_objects: + description: Stop logging growth of objects in memory +dump_log_objects: + description: Dump the repr of all matching objects to the log. + fields: + type: + description: The type of objects to dump to the log + example: State diff --git a/homeassistant/components/profiler/translations/fr.json b/homeassistant/components/profiler/translations/fr.json new file mode 100644 index 00000000000..4d10b4f4ecc --- /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/profiler/translations/lb.json b/homeassistant/components/profiler/translations/lb.json index b5a5bded9ff..3d5f9af425a 100644 --- a/homeassistant/components/profiler/translations/lb.json +++ b/homeassistant/components/profiler/translations/lb.json @@ -1,8 +1,11 @@ { "config": { + "abort": { + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." + }, "step": { "user": { - "description": "S\u00e9cher fir Profiler anzeriichten?" + "description": "Soll den Ariichtungs Prozess gestart ginn?" } } } diff --git a/homeassistant/components/progettihwsw/strings.json b/homeassistant/components/progettihwsw/strings.json index 9a0c49d2cba..bb98d565594 100644 --- a/homeassistant/components/progettihwsw/strings.json +++ b/homeassistant/components/progettihwsw/strings.json @@ -1,42 +1,41 @@ { "config": { - "error": { - "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", - "unknown": "[%key:common::config_flow::error::unknown%]" + "error": { + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "unknown": "[%key:common::config_flow::error::unknown%]" + }, + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + }, + "step": { + "user": { + "title": "Set up board", + "data": { + "host": "[%key:common::config_flow::data::host%]", + "port": "[%key:common::config_flow::data::port%]" + } }, - "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" - }, - "step": { - "user": { - "title": "Set up board", - "data": { - "host": "[%key:common::config_flow::data::host%]", - "port": "[%key:common::config_flow::data::port%]" - } - }, - "relay_modes": { - "title": "Set up relays", - "data": { - "relay_1": "Relay 1", - "relay_2": "Relay 2", - "relay_3": "Relay 3", - "relay_4": "Relay 4", - "relay_5": "Relay 5", - "relay_6": "Relay 6", - "relay_7": "Relay 7", - "relay_8": "Relay 8", - "relay_9": "Relay 9", - "relay_10": "Relay 10", - "relay_11": "Relay 11", - "relay_12": "Relay 12", - "relay_13": "Relay 13", - "relay_14": "Relay 14", - "relay_15": "Relay 15", - "relay_16": "Relay 16" - } - } + "relay_modes": { + "title": "Set up relays", + "data": { + "relay_1": "Relay 1", + "relay_2": "Relay 2", + "relay_3": "Relay 3", + "relay_4": "Relay 4", + "relay_5": "Relay 5", + "relay_6": "Relay 6", + "relay_7": "Relay 7", + "relay_8": "Relay 8", + "relay_9": "Relay 9", + "relay_10": "Relay 10", + "relay_11": "Relay 11", + "relay_12": "Relay 12", + "relay_13": "Relay 13", + "relay_14": "Relay 14", + "relay_15": "Relay 15", + "relay_16": "Relay 16" + } } - }, - "title": "ProgettiHWSW Automation" -} \ No newline at end of file + } + } +} diff --git a/homeassistant/components/progettihwsw/translations/ca.json b/homeassistant/components/progettihwsw/translations/ca.json index 00c0545e76a..203d841aa1b 100644 --- a/homeassistant/components/progettihwsw/translations/ca.json +++ b/homeassistant/components/progettihwsw/translations/ca.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "unknown": "Error inesperat", - "wrong_info_relay_modes": "La selecci\u00f3 del mode de rel\u00e9 ha de ser monostable o biestable." + "unknown": "Error inesperat" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "Configuraci\u00f3 del tauler" } } - }, - "title": "Automatitzaci\u00f3 ProgettiHWSW" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/el.json b/homeassistant/components/progettihwsw/translations/el.json index 76109815009..2fed1bba66f 100644 --- a/homeassistant/components/progettihwsw/translations/el.json +++ b/homeassistant/components/progettihwsw/translations/el.json @@ -28,6 +28,5 @@ "title": "\u03a1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1" } } - }, - "title": "\u0391\u03c5\u03c4\u03bf\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03cc\u03c2 ProgettiHWSW" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/en.json b/homeassistant/components/progettihwsw/translations/en.json index 68ef7389a26..cebf20d30c0 100644 --- a/homeassistant/components/progettihwsw/translations/en.json +++ b/homeassistant/components/progettihwsw/translations/en.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Failed to connect", - "unknown": "Unexpected error", - "wrong_info_relay_modes": "Relay mode selection must be monostable or bistable." + "unknown": "Unexpected error" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "Set up board" } } - }, - "title": "ProgettiHWSW Automation" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/es.json b/homeassistant/components/progettihwsw/translations/es.json index 7e5b6797210..d4915dcb4cd 100644 --- a/homeassistant/components/progettihwsw/translations/es.json +++ b/homeassistant/components/progettihwsw/translations/es.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "unknown": "Error inesperado", - "wrong_info_relay_modes": "La selecci\u00f3n del modo de rel\u00e9 debe ser monoestable o biestable." + "unknown": "Error inesperado" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "Configurar tablero" } } - }, - "title": "Automatizaci\u00f3n ProgettiHWSW" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/et.json b/homeassistant/components/progettihwsw/translations/et.json index d9d3c285653..b7e8591bbbf 100644 --- a/homeassistant/components/progettihwsw/translations/et.json +++ b/homeassistant/components/progettihwsw/translations/et.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "unknown": "Tundmatu viga", - "wrong_info_relay_modes": "Relee re\u017eiimi valik on kas mono- v\u00f5i bistabiilne." + "unknown": "Tundmatu viga" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "Seadista liides" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/fr.json b/homeassistant/components/progettihwsw/translations/fr.json index 7a833b27ef2..f175f49aaf4 100644 --- a/homeassistant/components/progettihwsw/translations/fr.json +++ b/homeassistant/components/progettihwsw/translations/fr.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "\u00c9chec de connexion", - "unknown": "Erreur inattendue", - "wrong_info_relay_modes": "La s\u00e9lection du mode de relais doit \u00eatre monostable ou bistable." + "unknown": "Erreur inattendue" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "Configurer le tableau" } } - }, - "title": "Automatisation ProgettiHWSW" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/it.json b/homeassistant/components/progettihwsw/translations/it.json index bad123861f7..955bcba692a 100644 --- a/homeassistant/components/progettihwsw/translations/it.json +++ b/homeassistant/components/progettihwsw/translations/it.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "unknown": "Errore imprevisto", - "wrong_info_relay_modes": "La selezione del modo di funzionamento del rel\u00e8 deve essere monostabile o bistabile." + "unknown": "Errore imprevisto" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "Impostare la scheda" } } - }, - "title": "Automazione di ProgettiHWSW" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/ko.json b/homeassistant/components/progettihwsw/translations/ko.json index b8b78de069c..02fca814811 100644 --- a/homeassistant/components/progettihwsw/translations/ko.json +++ b/homeassistant/components/progettihwsw/translations/ko.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "\uc5f0\uacb0 \uc2e4\ud328", - "unknown": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc5d0\ub7ec", - "wrong_info_relay_modes": "\ub9b4\ub808\uc774 \ubaa8\ub4dc \uc120\ud0dd\uc740 Monostable \ub610\ub294 Bistable \uc774\uc5b4\uc57c \ud569\ub2c8\ub2e4." + "unknown": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc5d0\ub7ec" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "\ubcf4\ub4dc \uc124\uc815" } } - }, - "title": "ProgettiHWSW \uc790\ub3d9\ud654" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/lb.json b/homeassistant/components/progettihwsw/translations/lb.json index 2e5491da644..00c80f3c9bd 100644 --- a/homeassistant/components/progettihwsw/translations/lb.json +++ b/homeassistant/components/progettihwsw/translations/lb.json @@ -4,7 +4,8 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen" + "cannot_connect": "Feeler beim verbannen", + "unknown": "Onerwaarte Feeler" }, "step": { "relay_modes": { @@ -36,6 +37,5 @@ "title": "Board ariichten" } } - }, - "title": "ProgettiHWSW Automatisme" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/nl.json b/homeassistant/components/progettihwsw/translations/nl.json index 511520bedbb..ba10aee5ea2 100644 --- a/homeassistant/components/progettihwsw/translations/nl.json +++ b/homeassistant/components/progettihwsw/translations/nl.json @@ -4,7 +4,8 @@ "already_configured": "Apparaat is al geconfigureerd" }, "error": { - "cannot_connect": "Kan geen verbinding maken" + "cannot_connect": "Kan geen verbinding maken", + "unknown": "Onverwachte fout" }, "step": { "relay_modes": { diff --git a/homeassistant/components/progettihwsw/translations/no.json b/homeassistant/components/progettihwsw/translations/no.json index 1a1bfa718b7..d1a688147ae 100644 --- a/homeassistant/components/progettihwsw/translations/no.json +++ b/homeassistant/components/progettihwsw/translations/no.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "unknown": "Uventet feil", - "wrong_info_relay_modes": "Valg av rel\u00e9modus m\u00e5 v\u00e6re monostable eller bistable." + "unknown": "Uventet feil" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "Definere tavle" } } - }, - "title": "ProgettiHWSW automatisering" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/pl.json b/homeassistant/components/progettihwsw/translations/pl.json index fb70d1a8104..485c29c9bdc 100644 --- a/homeassistant/components/progettihwsw/translations/pl.json +++ b/homeassistant/components/progettihwsw/translations/pl.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "unknown": "Nieoczekiwany b\u0142\u0105d", - "wrong_info_relay_modes": "Tryb przeka\u017anika musi by\u0107 monostabilny lub bistabilny" + "unknown": "Nieoczekiwany b\u0142\u0105d" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "Konfiguracja uk\u0142adu" } } - }, - "title": "Automatyzacja ProgettiHWSW" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/pt.json b/homeassistant/components/progettihwsw/translations/pt.json index 89405d0262b..82e6756df11 100644 --- a/homeassistant/components/progettihwsw/translations/pt.json +++ b/homeassistant/components/progettihwsw/translations/pt.json @@ -2,8 +2,7 @@ "config": { "error": { "cannot_connect": "Falha na liga\u00e7\u00e3o", - "unknown": "Erro inesperado", - "wrong_info_relay_modes": "A sele\u00e7\u00e3o do modo de rel\u00e9 deve ser monoest\u00e1vel ou biest\u00e1vel." + "unknown": "Erro inesperado" }, "step": { "relay_modes": { @@ -35,6 +34,5 @@ "title": "Configurar placa" } } - }, - "title": "Automa\u00e7\u00e3o ProgettiHWSW" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/ru.json b/homeassistant/components/progettihwsw/translations/ru.json index a136e30015d..fe394fcb9c9 100644 --- a/homeassistant/components/progettihwsw/translations/ru.json +++ b/homeassistant/components/progettihwsw/translations/ru.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", - "wrong_info_relay_modes": "\u0420\u0435\u0436\u0438\u043c \u0440\u0435\u043b\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \"monostable\" \u0438\u043b\u0438 \"bistable\"." + "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043b\u0430\u0442\u044b" } } - }, - "title": "ProgettiHWSW Automation" + } } \ No newline at end of file diff --git a/homeassistant/components/progettihwsw/translations/zh-Hant.json b/homeassistant/components/progettihwsw/translations/zh-Hant.json index c54ff924902..13a968114a5 100644 --- a/homeassistant/components/progettihwsw/translations/zh-Hant.json +++ b/homeassistant/components/progettihwsw/translations/zh-Hant.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "unknown": "\u672a\u9810\u671f\u932f\u8aa4", - "wrong_info_relay_modes": "\u7e7c\u96fb\u5668\u6a21\u5f0f\u9078\u64c7\u5fc5\u9808\u70ba\u8907\u632f\u5668\u6216\u96d9\u7a69\u614b\u96fb\u8def\u3002" + "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "step": { "relay_modes": { @@ -38,6 +37,5 @@ "title": "\u8a2d\u5b9a\u4e3b\u6a5f\u677f" } } - }, - "title": "ProgettiHWSW \u81ea\u52d5\u5316" + } } \ No newline at end of file diff --git a/homeassistant/components/proximity/__init__.py b/homeassistant/components/proximity/__init__.py index 2d0d14a69c1..6df0f50b720 100644 --- a/homeassistant/components/proximity/__init__.py +++ b/homeassistant/components/proximity/__init__.py @@ -12,6 +12,8 @@ from homeassistant.const import ( LENGTH_FEET, LENGTH_KILOMETERS, LENGTH_METERS, + LENGTH_MILES, + LENGTH_YARD, ) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity @@ -37,7 +39,13 @@ DEFAULT_PROXIMITY_ZONE = "home" DEFAULT_TOLERANCE = 1 DOMAIN = "proximity" -UNITS = [LENGTH_KILOMETERS, LENGTH_METERS, "mi", LENGTH_FEET] +UNITS = [ + LENGTH_METERS, + LENGTH_KILOMETERS, + LENGTH_FEET, + LENGTH_YARD, + LENGTH_MILES, +] ZONE_SCHEMA = vol.Schema( { diff --git a/homeassistant/components/ps4/translations/bg.json b/homeassistant/components/ps4/translations/bg.json index 7d453374b9d..3bc3542d02e 100644 --- a/homeassistant/components/ps4/translations/bg.json +++ b/homeassistant/components/ps4/translations/bg.json @@ -2,7 +2,6 @@ "config": { "abort": { "credential_error": "\u0413\u0440\u0435\u0448\u043a\u0430 \u043f\u0440\u0438 \u0438\u0437\u0432\u043b\u0438\u0447\u0430\u043d\u0435 \u043d\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438.", - "devices_configured": "\u0412\u0441\u0438\u0447\u043a\u0438 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u0430 \u0432\u0435\u0447\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u0438.", "no_devices_found": "\u041d\u0435 \u0441\u0430 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438 PlayStation 4 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u043c\u0440\u0435\u0436\u0430\u0442\u0430.", "port_987_bind_error": "\u041d\u0435\u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442 \u0437\u0430 \u0440\u0435\u0437\u0435\u0440\u0438\u0432\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0440\u0442 987. \u041c\u043e\u043b\u044f, \u043f\u0440\u043e\u0447\u0435\u0442\u0435\u0442\u0435 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438\u0442\u0435] (https://www.home-assistant.io/components/ps4/) \u0437\u0430 \u0434\u043e\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f.", "port_997_bind_error": "\u041d\u0435\u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442 \u0437\u0430 \u0440\u0435\u0437\u0435\u0440\u0438\u0432\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0440\u0442 997. \u041c\u043e\u043b\u044f, \u043f\u0440\u043e\u0447\u0435\u0442\u0435\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430](https://www.home-assistant.io/components/ps4/) \u0437\u0430 \u0434\u043e\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f." @@ -10,8 +9,7 @@ "error": { "credential_timeout": "\u0412\u0440\u0435\u043c\u0435\u0442\u043e \u0437\u0430 \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 \u0443\u0441\u043b\u0443\u0433\u0430\u0442\u0430 \u0437\u0430 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044f\u0432\u0430\u043d\u0435 \u0438\u0437\u0442\u0435\u0447\u0435. \u041d\u0430\u0442\u0438\u0441\u043d\u0435\u0442\u0435 \"\u0418\u0437\u043f\u0440\u0430\u0449\u0430\u043d\u0435\" \u0437\u0430 \u0434\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u0442\u0435.", "login_failed": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 PlayStation 4. \u041f\u0440\u043e\u0432\u0435\u0440\u0435\u0442\u0435 \u0434\u0430\u043b\u0438 \u0432\u044a\u0432\u0435\u0434\u0435\u043d\u0438\u044f PIN \u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d.", - "no_ipaddress": "\u0412\u044a\u0432\u0435\u0434\u0435\u0442\u0435 IP \u0430\u0434\u0440\u0435\u0441\u0430 \u043d\u0430 PlayStation 4, \u043a\u043e\u0439\u0442\u043e \u0438\u0441\u043a\u0430\u0442\u0435 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435.", - "not_ready": "PlayStation 4 \u043a\u043e\u043d\u0437\u043e\u043b\u0430\u0442\u0430 \u043d\u0435 \u0435 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0438\u043b\u0438 \u0441\u0432\u044a\u0440\u0437\u0430\u043d\u0430 \u043a\u044a\u043c \u043c\u0440\u0435\u0436\u0430\u0442\u0430." + "no_ipaddress": "\u0412\u044a\u0432\u0435\u0434\u0435\u0442\u0435 IP \u0430\u0434\u0440\u0435\u0441\u0430 \u043d\u0430 PlayStation 4, \u043a\u043e\u0439\u0442\u043e \u0438\u0441\u043a\u0430\u0442\u0435 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/ca.json b/homeassistant/components/ps4/translations/ca.json index 92563f333ac..53d45e5104d 100644 --- a/homeassistant/components/ps4/translations/ca.json +++ b/homeassistant/components/ps4/translations/ca.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", "credential_error": "Error en l'obtenci\u00f3 de les credencials.", - "devices_configured": "Tots els dispositius trobats ja estan configurats.", "no_devices_found": "No s'han trobat dispositius a la xarxa", "port_987_bind_error": "No s'ha pogut vincular amb el port 987. Consulta la [documentaci\u00f3](https://www.home-assistant.io/components/ps4/) per a m\u00e9s informaci\u00f3.", "port_997_bind_error": "No s'ha pogut vincular amb el port 997. Consulta la [documentaci\u00f3](https://www.home-assistant.io/components/ps4/) per a m\u00e9s informaci\u00f3." @@ -12,8 +11,7 @@ "cannot_connect": "Ha fallat la connexi\u00f3", "credential_timeout": "El servei de credencials ha expirat. Prem Envia per reiniciar-lo.", "login_failed": "No s'ha pogut sincronitzar amb la PlayStation 4. Verifica que el Codi PIN sigui correcte.", - "no_ipaddress": "Introdueix l'Adre\u00e7a IP de la PlayStation 4 que vulguis configurar.", - "not_ready": "La PlayStation 4 no est\u00e0 engegada o no s'ha connectada a la xarxa." + "no_ipaddress": "Introdueix l'Adre\u00e7a IP de la PlayStation 4 que vulguis configurar." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/cs.json b/homeassistant/components/ps4/translations/cs.json index 135cd0ce0de..0ef5eb5afee 100644 --- a/homeassistant/components/ps4/translations/cs.json +++ b/homeassistant/components/ps4/translations/cs.json @@ -2,7 +2,7 @@ "config": { "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "devices_configured": "V\u0161echna nalezen\u00e1 za\u0159\u00edzen\u00ed jsou ji\u017e nastavena.", + "credential_error": "P\u0159i na\u010d\u00edt\u00e1n\u00ed p\u0159ihla\u0161ovac\u00edch \u00fadaj\u016f do\u0161lo k chyb\u011b.", "no_devices_found": "V s\u00edti nebyla nalezena \u017e\u00e1dn\u00e1 za\u0159\u00edzen\u00ed", "port_987_bind_error": "Nelze se p\u0159ipojit na port 987. Dal\u0161\u00ed informace naleznete v [dokumentaci](https://www.home-assistant.io/components/ps4/).", "port_997_bind_error": "Nelze se p\u0159ipojit na port 997. Dal\u0161\u00ed informace naleznete v [dokumentaci](https://www.home-assistant.io/components/ps4/)." @@ -10,8 +10,7 @@ "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "login_failed": "Nepoda\u0159ilo se sp\u00e1rovat s PlayStation 4. Ov\u011b\u0159te, zda je PIN k\u00f3d spr\u00e1vn\u00fd.", - "no_ipaddress": "Zadejte IP adresu PlayStation 4, kter\u00fd chcete konfigurovat.", - "not_ready": "PlayStation 4 nen\u00ed zapnut\u00e9 nebo p\u0159ipojen\u00e9 k s\u00edti." + "no_ipaddress": "Zadejte IP adresu PlayStation 4, kter\u00fd chcete konfigurovat." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/da.json b/homeassistant/components/ps4/translations/da.json index 353edb079ae..747e2d07146 100644 --- a/homeassistant/components/ps4/translations/da.json +++ b/homeassistant/components/ps4/translations/da.json @@ -2,7 +2,6 @@ "config": { "abort": { "credential_error": "Fejl ved hentning af legitimationsoplysninger.", - "devices_configured": "Alle de fundne enheder er allerede konfigureret.", "no_devices_found": "Der blev ikke fundet nogen PlayStation 4-enheder p\u00e5 netv\u00e6rket.", "port_987_bind_error": "Kunne ikke binde til port 987. Se [dokumentationen](https://www.home-assistant.io/components/ps4/) for yderligere oplysninger.", "port_997_bind_error": "Kunne ikke binde til port 997. Se [dokumentationen](https://www.home-assistant.io/components/ps4/) for yderligere oplysninger." @@ -10,8 +9,7 @@ "error": { "credential_timeout": "Tjenesten for legitimationsoplysninger fik timeout. Tryk p\u00e5 send for at genstarte.", "login_failed": "Kunne ikke parre med PlayStation 4. Kontroller PIN er korrekt.", - "no_ipaddress": "Indtast IP-adressen p\u00e5 den PlayStation 4, du gerne vil konfigurere.", - "not_ready": "PlayStation 4 er ikke t\u00e6ndt eller tilsluttet til netv\u00e6rket." + "no_ipaddress": "Indtast IP-adressen p\u00e5 den PlayStation 4, du gerne vil konfigurere." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/de.json b/homeassistant/components/ps4/translations/de.json index 73fe6e8926f..71dd785b4ff 100644 --- a/homeassistant/components/ps4/translations/de.json +++ b/homeassistant/components/ps4/translations/de.json @@ -2,7 +2,6 @@ "config": { "abort": { "credential_error": "Fehler beim Abrufen der Anmeldeinformationen.", - "devices_configured": "Alle gefundenen Ger\u00e4te sind bereits konfiguriert.", "no_devices_found": "Es wurden keine PlayStation 4 im Netzwerk gefunden.", "port_987_bind_error": "Konnte sich nicht an Port 987 binden. Weitere Informationen findest du in der [Dokumentation] (https://www.home-assistant.io/components/ps4/).", "port_997_bind_error": "Bind to Port 997 nicht m\u00f6glich. Weitere Informationen findest du in der [Dokumentation](https://www.home-assistant.io/components/ps4/)" @@ -10,8 +9,7 @@ "error": { "credential_timeout": "Zeit\u00fcberschreitung beim Warten auf den Anmeldedienst. Klicken zum Neustarten auf Senden.", "login_failed": "Fehler beim Koppeln mit PlayStation 4. \u00dcberpr\u00fcfe, ob die PIN korrekt ist.", - "no_ipaddress": "Gib die IP-Adresse der PlayStation 4 ein, die konfiguriert werden soll.", - "not_ready": "PlayStation 4 ist nicht eingeschaltet oder mit dem Netzwerk verbunden." + "no_ipaddress": "Gib die IP-Adresse der PlayStation 4 ein, die konfiguriert werden soll." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/en.json b/homeassistant/components/ps4/translations/en.json index 8e326861279..12b154f48de 100644 --- a/homeassistant/components/ps4/translations/en.json +++ b/homeassistant/components/ps4/translations/en.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Device is already configured", "credential_error": "Error fetching credentials.", - "devices_configured": "All devices found are already configured.", "no_devices_found": "No devices found on the network", "port_987_bind_error": "Could not bind to port 987. Refer to the [documentation](https://www.home-assistant.io/components/ps4/) for additional info.", "port_997_bind_error": "Could not bind to port 997. Refer to the [documentation](https://www.home-assistant.io/components/ps4/) for additional info." @@ -12,8 +11,7 @@ "cannot_connect": "Failed to connect", "credential_timeout": "Credential service timed out. Press submit to restart.", "login_failed": "Failed to pair to PlayStation 4. Verify PIN Code is correct.", - "no_ipaddress": "Enter the IP Address of the PlayStation 4 you would like to configure.", - "not_ready": "PlayStation 4 is not on or connected to network." + "no_ipaddress": "Enter the IP Address of the PlayStation 4 you would like to configure." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/es-419.json b/homeassistant/components/ps4/translations/es-419.json index c718c4469aa..220183775f4 100644 --- a/homeassistant/components/ps4/translations/es-419.json +++ b/homeassistant/components/ps4/translations/es-419.json @@ -2,7 +2,6 @@ "config": { "abort": { "credential_error": "Error al obtener las credenciales.", - "devices_configured": "Todos los dispositivos encontrados ya est\u00e1n configurados.", "no_devices_found": "No se encontraron dispositivos PlayStation 4 en la red.", "port_987_bind_error": "No se pudo enlazar al puerto 987.", "port_997_bind_error": "No se pudo enlazar al puerto 997." @@ -10,8 +9,7 @@ "error": { "credential_timeout": "Servicio de credenciales agotado. Presione enviar para reiniciar.", "login_failed": "No se ha podido emparejar con PlayStation 4. Verifique que el PIN sea correcto.", - "no_ipaddress": "Ingrese la direcci\u00f3n IP de la PlayStation 4 que desea configurar.", - "not_ready": "PlayStation 4 no est\u00e1 encendida o conectada a la red." + "no_ipaddress": "Ingrese la direcci\u00f3n IP de la PlayStation 4 que desea configurar." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/es.json b/homeassistant/components/ps4/translations/es.json index 0782e946885..f65a27c61b6 100644 --- a/homeassistant/components/ps4/translations/es.json +++ b/homeassistant/components/ps4/translations/es.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado", "credential_error": "Error al obtener las credenciales.", - "devices_configured": "Todos los dispositivos encontrados ya est\u00e1n configurados.", "no_devices_found": "No se encuentran dispositivos PlayStation 4 en la red.", "port_987_bind_error": "No se ha podido unir al puerto 987. Consulta la [documentaci\u00f3n](https://www.home-assistant.io/components/ps4/) para m\u00e1s informaci\u00f3n.", "port_997_bind_error": "No se ha podido unir al puerto 997. Consulta la [documentaci\u00f3n](https://www.home-assistant.io/components/ps4/) para m\u00e1s informaci\u00f3n." @@ -12,8 +11,7 @@ "cannot_connect": "No se pudo conectar", "credential_timeout": "Se agot\u00f3 el tiempo para el servicio de credenciales. Pulsa enviar para reiniciar.", "login_failed": "No se ha podido vincular con PlayStation 4. Verifica que el PIN sea correcto.", - "no_ipaddress": "Introduce la direcci\u00f3n IP de la PlayStation 4 que quieres configurar.", - "not_ready": "PlayStation 4 no est\u00e1 encendido o conectado a la red." + "no_ipaddress": "Introduce la direcci\u00f3n IP de la PlayStation 4 que quieres configurar." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/et.json b/homeassistant/components/ps4/translations/et.json index 5d7f75573aa..ddc6f0b73a9 100644 --- a/homeassistant/components/ps4/translations/et.json +++ b/homeassistant/components/ps4/translations/et.json @@ -2,25 +2,36 @@ "config": { "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "no_devices_found": "V\u00f5rgust ei leitud seadmeid" + "credential_error": "Viga volituste hankimisel.", + "no_devices_found": "V\u00f5rgust ei leitud seadmeid", + "port_987_bind_error": "Ei saa siduda pordiga 987. Lisateavet leiad aadressilt [documentation](https://www.home-assistant.io/components/ps4/).", + "port_997_bind_error": "Ei saa siduda pordiga 997. Lisateavet leiad aadressilt [documentation](https://www.home-assistant.io/components/ps4/)." }, "error": { "cannot_connect": "\u00dchendus nurjus", + "credential_timeout": "Mandaaditeenus aegus. Taask\u00e4ivitamiseks vajuta nuppu Esita.", "login_failed": "PlayStation 4-ga sidumine nurjus. Veendu, et PIN kood on \u00f5ige.", "no_ipaddress": "Sisesta Playstation, 4 mida soovid seadistada, IP-aadress." }, "step": { + "creds": { + "description": "Vaja on volitusi. Vajuta nuppu Esita ja seej\u00e4rel v\u00e4rskenda PS4 2nd Screen rakenduses seadmeid ning vali j\u00e4tkamiseks seade \u201eHome-Assistant\u201d.", + "title": "" + }, "link": { "data": { "code": "PIN kood", "ip_address": "IP aadress", - "name": "Nimi" + "name": "Nimi", + "region": "Piirkond" }, - "description": "Sisesta oma PlayStation 4 teave. PIN koodi saamiseks mine PlayStation 4 konsooli \u201eSeaded\u201d. Seej\u00e4rel liigu jaotisse \u201eMobiilirakenduse \u00fchenduse seaded\u201d ja vali \u201eLisa seade\u201d. SisestaPIN kood . Lisateavet leiad [dokumentatsioonist] (https://www.home-assistant.io/components/ps4/)." + "description": "Sisesta oma PlayStation 4 teave. PIN koodi saamiseks mine PlayStation 4 konsooli \u201eSeaded\u201d. Seej\u00e4rel liigu jaotisse \u201eMobiilirakenduse \u00fchenduse seaded\u201d ja vali \u201eLisa seade\u201d. SisestaPIN kood . Lisateavet leiad [dokumentatsioonist] (https://www.home-assistant.io/components/ps4/).", + "title": "" }, "mode": { "data": { - "ip_address": "IP-aadress (J\u00e4tke t\u00fchjaks, kui kasutate automaatset tuvastamist)" + "ip_address": "IP-aadress (J\u00e4tke t\u00fchjaks, kui kasutate automaatset tuvastamist)", + "mode": "Seadistuste re\u017eiim" }, "description": "Valikonfigureerimise re\u017eiim. V\u00e4lja IP-aadress saab automaatse tuvastamise valimisel t\u00fchjaks j\u00e4tta, kuna seadmed avastatakse automaatselt.", "title": "" diff --git a/homeassistant/components/ps4/translations/fr.json b/homeassistant/components/ps4/translations/fr.json index ca152e727c8..82fe682e8f6 100644 --- a/homeassistant/components/ps4/translations/fr.json +++ b/homeassistant/components/ps4/translations/fr.json @@ -1,17 +1,17 @@ { "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.", "port_987_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.", "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.", - "not_ready": "PlayStation 4 n'est pas allum\u00e9e ou connect\u00e9e au r\u00e9seau." + "no_ipaddress": "Entrez l'adresse IP de la PlayStation 4 que vous souhaitez configurer." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/he.json b/homeassistant/components/ps4/translations/he.json index 7513b5be12d..ec0807982cc 100644 --- a/homeassistant/components/ps4/translations/he.json +++ b/homeassistant/components/ps4/translations/he.json @@ -1,12 +1,8 @@ { "config": { "abort": { - "devices_configured": "\u05db\u05dc \u05d4\u05d4\u05ea\u05e7\u05e0\u05d9\u05dd \u05e9\u05e0\u05de\u05e6\u05d0\u05d5 \u05db\u05d1\u05e8 \u05de\u05d5\u05d2\u05d3\u05e8\u05d9\u05dd.", "no_devices_found": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05db\u05e9\u05d9\u05e8\u05d9 \u05e4\u05dc\u05d9\u05d9\u05e1\u05d8\u05d9\u05d9\u05e9\u05df 4 \u05d1\u05e8\u05e9\u05ea." }, - "error": { - "not_ready": "PlayStation 4 \u05d0\u05d9\u05e0\u05d5 \u05e4\u05d5\u05e2\u05dc \u05d0\u05d5 \u05de\u05d7\u05d5\u05d1\u05e8 \u05dc\u05e8\u05e9\u05ea." - }, "step": { "creds": { "title": "\u05e4\u05dc\u05d9\u05d9\u05e1\u05d8\u05d9\u05d9\u05e9\u05df 4" diff --git a/homeassistant/components/ps4/translations/it.json b/homeassistant/components/ps4/translations/it.json index 73dcd5890a1..8ada9acadb3 100644 --- a/homeassistant/components/ps4/translations/it.json +++ b/homeassistant/components/ps4/translations/it.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "credential_error": "Errore nel recupero delle credenziali.", - "devices_configured": "Tutti i dispositivi trovati sono gi\u00e0 configurati.", "no_devices_found": "Nessun dispositivo trovato sulla rete", "port_987_bind_error": "Impossibile collegarsi alla porta 987. Fare riferimento alla [documentazione](https://www.home-assistant.io/components/ps4/) per ulteriori informazioni.", "port_997_bind_error": "Impossibile collegarsi alla porta 997. Consultare la [documentazione](https://www.home-assistant.io/components/ps4/) per ulteriori informazioni." @@ -12,8 +11,7 @@ "cannot_connect": "Impossibile connettersi", "credential_timeout": "Servizio credenziali scaduto. Premi Invia per riavviare.", "login_failed": "Impossibile eseguire l'associazione a PlayStation 4. Verificare che il Codice PIN sia corretto.", - "no_ipaddress": "Inserire l'Indirizzo IP della PlayStation 4 che desideri configurare.", - "not_ready": "La PlayStation 4 non \u00e8 accesa o non \u00e8 collegata alla rete." + "no_ipaddress": "Inserire l'Indirizzo IP della PlayStation 4 che desideri configurare." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/ko.json b/homeassistant/components/ps4/translations/ko.json index 5a9ab246ac2..0e62a64d1c6 100644 --- a/homeassistant/components/ps4/translations/ko.json +++ b/homeassistant/components/ps4/translations/ko.json @@ -2,7 +2,6 @@ "config": { "abort": { "credential_error": "\uc790\uaca9 \uc99d\uba85\uc744 \uac00\uc838\uc624\ub294 \uc911 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.", - "devices_configured": "\ubc1c\uacac\ub41c \ubaa8\ub4e0 \uae30\uae30\ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "no_devices_found": "PlayStation 4 \uae30\uae30\ub97c \ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", "port_987_bind_error": "\ud3ec\ud2b8 987 \uc5d0 \ubc14\uc778\ub529 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. \ucd94\uac00 \uc815\ubcf4\ub294 [\uc548\ub0b4](https://www.home-assistant.io/components/ps4/) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694.", "port_997_bind_error": "\ud3ec\ud2b8 997 \uc5d0 \ubc14\uc778\ub529 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. \ucd94\uac00 \uc815\ubcf4\ub294 [\uc548\ub0b4](https://www.home-assistant.io/components/ps4/) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." @@ -10,8 +9,7 @@ "error": { "credential_timeout": "\uc790\uaca9 \uc99d\uba85 \uc11c\ube44\uc2a4 \uc2dc\uac04\uc774 \ucd08\uacfc\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ud655\uc778\uc744 \ud074\ub9ad\ud558\uc5ec \ub2e4\uc2dc \uc2dc\uc791\ud574\uc8fc\uc138\uc694.", "login_failed": "PlayStation 4 \uc640 \ud398\uc5b4\ub9c1\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. PIN \uc774 \uc62c\ubc14\ub978\uc9c0 \ud655\uc778\ud574\uc8fc\uc138\uc694.", - "no_ipaddress": "\uad6c\uc131\ud558\uace0\uc790 \ud558\ub294 PlayStation 4 \uc758 IP \uc8fc\uc18c\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694.", - "not_ready": "PlayStation 4 \uac00 \ucf1c\uc838 \uc788\uc9c0 \uc54a\uac70\ub098 \ub124\ud2b8\uc6cc\ud06c\uc5d0 \uc5f0\uacb0\ub418\uc5b4 \uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4." + "no_ipaddress": "\uad6c\uc131\ud558\uace0\uc790 \ud558\ub294 PlayStation 4 \uc758 IP \uc8fc\uc18c\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/lb.json b/homeassistant/components/ps4/translations/lb.json index 4295422780e..444de75469c 100644 --- a/homeassistant/components/ps4/translations/lb.json +++ b/homeassistant/components/ps4/translations/lb.json @@ -1,17 +1,17 @@ { "config": { "abort": { + "already_configured": "Apparat ass scho konfigur\u00e9iert", "credential_error": "Feeler beim ausliesen vun den Umeldungs Informatiounen.", - "devices_configured": "All Apparater sinn schonn konfigur\u00e9iert", - "no_devices_found": "Keng Playstation 4 am Netzwierk fonnt.", + "no_devices_found": "Keng Apparater am Netzwierk fonnt.", "port_987_bind_error": "Konnt sech net mam Port 987 verbannen. Liest [Dokumentatioun](https://www.home-assistant.io/components/ps4/) fir w\u00e9ider Informatiounen.", "port_997_bind_error": "Konnt sech net mam Port 997 verbannen. Liest [Dokumentatioun](https://www.home-assistant.io/components/ps4/) fir w\u00e9ider Informatiounen." }, "error": { + "cannot_connect": "Feeler beim verbannen", "credential_timeout": "Z\u00e4it Iwwerschreidung beim Service vun den Umeldungsinformatiounen. Dr\u00e9ck op ofsch\u00e9cke fir nach emol ze starten.", - "login_failed": "Feeler beim verbanne mat der Playstation 4. Iwwerpr\u00e9ift op de PIN korrekt ass.", - "no_ipaddress": "Gitt d'IP Adresse vun der Playstation 4 an:", - "not_ready": "PlayStation 4 ass net un oder mam Netzwierk verbonnen." + "login_failed": "Feeler beim verbanne mat der Playstation 4. Iwwerpr\u00e9if op de PIN Code korrekt ass.", + "no_ipaddress": "G\u00ebff d'IP Adresse vun der Playstation 4 d\u00e9i soll konfigur\u00e9iert ginn an:" }, "step": { "creds": { @@ -20,12 +20,12 @@ }, "link": { "data": { - "code": "PIN", + "code": "PIN Code", "ip_address": "IP Adresse", "name": "Numm", "region": "Regioun" }, - "description": "Gitt \u00e4r Playstation 4 Informatiounen an. Fir 'PIN', gitt an d'Astellunge vun der Playstation 4 Konsole. Dann op 'Mobile App Verbindungs Astellungen' a wielt \"Apparat dob\u00e4isetzen' aus. Gitt de PIN an deen ugewise g\u00ebtt. Liest [Dokumentatioun](https://www.home-assistant.io/components/ps4/) fir w\u00e9ider Informatiounen.", + "description": "G\u00ebff deng Playstation 4 Informatiounen an. Fir 'PIN Code', g\u00e9i an d'Astellunge vun der Playstation 4 Konsole. Dann op 'Mobile App Verbindungs Astellungen' a wiel \"Apparat dob\u00e4isetzen' aus. G\u00ebff de PIN Code an deen ugewise g\u00ebtt. Lies [Dokumentatioun](https://www.home-assistant.io/components/ps4/) fir w\u00e9ider Informatiounen.", "title": "PlayStation 4" }, "mode": { diff --git a/homeassistant/components/ps4/translations/nl.json b/homeassistant/components/ps4/translations/nl.json index 9b010ce2887..d86240b2c0a 100644 --- a/homeassistant/components/ps4/translations/nl.json +++ b/homeassistant/components/ps4/translations/nl.json @@ -1,8 +1,8 @@ { "config": { "abort": { + "already_configured": "Apparaat is al geconfigureerd", "credential_error": "Fout bij ophalen van inloggegevens.", - "devices_configured": "Alle gevonden apparaten zijn al geconfigureerd.", "no_devices_found": "Geen PlayStation 4 apparaten gevonden op het netwerk.", "port_987_bind_error": "Kon niet binden aan poort 987. Raadpleeg de [documentatie] (https://www.home-assistant.io/components/ps4/) voor meer informatie.", "port_997_bind_error": "Kon niet binden aan poort 997. Raadpleeg de [documentatie] (https://www.home-assistant.io/components/ps4/) voor aanvullende informatie." @@ -10,8 +10,7 @@ "error": { "credential_timeout": "Time-out van inlog service. Druk op Submit om opnieuw te starten.", "login_failed": "Kan niet koppelen met PlayStation 4. Controleer of de pincode juist is.", - "no_ipaddress": "Voer het IP-adres in van de PlayStation 4 die je wilt configureren.", - "not_ready": "PlayStation 4 staat niet aan of is niet verbonden met een netwerk." + "no_ipaddress": "Voer het IP-adres in van de PlayStation 4 die je wilt configureren." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/no.json b/homeassistant/components/ps4/translations/no.json index 1aaa81621c9..f6f93fada05 100644 --- a/homeassistant/components/ps4/translations/no.json +++ b/homeassistant/components/ps4/translations/no.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Enheten er allerede konfigurert", "credential_error": "Feil ved henting av legitimasjon.", - "devices_configured": "Alle enheter som ble funnet er allerede konfigurert.", "no_devices_found": "Ingen enheter funnet p\u00e5 nettverket", "port_987_bind_error": "Kunne ikke binde til port 987. Se [dokumentasjonen](https://www.home-assistant.io/components/ps4/) for mer info.", "port_997_bind_error": "Kunne ikke binde til port 997. Se [dokumentasjonen](https://www.home-assistant.io/components/ps4/) for videre informasjon." @@ -12,8 +11,7 @@ "cannot_connect": "Tilkobling mislyktes", "credential_timeout": "Legitimasjonstjenesten ble tidsavbrutt. Trykk send for \u00e5 starte p\u00e5 nytt.", "login_failed": "Kunne ikke koble til PlayStation 4. Bekreft at PIN-kode er riktig.", - "no_ipaddress": "Skriv inn IP adresse til PlayStation 4 du vil konfigurere.", - "not_ready": "PlayStation 4 er ikke p\u00e5sl\u00e5tt eller koblet til nettverk." + "no_ipaddress": "Skriv inn IP adresse til PlayStation 4 du vil konfigurere." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/pl.json b/homeassistant/components/ps4/translations/pl.json index 0e2dba2265c..9840363630d 100644 --- a/homeassistant/components/ps4/translations/pl.json +++ b/homeassistant/components/ps4/translations/pl.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "credential_error": "B\u0142\u0105d podczas pobierania danych logowania", - "devices_configured": "Wszystkie znalezione urz\u0105dzenia s\u0105 ju\u017c skonfigurowane", "no_devices_found": "Nie znaleziono urz\u0105dze\u0144 w sieci", "port_987_bind_error": "Nie mo\u017cna powi\u0105za\u0107 z portem 987. Zapoznaj si\u0119 z [dokumentacj\u0105](https://www.home-assistant.io/components/ps4/), by pozna\u0107 szczeg\u00f3\u0142y.", "port_997_bind_error": "Nie mo\u017cna powi\u0105za\u0107 z portem 997. Zapoznaj si\u0119 z [dokumentacj\u0105](https://www.home-assistant.io/components/ps4/), by pozna\u0107 szczeg\u00f3\u0142y." @@ -12,8 +11,7 @@ "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "credential_timeout": "Przekroczono limit czasu us\u0142ugi po\u015bwiadcze\u0144. Naci\u015bnij przycisk \"Zatwierd\u017a\", aby ponowi\u0107.", "login_failed": "Nie uda\u0142o si\u0119 sparowa\u0107 z PlayStation 4. Sprawd\u017a, czy kod PIN jest poprawny.", - "no_ipaddress": "Wprowad\u017a adres IP PlayStation 4, kt\u00f3ry chcesz skonfigurowa\u0107", - "not_ready": "PlayStation 4 nie jest w\u0142\u0105czona lub po\u0142\u0105czona z sieci\u0105" + "no_ipaddress": "Wprowad\u017a adres IP PlayStation 4, kt\u00f3ry chcesz skonfigurowa\u0107" }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/pt-BR.json b/homeassistant/components/ps4/translations/pt-BR.json index 593ecd19f9a..e0547d1f06f 100644 --- a/homeassistant/components/ps4/translations/pt-BR.json +++ b/homeassistant/components/ps4/translations/pt-BR.json @@ -2,7 +2,6 @@ "config": { "abort": { "credential_error": "Erro ao buscar credenciais.", - "devices_configured": "Todos os dispositivos encontrados j\u00e1 est\u00e3o configurados.", "no_devices_found": "Nenhum dispositivo PlayStation 4 encontrado na rede.", "port_987_bind_error": "N\u00e3o foi poss\u00edvel conectar na porta 987. Consulte a [documenta\u00e7\u00e3o] (https://www.home-assistant.io/components/ps4/) para informa\u00e7\u00f5es adicionais.", "port_997_bind_error": "N\u00e3o foi poss\u00edvel conectar na porta 997. Consulte a [documenta\u00e7\u00e3o] (https://www.home-assistant.io/components/ps4/) para informa\u00e7\u00f5es adicionais." @@ -10,8 +9,7 @@ "error": { "credential_timeout": "Servi\u00e7o de credencial expirou. Pressione Submit para reiniciar.", "login_failed": "N\u00e3o foi poss\u00edvel parear com o PlayStation 4. Verifique se o PIN est\u00e1 correto.", - "no_ipaddress": "Digite o endere\u00e7o IP do PlayStation 4 que voc\u00ea gostaria de configurar.", - "not_ready": "O PlayStation 4 n\u00e3o est\u00e1 ligado ou conectado \u00e0 rede." + "no_ipaddress": "Digite o endere\u00e7o IP do PlayStation 4 que voc\u00ea gostaria de configurar." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/pt.json b/homeassistant/components/ps4/translations/pt.json index de97213fcc4..a8b6c3c6ccf 100644 --- a/homeassistant/components/ps4/translations/pt.json +++ b/homeassistant/components/ps4/translations/pt.json @@ -2,12 +2,10 @@ "config": { "abort": { "credential_error": "Erro ao obter credenciais.", - "devices_configured": "Todos os dispositivos encontrados j\u00e1 est\u00e3o configurados.", "no_devices_found": "N\u00e3o foram encontrados dispositivos PlayStation 4 na rede." }, "error": { - "login_failed": "Falha ao emparelhar com a PlayStation 4. Verifique se o PIN est\u00e1 correto.", - "not_ready": "A PlayStation 4 n\u00e3o est\u00e1 ligada ou ligada \u00e0 rede." + "login_failed": "Falha ao emparelhar com a PlayStation 4. Verifique se o PIN est\u00e1 correto." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/ru.json b/homeassistant/components/ps4/translations/ru.json index bf9501901ec..d39907d0179 100644 --- a/homeassistant/components/ps4/translations/ru.json +++ b/homeassistant/components/ps4/translations/ru.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "credential_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0443\u0447\u0451\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.", - "devices_configured": "\u0412\u0441\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u044b.", "no_devices_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u0441\u0435\u0442\u0438.", "port_987_bind_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043f\u043e\u0440\u0442\u0443 987. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/ps4/).", "port_997_bind_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043f\u043e\u0440\u0442\u0443 997. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/ps4/)." @@ -12,8 +11,7 @@ "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "credential_timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 **\u041f\u041e\u0414\u0422\u0412\u0415\u0420\u0414\u0418\u0422\u042c**, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u043e\u043f\u044b\u0442\u043a\u0443.", "login_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u0441 PlayStation 4. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e PIN-\u043a\u043e\u0434 \u0432\u0432\u0435\u0434\u0451\u043d \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e.", - "no_ipaddress": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 IP-\u0430\u0434\u0440\u0435\u0441 PlayStation 4.", - "not_ready": "PlayStation 4 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u043a \u0441\u0435\u0442\u0438." + "no_ipaddress": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 IP-\u0430\u0434\u0440\u0435\u0441 PlayStation 4." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/sl.json b/homeassistant/components/ps4/translations/sl.json index 13dfc6c2147..1d5752eb326 100644 --- a/homeassistant/components/ps4/translations/sl.json +++ b/homeassistant/components/ps4/translations/sl.json @@ -2,7 +2,6 @@ "config": { "abort": { "credential_error": "Napaka pri pridobivanju poverilnic.", - "devices_configured": "Vse najdene naprave so \u017ee konfigurirane.", "no_devices_found": "V omre\u017eju ni najdenih naprav PS4.", "port_987_bind_error": "Ne morem se povezati z vrati 987. Dodatne informacije najdete v [dokumentaciji] (https://www.home-assistant.io/components/ps4/).", "port_997_bind_error": "Ne morem se povezati z vrati 997. Dodatne informacije najdete v [dokumentaciji] (https://www.home-assistant.io/components/ps4/)." @@ -10,8 +9,7 @@ "error": { "credential_timeout": "Storitev poverilnic je potekla. Pritisnite Po\u0161lji za ponovni zagon.", "login_failed": "Neuspelo seznanjanje s PlayStation 4. Preverite, ali je koda PIN pravilna.", - "no_ipaddress": "Vnesite IP naslov PlayStation-a 4, ki ga \u017eelite konfigurirati.", - "not_ready": "PlayStation 4 ni vklopljen ali povezan z omre\u017ejem." + "no_ipaddress": "Vnesite IP naslov PlayStation-a 4, ki ga \u017eelite konfigurirati." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/sv.json b/homeassistant/components/ps4/translations/sv.json index 3ed8a3765fc..ec117fb9b98 100644 --- a/homeassistant/components/ps4/translations/sv.json +++ b/homeassistant/components/ps4/translations/sv.json @@ -2,7 +2,6 @@ "config": { "abort": { "credential_error": "Fel n\u00e4r f\u00f6rs\u00f6ker h\u00e4mta autentiseringsuppgifter.", - "devices_configured": "Alla enheter som hittats \u00e4r redan konfigurerade.", "no_devices_found": "Inga PlayStation 4 enheter hittades p\u00e5 n\u00e4tverket.", "port_987_bind_error": "Kunde inte binda till port 987.", "port_997_bind_error": "Kunde inte binda till port 997." @@ -10,8 +9,7 @@ "error": { "credential_timeout": "Autentiseringstj\u00e4nsten orsakade timeout. Tryck p\u00e5 Skicka f\u00f6r att starta om.", "login_failed": "Misslyckades med att para till PlayStation 4. Verifiera PIN-koden \u00e4r korrekt.", - "no_ipaddress": "Ange IP-adressen f\u00f6r PlayStation 4 du vill konfigurera.", - "not_ready": "PlayStation 4 \u00e4r inte p\u00e5slagen eller ansluten till n\u00e4tverket." + "no_ipaddress": "Ange IP-adressen f\u00f6r PlayStation 4 du vill konfigurera." }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/zh-Hans.json b/homeassistant/components/ps4/translations/zh-Hans.json index 770a3d8953b..e2c38ad5d05 100644 --- a/homeassistant/components/ps4/translations/zh-Hans.json +++ b/homeassistant/components/ps4/translations/zh-Hans.json @@ -2,15 +2,13 @@ "config": { "abort": { "credential_error": "\u83b7\u53d6\u51ed\u636e\u65f6\u51fa\u9519\u3002", - "devices_configured": "\u6240\u6709\u53d1\u73b0\u7684\u8bbe\u5907\u90fd\u5df2\u914d\u7f6e\u5b8c\u6210\u3002", "no_devices_found": "\u6ca1\u6709\u5728\u7f51\u7edc\u4e0a\u627e\u5230 PlayStation 4 \u8bbe\u5907\u3002", "port_987_bind_error": "\u65e0\u6cd5\u7ed1\u5b9a\u7aef\u53e3 987\u3002", "port_997_bind_error": "\u65e0\u6cd5\u7ed1\u5b9a\u7aef\u53e3 997\u3002" }, "error": { "cannot_connect": "\u8fde\u63a5\u5931\u8d25", - "login_failed": "\u65e0\u6cd5\u4e0e PlayStation 4 \u914d\u5bf9\u3002\u8bf7\u786e\u8ba4 PIN \u662f\u5426\u6b63\u786e\u3002", - "not_ready": "PlayStation 4 \u672a\u5f00\u673a\u6216\u672a\u8fde\u63a5\u5230\u7f51\u7edc\u3002" + "login_failed": "\u65e0\u6cd5\u4e0e PlayStation 4 \u914d\u5bf9\u3002\u8bf7\u786e\u8ba4 PIN \u662f\u5426\u6b63\u786e\u3002" }, "step": { "creds": { diff --git a/homeassistant/components/ps4/translations/zh-Hant.json b/homeassistant/components/ps4/translations/zh-Hant.json index 273c30d1d7a..ddfcbef493f 100644 --- a/homeassistant/components/ps4/translations/zh-Hant.json +++ b/homeassistant/components/ps4/translations/zh-Hant.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "credential_error": "\u53d6\u5f97\u6191\u8b49\u932f\u8aa4\u3002", - "devices_configured": "\u6240\u6709\u8a2d\u5099\u90fd\u5df2\u8a2d\u5b9a\u5b8c\u6210\u3002", "no_devices_found": "\u7db2\u8def\u4e0a\u627e\u4e0d\u5230\u8a2d\u5099", "port_987_bind_error": "\u7121\u6cd5\u7d81\u5b9a\u901a\u8a0a\u57e0 987\u3002\u8acb\u53c3\u8003 [documentation](https://www.home-assistant.io/components/ps4/) \u4ee5\u7372\u5f97\u66f4\u591a\u8cc7\u8a0a\u3002", "port_997_bind_error": "\u7121\u6cd5\u7d81\u5b9a\u901a\u8a0a\u57e0 997\u3002\u8acb\u53c3\u8003 [documentation](https://www.home-assistant.io/components/ps4/) \u4ee5\u7372\u5f97\u66f4\u591a\u8cc7\u8a0a\u3002" @@ -12,8 +11,7 @@ "cannot_connect": "\u9023\u7dda\u5931\u6557", "credential_timeout": "\u6191\u8b49\u670d\u52d9\u903e\u6642\uff0c\u9ede\u9078\u300c\u50b3\u9001\u300d\u4ee5\u91cd\u555f\u3002", "login_failed": "PlayStation 4 \u914d\u5c0d\u5931\u6557\uff0c\u8acb\u78ba\u8a8d PIN \u78bc\u3002", - "no_ipaddress": "\u8f38\u5165\u6240\u8981\u8a2d\u5b9a\u7684 PlayStation 4 \u4e4b IP \u4f4d\u5740\u3002", - "not_ready": "PlayStation 4 \u4e26\u672a\u958b\u555f\u6216\u672a\u9023\u7dda\u81f3\u7db2\u8def\u3002" + "no_ipaddress": "\u8f38\u5165\u6240\u8981\u8a2d\u5b9a\u7684 PlayStation 4 \u4e4b IP \u4f4d\u5740\u3002" }, "step": { "creds": { diff --git a/homeassistant/components/ptvsd/__init__.py b/homeassistant/components/ptvsd/__init__.py index 55cef1405d9..258589084a0 100644 --- a/homeassistant/components/ptvsd/__init__.py +++ b/homeassistant/components/ptvsd/__init__.py @@ -36,6 +36,10 @@ CONFIG_SCHEMA = vol.Schema( async def async_setup(hass: HomeAssistantType, config: ConfigType): """Set up ptvsd debugger.""" + _LOGGER.warning( + "ptvsd is deprecated and will be removed in Home Assistant Core 0.120." + "The debugpy integration can be used as a full replacement for ptvsd" + ) # This is a local import, since importing this at the top, will cause # ptvsd to hook into `sys.settrace`. So does `coverage` to generate diff --git a/homeassistant/components/pvpc_hourly_pricing/translations/et.json b/homeassistant/components/pvpc_hourly_pricing/translations/et.json index 7df1adb08b5..e80e5ef68cd 100644 --- a/homeassistant/components/pvpc_hourly_pricing/translations/et.json +++ b/homeassistant/components/pvpc_hourly_pricing/translations/et.json @@ -2,6 +2,16 @@ "config": { "abort": { "already_configured": "Teenus on juba seadistatud" + }, + "step": { + "user": { + "data": { + "name": "Anduri nimi", + "tariff": "Lepinguline tariif (1, 2 v\u00f5i 3 perioodi)" + }, + "description": "See andur kasutab ametlikku API-d, et saada Hispaania [tunni hinnakujundus (PVPC)] (https://www.esios.ree.es/es/pvpc) elektri tunnihind.\n T\u00e4psema selgituse saamiseks k\u00fclasta [integratsioonidokumente] (https://www.home-assistant.io/integrations/pvpc_hourly_pricing/) \n\n Vali lepinguline m\u00e4\u00e4r l\u00e4htudes arveldusperioodide arvust p\u00e4evas:\n - 1 periood: normaalne\n - 2 perioodi: v\u00e4hendatud (\u00f6\u00f6hind)\n - 3 perioodi: elektriauto (\u00f6\u00f6 hind 3 perioodi)", + "title": "Tariifivalik" + } } } } \ No newline at end of file diff --git a/homeassistant/components/pvpc_hourly_pricing/translations/lb.json b/homeassistant/components/pvpc_hourly_pricing/translations/lb.json index d176bc4ab6e..78894094b72 100644 --- a/homeassistant/components/pvpc_hourly_pricing/translations/lb.json +++ b/homeassistant/components/pvpc_hourly_pricing/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Integratioun ass scho konfigur\u00e9iert mat engem Sensor mat deem Tarif" + "already_configured": "Service ass scho konfigur\u00e9iert" }, "step": { "user": { diff --git a/homeassistant/components/python_script/__init__.py b/homeassistant/components/python_script/__init__.py index 36963dc2f20..6bd840074d9 100644 --- a/homeassistant/components/python_script/__init__.py +++ b/homeassistant/components/python_script/__init__.py @@ -5,15 +5,18 @@ import logging import os import time -from RestrictedPython import compile_restricted_exec +from RestrictedPython import ( + compile_restricted_exec, + limited_builtins, + safe_builtins, + utility_builtins, +) from RestrictedPython.Eval import default_guarded_getitem from RestrictedPython.Guards import ( full_write_guard, guarded_iter_unpack_sequence, guarded_unpack_sequence, - safe_builtins, ) -from RestrictedPython.Utilities import utility_builtins import voluptuous as vol from homeassistant.const import SERVICE_RELOAD @@ -178,12 +181,21 @@ def execute(hass, filename, source, data=None): return getattr(obj, name, default) + extra_builtins = { + "datetime": datetime, + "sorted": sorted, + "time": TimeWrapper(), + "dt_util": dt_util, + "min": min, + "max": max, + "sum": sum, + "any": any, + "all": all, + } builtins = safe_builtins.copy() builtins.update(utility_builtins) - builtins["datetime"] = datetime - builtins["sorted"] = sorted - builtins["time"] = TimeWrapper() - builtins["dt_util"] = dt_util + builtins.update(limited_builtins) + builtins.update(extra_builtins) logger = logging.getLogger(f"{__name__}.{filename}") restricted_globals = { "__builtins__": builtins, diff --git a/homeassistant/components/qnap/sensor.py b/homeassistant/components/qnap/sensor.py index fe4003a9423..11faba0f210 100644 --- a/homeassistant/components/qnap/sensor.py +++ b/homeassistant/components/qnap/sensor.py @@ -85,12 +85,12 @@ _VOLUME_MON_COND = { } _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/rachio/strings.json b/homeassistant/components/rachio/strings.json index c6f1f4ca264..105a2f7c78a 100644 --- a/homeassistant/components/rachio/strings.json +++ b/homeassistant/components/rachio/strings.json @@ -3,7 +3,7 @@ "step": { "user": { "title": "Connect to your Rachio device", - "description": "You will need the API Key from https://app.rach.io/. Select 'Account Settings, and then click on 'GET API KEY'.", + "description": "You will need the API Key from https://app.rach.io/. Go to Settings, then click 'GET API KEY'.", "data": { "api_key": "[%key:common::config_flow::data::api_key%]" } @@ -22,7 +22,7 @@ "step": { "init": { "data": { - "manual_run_mins": "For how long, in minutes, to turn on a station when the switch is enabled." + "manual_run_mins": "Duration in minutes to run when activating a zone switch" } } } diff --git a/homeassistant/components/rachio/translations/ca.json b/homeassistant/components/rachio/translations/ca.json index c451b4df83e..52534a4fb5a 100644 --- a/homeassistant/components/rachio/translations/ca.json +++ b/homeassistant/components/rachio/translations/ca.json @@ -13,7 +13,7 @@ "data": { "api_key": "Clau API" }, - "description": "Necessitar\u00e0s la clau API de https://app.rach.io/. Selecciona 'Configuraci\u00f3 del compte' (Account Settings) i, a continuaci\u00f3, clica 'Obtenir clau API' (GET API KEY).", + "description": "Necessitar\u00e0s la clau API de https://app.rach.io/. Ves a Configuraci\u00f3 (Settings) i, a continuaci\u00f3, clica 'GET API KEY'.", "title": "Connexi\u00f3 amb dispositiu Rachio" } } @@ -22,7 +22,7 @@ "step": { "init": { "data": { - "manual_run_mins": "Durant quant de temps (en minuts) mantenir engegada una estaci\u00f3 quan l'interruptor s'activa." + "manual_run_mins": "Durada en minuts a executar quan s'activi un interruptor de zona" } } } diff --git a/homeassistant/components/rachio/translations/cs.json b/homeassistant/components/rachio/translations/cs.json index 7239396d712..eed0bf75f3e 100644 --- a/homeassistant/components/rachio/translations/cs.json +++ b/homeassistant/components/rachio/translations/cs.json @@ -13,17 +13,9 @@ "data": { "api_key": "Kl\u00ed\u010d API" }, + "description": "Budete pot\u0159ebovat API kl\u00ed\u010d z https://app.rach.io/. P\u0159ejd\u011bte do \"Nastaven\u00ed\" a pak klikn\u011bte na \"Z\u00cdSKAT API KL\u00cd\u010c\".", "title": "P\u0159ipojen\u00ed k za\u0159\u00edzeni Rachio" } } - }, - "options": { - "step": { - "init": { - "data": { - "manual_run_mins": "Na jak dlouho, v minut\u00e1ch, zapnout stanici, kdy\u017e je zapnut vyp\u00edna\u010d." - } - } - } } } \ No newline at end of file diff --git a/homeassistant/components/rachio/translations/en.json b/homeassistant/components/rachio/translations/en.json index ca466938a3c..f2eac811f8a 100644 --- a/homeassistant/components/rachio/translations/en.json +++ b/homeassistant/components/rachio/translations/en.json @@ -13,7 +13,7 @@ "data": { "api_key": "API Key" }, - "description": "You will need the API Key from https://app.rach.io/. Select 'Account Settings, and then click on 'GET API KEY'.", + "description": "You will need the API Key from https://app.rach.io/. Go to Settings, then click 'GET API KEY'.", "title": "Connect to your Rachio device" } } @@ -22,7 +22,7 @@ "step": { "init": { "data": { - "manual_run_mins": "For how long, in minutes, to turn on a station when the switch is enabled." + "manual_run_mins": "Duration in minutes to run when activating a zone switch" } } } diff --git a/homeassistant/components/rachio/translations/et.json b/homeassistant/components/rachio/translations/et.json index 696b5dbf001..5245dc92384 100644 --- a/homeassistant/components/rachio/translations/et.json +++ b/homeassistant/components/rachio/translations/et.json @@ -12,6 +12,17 @@ "user": { "data": { "api_key": "API v\u00f5ti" + }, + "description": "Vaja on API-v\u00f5tit aadressilt https://app.rach.io/. Mine men\u00fc\u00fcsse Seaded ja seej\u00e4rel kl\u00f5psa nuppu \"Hangi API KEY\".", + "title": "\u00dchendu oma Rachio seadmega" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "manual_run_mins": "Tsoonil\u00fcliti aktiveerimisel t\u00f6\u00f6tamise kestus minutites" } } } diff --git a/homeassistant/components/rachio/translations/it.json b/homeassistant/components/rachio/translations/it.json index 49d64be1523..1a1abb6214d 100644 --- a/homeassistant/components/rachio/translations/it.json +++ b/homeassistant/components/rachio/translations/it.json @@ -13,7 +13,7 @@ "data": { "api_key": "Chiave API" }, - "description": "\u00c8 necessaria la chiave API di https://app.rach.io/. Selezionare 'Impostazioni Account', quindi fare clic su 'GET API KEY'.", + "description": "\u00c8 necessaria la chiave API da https://app.rach.io/. Vai su Impostazioni, quindi fai clic su 'GET API KEY'.", "title": "Connettiti al tuo dispositivo Rachio" } } @@ -22,7 +22,7 @@ "step": { "init": { "data": { - "manual_run_mins": "Per quanto tempo, in minuti, accendere una stazione quando l'interruttore \u00e8 abilitato." + "manual_run_mins": "Durata in minuti per l'esecuzione durante l'attivazione di un interruttore di zona" } } } diff --git a/homeassistant/components/rachio/translations/lb.json b/homeassistant/components/rachio/translations/lb.json index 23f95ee9e52..9dc716d962a 100644 --- a/homeassistant/components/rachio/translations/lb.json +++ b/homeassistant/components/rachio/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, diff --git a/homeassistant/components/rachio/translations/no.json b/homeassistant/components/rachio/translations/no.json index c05d2f4c8ec..b5920421e98 100644 --- a/homeassistant/components/rachio/translations/no.json +++ b/homeassistant/components/rachio/translations/no.json @@ -13,7 +13,7 @@ "data": { "api_key": "API-n\u00f8kkel" }, - "description": "Du trenger API-n\u00f8kkelen fra https://app.rach.io/. Velg 'Kontoinnstillinger' og klikk deretter p\u00e5 'F\u00e5 API n\u00f8kkel'.", + "description": "Du trenger API-n\u00f8kkelen fra https://app.rach.io/. G\u00e5 til Innstillinger, og klikk deretter 'GET API KEY'.", "title": "Koble til Rachio-enheten din" } } @@ -22,7 +22,7 @@ "step": { "init": { "data": { - "manual_run_mins": "Hvor lenge, i minutter, for \u00e5 sl\u00e5 p\u00e5 en stasjon n\u00e5r bryteren er aktivert." + "manual_run_mins": "Varighet i minutter \u00e5 kj\u00f8re n\u00e5r du aktiverer en sonebryter" } } } diff --git a/homeassistant/components/rachio/translations/pl.json b/homeassistant/components/rachio/translations/pl.json index 450a4ce3eb2..0cb44fe8b38 100644 --- a/homeassistant/components/rachio/translations/pl.json +++ b/homeassistant/components/rachio/translations/pl.json @@ -13,7 +13,7 @@ "data": { "api_key": "Klucz API" }, - "description": "B\u0119dziesz potrzebowa\u0142 klucza API ze strony https://app.rach.io/. Wybierz 'Account Settings', a nast\u0119pnie kliknij 'GET API KEY'.", + "description": "B\u0119dziesz potrzebowa\u0142 klucza API ze strony https://app.rach.io/. Kliknij 'Settings', a nast\u0119pnie 'GET API KEY'.", "title": "Po\u0142\u0105czenie z urz\u0105dzeniem Rachio" } } @@ -22,7 +22,7 @@ "step": { "init": { "data": { - "manual_run_mins": "Jak d\u0142ugo, w minutach, nale\u017cy w\u0142\u0105czy\u0107 stacj\u0119, gdy prze\u0142\u0105cznik jest w\u0142\u0105czony." + "manual_run_mins": "Czas dzia\u0142ania (w minutach), od aktywacji prze\u0142\u0105cznika strefy." } } } diff --git a/homeassistant/components/rachio/translations/ru.json b/homeassistant/components/rachio/translations/ru.json index c85a07e58bf..53cd98387fa 100644 --- a/homeassistant/components/rachio/translations/ru.json +++ b/homeassistant/components/rachio/translations/ru.json @@ -13,7 +13,7 @@ "data": { "api_key": "\u041a\u043b\u044e\u0447 API" }, - "description": "\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0443\u0436\u0435\u043d \u043a\u043b\u044e\u0447 API \u0441 \u0441\u0430\u0439\u0442\u0430 https://app.rach.io/. \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 'Account Settings', \u0430 \u0437\u0430\u0442\u0435\u043c \u043d\u0430\u0436\u043c\u0438\u0442\u0435 'GET API KEY'.", + "description": "\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0443\u0436\u0435\u043d \u043a\u043b\u044e\u0447 API \u0441 \u0441\u0430\u0439\u0442\u0430 https://app.rach.io/. \u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u0430 \u0437\u0430\u0442\u0435\u043c \u043d\u0430\u0436\u043c\u0438\u0442\u0435 'GET API KEY'.", "title": "Rachio" } } @@ -22,7 +22,7 @@ "step": { "init": { "data": { - "manual_run_mins": "\u041d\u0430 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0446\u0438\u044e, \u043a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u0432\u043a\u043b\u044e\u0447\u0435\u043d (\u0432 \u043c\u0438\u043d\u0443\u0442\u0430\u0445)." + "manual_run_mins": "\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044f \u0437\u043e\u043d\u044b (\u0432 \u043c\u0438\u043d\u0443\u0442\u0430\u0445)" } } } diff --git a/homeassistant/components/rachio/translations/zh-Hant.json b/homeassistant/components/rachio/translations/zh-Hant.json index c79264706c6..f8dbde46919 100644 --- a/homeassistant/components/rachio/translations/zh-Hant.json +++ b/homeassistant/components/rachio/translations/zh-Hant.json @@ -13,7 +13,7 @@ "data": { "api_key": "API \u5bc6\u9470" }, - "description": "\u5c07\u6703\u9700\u8981\u7531 https://app.rach.io/ \u53d6\u5f97 App \u5bc6\u9470\u3002\u9078\u64c7\u5e33\u865f\u8a2d\u5b9a\uff08Account Settings\uff09\u3001\u4e26\u9078\u64c7\u7372\u5f97\u5bc6\u9470\uff08GET API KEY\uff09\u3002", + "description": "\u5c07\u6703\u9700\u8981\u7531 https://app.rach.io/ \u53d6\u5f97 App \u5bc6\u9470\u3002\u9078\u64c7\u8a2d\u5b9a\u4e26\u9078\u64c7\u7372\u5f97\u5bc6\u9470\uff08GET API KEY\uff09\u3002", "title": "\u9023\u7dda\u81f3 Rachio \u8a2d\u5099" } } @@ -22,7 +22,7 @@ "step": { "init": { "data": { - "manual_run_mins": "\u7576\u958b\u95dc\u958b\u555f\u5f8c\u3001\u5de5\u4f5c\u7ad9\u6240\u8981\u958b\u555f\u7684\u5206\u9418\u6578\u3002" + "manual_run_mins": "\u7576\u5340\u57df\u958b\u95dc\u958b\u555f\u5f8c\u3001\u6240\u8981\u958b\u555f\u7684\u5206\u9418\u6578\u3002" } } } diff --git a/homeassistant/components/rainforest_eagle/manifest.json b/homeassistant/components/rainforest_eagle/manifest.json index bae9cbe4ccb..4fbce5d04ce 100644 --- a/homeassistant/components/rainforest_eagle/manifest.json +++ b/homeassistant/components/rainforest_eagle/manifest.json @@ -2,6 +2,6 @@ "domain": "rainforest_eagle", "name": "Rainforest Eagle-200", "documentation": "https://www.home-assistant.io/integrations/rainforest_eagle", - "requirements": ["eagle200_reader==0.2.4", "uEagle==0.0.1"], + "requirements": ["eagle200_reader==0.2.4", "uEagle==0.0.2"], "codeowners": ["@gtdiehl", "@jcalbert"] } diff --git a/homeassistant/components/rainmachine/__init__.py b/homeassistant/components/rainmachine/__init__.py index 7d3c10636fa..a520772ff77 100644 --- a/homeassistant/components/rainmachine/__init__.py +++ b/homeassistant/components/rainmachine/__init__.py @@ -1,54 +1,55 @@ """Support for RainMachine devices.""" import asyncio from datetime import timedelta -import logging +from functools import partial from regenmaschine import Client +from regenmaschine.controller import Controller from regenmaschine.errors import RainMachineError import voluptuous as vol +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_ATTRIBUTION, CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, - CONF_SCAN_INTERVAL, CONF_SSL, ) -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client, config_validation as cv -from homeassistant.helpers.dispatcher import async_dispatcher_send -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.service import verify_domain_control +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, + UpdateFailed, +) from .const import ( CONF_ZONE_RUN_TIME, - DATA_CLIENT, + DATA_CONTROLLER, + DATA_COORDINATOR, DATA_PROGRAMS, DATA_PROVISION_SETTINGS, DATA_RESTRICTIONS_CURRENT, DATA_RESTRICTIONS_UNIVERSAL, DATA_ZONES, - DATA_ZONES_DETAILS, - DEFAULT_SCAN_INTERVAL, DEFAULT_ZONE_RUN, DOMAIN, - PROGRAM_UPDATE_TOPIC, - SENSOR_UPDATE_TOPIC, - ZONE_UPDATE_TOPIC, + LOGGER, ) -_LOGGER = logging.getLogger(__name__) - CONF_PROGRAM_ID = "program_id" CONF_SECONDS = "seconds" CONF_ZONE_ID = "zone_id" +DATA_LISTENER = "listener" + DEFAULT_ATTRIBUTION = "Data provided by Green Electronics LLC" DEFAULT_ICON = "mdi:water" DEFAULT_SSL = True +DEFAULT_UPDATE_INTERVAL = timedelta(seconds=15) SERVICE_ALTER_PROGRAM = vol.Schema({vol.Required(CONF_PROGRAM_ID): cv.positive_int}) @@ -75,19 +76,54 @@ SERVICE_STOP_ZONE_SCHEMA = vol.Schema({vol.Required(CONF_ZONE_ID): cv.positive_i CONFIG_SCHEMA = cv.deprecated(DOMAIN, invalidation_version="0.119") +PLATFORMS = ["binary_sensor", "sensor", "switch"] -async def async_setup(hass, config): + +async def async_update_programs_and_zones( + hass: HomeAssistant, entry: ConfigEntry +) -> None: + """Update program and zone DataUpdateCoordinators. + + Program and zone updates always go together because of how linked they are: + programs affect zones and certain combinations of zones affect programs. + """ + await asyncio.gather( + *[ + hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id][ + DATA_PROGRAMS + ].async_refresh(), + hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id][ + DATA_ZONES + ].async_refresh(), + ] + ) + + +async def async_setup(hass: HomeAssistant, config: dict) -> bool: """Set up the RainMachine component.""" - hass.data[DOMAIN] = {DATA_CLIENT: {}} + hass.data[DOMAIN] = {DATA_CONTROLLER: {}, DATA_COORDINATOR: {}, DATA_LISTENER: {}} return True -async def async_setup_entry(hass, config_entry): +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up RainMachine as config entry.""" - if not config_entry.unique_id: - hass.config_entries.async_update_entry( - config_entry, unique_id=config_entry.data[CONF_IP_ADDRESS] - ) + hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id] = {} + + entry_updates = {} + if not entry.unique_id: + # If the config entry doesn't already have a unique ID, set one: + entry_updates["unique_id"] = entry.data[CONF_IP_ADDRESS] + if CONF_ZONE_RUN_TIME in entry.data: + # If a zone run time exists in the config entry's data, pop it and move it to + # options: + data = {**entry.data} + entry_updates["data"] = data + entry_updates["options"] = { + **entry.options, + CONF_ZONE_RUN_TIME: data.pop(CONF_ZONE_RUN_TIME), + } + if entry_updates: + hass.config_entries.async_update_entry(entry, **entry_updates) _verify_domain_control = verify_domain_control(hass, DOMAIN) @@ -96,105 +132,133 @@ async def async_setup_entry(hass, config_entry): try: await client.load_local( - config_entry.data[CONF_IP_ADDRESS], - config_entry.data[CONF_PASSWORD], - port=config_entry.data[CONF_PORT], - ssl=config_entry.data.get(CONF_SSL, DEFAULT_SSL), + entry.data[CONF_IP_ADDRESS], + entry.data[CONF_PASSWORD], + port=entry.data[CONF_PORT], + ssl=entry.data.get(CONF_SSL, DEFAULT_SSL), ) except RainMachineError as err: - _LOGGER.error("An error occurred: %s", err) + LOGGER.error("An error occurred: %s", err) raise ConfigEntryNotReady from err - else: - # regenmaschine can load multiple controllers at once, but we only grab the one - # we loaded above: - controller = next(iter(client.controllers.values())) - rainmachine = RainMachine( + # regenmaschine can load multiple controllers at once, but we only grab the one + # we loaded above: + controller = hass.data[DOMAIN][DATA_CONTROLLER][entry.entry_id] = next( + iter(client.controllers.values()) + ) + + async def async_update(api_category: str) -> dict: + """Update the appropriate API data based on a category.""" + try: + if api_category == DATA_PROGRAMS: + return await controller.programs.all(include_inactive=True) + + if api_category == DATA_PROVISION_SETTINGS: + return await controller.provisioning.settings() + + if api_category == DATA_RESTRICTIONS_CURRENT: + return await controller.restrictions.current() + + if api_category == DATA_RESTRICTIONS_UNIVERSAL: + return await controller.restrictions.universal() + + return await controller.zones.all(details=True, include_inactive=True) + except RainMachineError as err: + raise UpdateFailed(err) from err + + controller_init_tasks = [] + for api_category in [ + DATA_PROGRAMS, + DATA_PROVISION_SETTINGS, + DATA_RESTRICTIONS_CURRENT, + DATA_RESTRICTIONS_UNIVERSAL, + DATA_ZONES, + ]: + coordinator = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id][ + api_category + ] = DataUpdateCoordinator( hass, - controller, - config_entry.data.get(CONF_ZONE_RUN_TIME, DEFAULT_ZONE_RUN), - config_entry.data.get( - CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL.total_seconds() - ), + LOGGER, + name=f'{controller.name} ("{api_category}")', + update_interval=DEFAULT_UPDATE_INTERVAL, + update_method=partial(async_update, api_category), ) + controller_init_tasks.append(coordinator.async_refresh()) - # Update the data object, which at this point (prior to any sensors registering - # "interest" in the API), will focus on grabbing the latest program and zone data: - await rainmachine.async_update() - hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = rainmachine + await asyncio.gather(*controller_init_tasks) - for component in ("binary_sensor", "sensor", "switch"): + for component in PLATFORMS: hass.async_create_task( - hass.config_entries.async_forward_entry_setup(config_entry, component) + hass.config_entries.async_forward_entry_setup(entry, component) ) @_verify_domain_control - async def disable_program(call): + async def disable_program(call: ServiceCall): """Disable a program.""" - await rainmachine.controller.programs.disable(call.data[CONF_PROGRAM_ID]) - await rainmachine.async_update_programs_and_zones() + await controller.programs.disable(call.data[CONF_PROGRAM_ID]) + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def disable_zone(call): + async def disable_zone(call: ServiceCall): """Disable a zone.""" - await rainmachine.controller.zones.disable(call.data[CONF_ZONE_ID]) - await rainmachine.async_update_programs_and_zones() + await controller.zones.disable(call.data[CONF_ZONE_ID]) + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def enable_program(call): + async def enable_program(call: ServiceCall): """Enable a program.""" - await rainmachine.controller.programs.enable(call.data[CONF_PROGRAM_ID]) - await rainmachine.async_update_programs_and_zones() + await controller.programs.enable(call.data[CONF_PROGRAM_ID]) + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def enable_zone(call): + async def enable_zone(call: ServiceCall): """Enable a zone.""" - await rainmachine.controller.zones.enable(call.data[CONF_ZONE_ID]) - await rainmachine.async_update_programs_and_zones() + await controller.zones.enable(call.data[CONF_ZONE_ID]) + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def pause_watering(call): + async def pause_watering(call: ServiceCall): """Pause watering for a set number of seconds.""" - await rainmachine.controller.watering.pause_all(call.data[CONF_SECONDS]) - await rainmachine.async_update_programs_and_zones() + await controller.watering.pause_all(call.data[CONF_SECONDS]) + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def start_program(call): + async def start_program(call: ServiceCall): """Start a particular program.""" - await rainmachine.controller.programs.start(call.data[CONF_PROGRAM_ID]) - await rainmachine.async_update_programs_and_zones() + await controller.programs.start(call.data[CONF_PROGRAM_ID]) + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def start_zone(call): + async def start_zone(call: ServiceCall): """Start a particular zone for a certain amount of time.""" - await rainmachine.controller.zones.start( + await controller.zones.start( call.data[CONF_ZONE_ID], call.data[CONF_ZONE_RUN_TIME] ) - await rainmachine.async_update_programs_and_zones() + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def stop_all(call): + async def stop_all(call: ServiceCall): """Stop all watering.""" - await rainmachine.controller.watering.stop_all() - await rainmachine.async_update_programs_and_zones() + await controller.watering.stop_all() + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def stop_program(call): + async def stop_program(call: ServiceCall): """Stop a program.""" - await rainmachine.controller.programs.stop(call.data[CONF_PROGRAM_ID]) - await rainmachine.async_update_programs_and_zones() + await controller.programs.stop(call.data[CONF_PROGRAM_ID]) + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def stop_zone(call): + async def stop_zone(call: ServiceCall): """Stop a zone.""" - await rainmachine.controller.zones.stop(call.data[CONF_ZONE_ID]) - await rainmachine.async_update_programs_and_zones() + await controller.zones.stop(call.data[CONF_ZONE_ID]) + await async_update_programs_and_zones(hass, entry) @_verify_domain_control - async def unpause_watering(call): + async def unpause_watering(call: ServiceCall): """Unpause watering.""" - await rainmachine.controller.watering.unpause_all() - await rainmachine.async_update_programs_and_zones() + await controller.watering.unpause_all() + await async_update_programs_and_zones(hass, entry) for service, method, schema in [ ("disable_program", disable_program, SERVICE_ALTER_PROGRAM), @@ -211,184 +275,68 @@ async def async_setup_entry(hass, config_entry): ]: hass.services.async_register(DOMAIN, service, method, schema=schema) - return True - - -async def async_unload_entry(hass, config_entry): - """Unload an OpenUV config entry.""" - hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id) - - tasks = [ - hass.config_entries.async_forward_entry_unload(config_entry, component) - for component in ("binary_sensor", "sensor", "switch") - ] - - await asyncio.gather(*tasks) + hass.data[DOMAIN][DATA_LISTENER] = entry.add_update_listener(async_reload_entry) return True -class RainMachine: - """Define a generic RainMachine object.""" +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Unload an RainMachine config entry.""" + unload_ok = all( + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(entry, component) + for component in PLATFORMS + ] + ) + ) + if unload_ok: + hass.data[DOMAIN][DATA_COORDINATOR].pop(entry.entry_id) + cancel_listener = hass.data[DOMAIN][DATA_LISTENER].pop(entry.entry_id) + cancel_listener() - def __init__(self, hass, controller, default_zone_runtime, scan_interval): - """Initialize.""" - self._async_cancel_time_interval_listener = None - self._scan_interval_seconds = scan_interval - self.controller = controller - self.data = {} - self.default_zone_runtime = default_zone_runtime - self.device_mac = controller.mac - self.hass = hass - - self._api_category_count = { - DATA_PROVISION_SETTINGS: 0, - DATA_RESTRICTIONS_CURRENT: 0, - DATA_RESTRICTIONS_UNIVERSAL: 0, - } - self._api_category_locks = { - DATA_PROVISION_SETTINGS: asyncio.Lock(), - DATA_RESTRICTIONS_CURRENT: asyncio.Lock(), - DATA_RESTRICTIONS_UNIVERSAL: asyncio.Lock(), - } - - async def _async_update_listener_action(self, now): - """Define an async_track_time_interval action to update data.""" - await self.async_update() - - @callback - def async_deregister_sensor_api_interest(self, api_category): - """Decrement the number of entities with data needs from an API category.""" - # If this deregistration should leave us with no registration at all, remove the - # time interval: - if sum(self._api_category_count.values()) == 0: - if self._async_cancel_time_interval_listener: - self._async_cancel_time_interval_listener() - self._async_cancel_time_interval_listener = None - return - - self._api_category_count[api_category] -= 1 - - async def async_fetch_from_api(self, api_category): - """Execute the appropriate coroutine to fetch particular data from the API.""" - if api_category == DATA_PROGRAMS: - data = await self.controller.programs.all(include_inactive=True) - elif api_category == DATA_PROVISION_SETTINGS: - data = await self.controller.provisioning.settings() - elif api_category == DATA_RESTRICTIONS_CURRENT: - data = await self.controller.restrictions.current() - elif api_category == DATA_RESTRICTIONS_UNIVERSAL: - data = await self.controller.restrictions.universal() - elif api_category == DATA_ZONES: - data = await self.controller.zones.all(include_inactive=True) - elif api_category == DATA_ZONES_DETAILS: - # This API call needs to be separate from the DATA_ZONES one above because, - # maddeningly, the DATA_ZONES_DETAILS API call doesn't include the current - # state of the zone: - data = await self.controller.zones.all(details=True, include_inactive=True) - - self.data[api_category] = data - - async def async_register_sensor_api_interest(self, api_category): - """Increment the number of entities with data needs from an API category.""" - # If this is the first registration we have, start a time interval: - if not self._async_cancel_time_interval_listener: - self._async_cancel_time_interval_listener = async_track_time_interval( - self.hass, - self._async_update_listener_action, - timedelta(seconds=self._scan_interval_seconds), - ) - - self._api_category_count[api_category] += 1 - - # If a sensor registers interest in a particular API call and the data doesn't - # exist for it yet, make the API call and grab the data: - async with self._api_category_locks[api_category]: - if api_category not in self.data: - await self.async_fetch_from_api(api_category) - - async def async_update(self): - """Update all RainMachine data.""" - tasks = [self.async_update_programs_and_zones(), self.async_update_sensors()] - await asyncio.gather(*tasks) - - async def async_update_sensors(self): - """Update sensor/binary sensor data.""" - _LOGGER.debug("Updating sensor data for RainMachine") - - # Fetch an API category if there is at least one interested entity: - tasks = {} - for category, count in self._api_category_count.items(): - if count == 0: - continue - tasks[category] = self.async_fetch_from_api(category) - - results = await asyncio.gather(*tasks.values(), return_exceptions=True) - for api_category, result in zip(tasks, results): - if isinstance(result, RainMachineError): - _LOGGER.error( - "There was an error while updating %s: %s", api_category, result - ) - continue - - async_dispatcher_send(self.hass, SENSOR_UPDATE_TOPIC) - - async def async_update_programs_and_zones(self): - """Update program and zone data. - - Program and zone updates always go together because of how linked they are: - programs affect zones and certain combinations of zones affect programs. - - Note that this call does not take into account interested entities when making - the API calls; we make the reasonable assumption that switches will always be - enabled. - """ - _LOGGER.debug("Updating program and zone data for RainMachine") - - tasks = { - DATA_PROGRAMS: self.async_fetch_from_api(DATA_PROGRAMS), - DATA_ZONES: self.async_fetch_from_api(DATA_ZONES), - DATA_ZONES_DETAILS: self.async_fetch_from_api(DATA_ZONES_DETAILS), - } - - results = await asyncio.gather(*tasks.values(), return_exceptions=True) - for api_category, result in zip(tasks, results): - if isinstance(result, RainMachineError): - _LOGGER.error( - "There was an error while updating %s: %s", api_category, result - ) - - async_dispatcher_send(self.hass, PROGRAM_UPDATE_TOPIC) - async_dispatcher_send(self.hass, ZONE_UPDATE_TOPIC) + return unload_ok -class RainMachineEntity(Entity): +async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Handle an options update.""" + await hass.config_entries.async_reload(entry.entry_id) + + +class RainMachineEntity(CoordinatorEntity): """Define a generic RainMachine entity.""" - def __init__(self, rainmachine): + def __init__( + self, coordinator: DataUpdateCoordinator, controller: Controller + ) -> None: """Initialize.""" + super().__init__(coordinator) self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION} + self._controller = controller self._device_class = None + # The colons are removed from the device MAC simply because that value + # (unnecessarily) makes up the existing unique ID formula and we want to avoid + # a breaking change: + self._unique_id = controller.mac.replace(":", "") self._name = None - self.rainmachine = rainmachine @property - def device_class(self): + def device_class(self) -> str: """Return the device class.""" return self._device_class @property - def device_info(self): + def device_info(self) -> dict: """Return device registry information for this entity.""" return { - "identifiers": {(DOMAIN, self.rainmachine.controller.mac)}, - "name": self.rainmachine.controller.name, + "identifiers": {(DOMAIN, self._controller.mac)}, + "name": self._controller.name, "manufacturer": "RainMachine", "model": ( - f"Version {self.rainmachine.controller.hardware_version} " - f"(API: {self.rainmachine.controller.api_version})" + f"Version {self._controller.hardware_version} " + f"(API: {self._controller.api_version})" ), - "sw_version": self.rainmachine.controller.software_version, + "sw_version": self._controller.software_version, } @property @@ -401,18 +349,18 @@ class RainMachineEntity(Entity): """Return the name of the entity.""" return self._name - @property - def should_poll(self): - """Disable polling.""" - return False - @callback - def _update_state(self): - """Update the state.""" + def _handle_coordinator_update(self): + """Respond to a DataUpdateCoordinator update.""" self.update_from_latest_data() self.async_write_ha_state() + async def async_added_to_hass(self): + """Handle entity which will be added.""" + await super().async_added_to_hass() + self.update_from_latest_data() + @callback - def update_from_latest_data(self): - """Update the entity.""" + def update_from_latest_data(self) -> None: + """Update the state.""" raise NotImplementedError diff --git a/homeassistant/components/rainmachine/binary_sensor.py b/homeassistant/components/rainmachine/binary_sensor.py index e2ef8cea64b..5d141b0f008 100644 --- a/homeassistant/components/rainmachine/binary_sensor.py +++ b/homeassistant/components/rainmachine/binary_sensor.py @@ -1,16 +1,22 @@ """This platform provides binary sensors for key RainMachine data.""" +from functools import partial +from typing import Callable + +from regenmaschine.controller import Controller + from homeassistant.components.binary_sensor import BinarySensorEntity -from homeassistant.core import callback -from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from . import RainMachineEntity from .const import ( - DATA_CLIENT, + DATA_CONTROLLER, + DATA_COORDINATOR, DATA_PROVISION_SETTINGS, DATA_RESTRICTIONS_CURRENT, DATA_RESTRICTIONS_UNIVERSAL, - DOMAIN as RAINMACHINE_DOMAIN, - SENSOR_UPDATE_TOPIC, + DOMAIN, ) TYPE_FLOW_SENSOR = "flow_sensor" @@ -66,32 +72,60 @@ BINARY_SENSORS = { } -async def async_setup_entry(hass, entry, async_add_entities): +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: Callable +) -> None: """Set up RainMachine binary sensors based on a config entry.""" - rainmachine = hass.data[RAINMACHINE_DOMAIN][DATA_CLIENT][entry.entry_id] + controller = hass.data[DOMAIN][DATA_CONTROLLER][entry.entry_id] + coordinators = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id] + + @callback + def async_get_sensor(api_category: str) -> partial: + """Generate the appropriate sensor object for an API category.""" + if api_category == DATA_PROVISION_SETTINGS: + return partial( + ProvisionSettingsBinarySensor, + coordinators[DATA_PROVISION_SETTINGS], + ) + + if api_category == DATA_RESTRICTIONS_CURRENT: + return partial( + CurrentRestrictionsBinarySensor, + coordinators[DATA_RESTRICTIONS_CURRENT], + ) + + return partial( + UniversalRestrictionsBinarySensor, + coordinators[DATA_RESTRICTIONS_UNIVERSAL], + ) + async_add_entities( [ - RainMachineBinarySensor( - rainmachine, sensor_type, name, icon, enabled_by_default, api_category + async_get_sensor(api_category)( + controller, sensor_type, name, icon, enabled_by_default ) for ( sensor_type, (name, icon, enabled_by_default, api_category), ) in BINARY_SENSORS.items() - ], + ] ) class RainMachineBinarySensor(RainMachineEntity, BinarySensorEntity): - """A sensor implementation for raincloud device.""" + """Define a general RainMachine binary sensor.""" def __init__( - self, rainmachine, sensor_type, name, icon, enabled_by_default, api_category - ): + self, + coordinator: DataUpdateCoordinator, + controller: Controller, + sensor_type: str, + name: str, + icon: str, + enabled_by_default: bool, + ) -> None: """Initialize the sensor.""" - super().__init__(rainmachine) - - self._api_category = api_category + super().__init__(coordinator, controller) self._enabled_by_default = enabled_by_default self._icon = icon self._name = name @@ -99,7 +133,7 @@ class RainMachineBinarySensor(RainMachineEntity, BinarySensorEntity): self._state = None @property - def entity_registry_enabled_default(self): + def entity_registry_enabled_default(self) -> bool: """Determine whether an entity is enabled by default.""" return self._enabled_by_default @@ -109,54 +143,61 @@ class RainMachineBinarySensor(RainMachineEntity, BinarySensorEntity): return self._icon @property - def is_on(self): + def is_on(self) -> bool: """Return the status of the sensor.""" return self._state @property def unique_id(self) -> str: """Return a unique, Home Assistant friendly identifier for this entity.""" - return "{}_{}".format( - self.rainmachine.device_mac.replace(":", ""), self._sensor_type - ) + return f"{self._unique_id}_{self._sensor_type}" - async def async_added_to_hass(self): - """Register callbacks.""" - self.async_on_remove( - async_dispatcher_connect(self.hass, SENSOR_UPDATE_TOPIC, self._update_state) - ) - await self.rainmachine.async_register_sensor_api_interest(self._api_category) - self.update_from_latest_data() - async def async_will_remove_from_hass(self): - """Disconnect dispatcher listeners and deregister API interest.""" - super().async_will_remove_from_hass() - self.rainmachine.async_deregister_sensor_api_interest(self._api_category) +class CurrentRestrictionsBinarySensor(RainMachineBinarySensor): + """Define a binary sensor that handles current restrictions data.""" @callback - def update_from_latest_data(self): + def update_from_latest_data(self) -> None: + """Update the state.""" + if self._sensor_type == TYPE_FREEZE: + self._state = self.coordinator.data["freeze"] + elif self._sensor_type == TYPE_HOURLY: + self._state = self.coordinator.data["hourly"] + elif self._sensor_type == TYPE_MONTH: + self._state = self.coordinator.data["month"] + elif self._sensor_type == TYPE_RAINDELAY: + self._state = self.coordinator.data["rainDelay"] + elif self._sensor_type == TYPE_RAINSENSOR: + self._state = self.coordinator.data["rainSensor"] + elif self._sensor_type == TYPE_WEEKDAY: + self._state = self.coordinator.data["weekDay"] + + +class ProvisionSettingsBinarySensor(RainMachineBinarySensor): + """Define a binary sensor that handles provisioning data.""" + + @callback + def update_from_latest_data(self) -> None: + """Update the state.""" + if self._sensor_type == TYPE_FREEZE: + self._state = self.coordinator.data["freeze"] + elif self._sensor_type == TYPE_HOURLY: + self._state = self.coordinator.data["hourly"] + elif self._sensor_type == TYPE_MONTH: + self._state = self.coordinator.data["month"] + elif self._sensor_type == TYPE_RAINDELAY: + self._state = self.coordinator.data["rainDelay"] + elif self._sensor_type == TYPE_RAINSENSOR: + self._state = self.coordinator.data["rainSensor"] + elif self._sensor_type == TYPE_WEEKDAY: + self._state = self.coordinator.data["weekDay"] + + +class UniversalRestrictionsBinarySensor(RainMachineBinarySensor): + """Define a binary sensor that handles universal restrictions data.""" + + @callback + def update_from_latest_data(self) -> None: """Update the state.""" if self._sensor_type == TYPE_FLOW_SENSOR: - self._state = self.rainmachine.data[DATA_PROVISION_SETTINGS]["system"].get( - "useFlowSensor" - ) - elif self._sensor_type == TYPE_FREEZE: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_CURRENT]["freeze"] - elif self._sensor_type == TYPE_FREEZE_PROTECTION: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_UNIVERSAL][ - "freezeProtectEnabled" - ] - elif self._sensor_type == TYPE_HOT_DAYS: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_UNIVERSAL][ - "hotDaysExtraWatering" - ] - elif self._sensor_type == TYPE_HOURLY: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_CURRENT]["hourly"] - elif self._sensor_type == TYPE_MONTH: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_CURRENT]["month"] - elif self._sensor_type == TYPE_RAINDELAY: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_CURRENT]["rainDelay"] - elif self._sensor_type == TYPE_RAINSENSOR: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_CURRENT]["rainSensor"] - elif self._sensor_type == TYPE_WEEKDAY: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_CURRENT]["weekDay"] + self._state = self.coordinator.data["system"].get("useFlowSensor") diff --git a/homeassistant/components/rainmachine/config_flow.py b/homeassistant/components/rainmachine/config_flow.py index d942ecccfab..49eba95d047 100644 --- a/homeassistant/components/rainmachine/config_flow.py +++ b/homeassistant/components/rainmachine/config_flow.py @@ -4,19 +4,13 @@ from regenmaschine.errors import RainMachineError import voluptuous as vol from homeassistant import config_entries -from homeassistant.const import ( - CONF_IP_ADDRESS, - CONF_PASSWORD, - CONF_PORT, - CONF_SCAN_INTERVAL, - CONF_SSL, -) -from homeassistant.helpers import aiohttp_client +from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SSL +from homeassistant.core import callback +from homeassistant.helpers import aiohttp_client, config_validation as cv from .const import ( # pylint: disable=unused-import CONF_ZONE_RUN_TIME, DEFAULT_PORT, - DEFAULT_SCAN_INTERVAL, DEFAULT_ZONE_RUN, DOMAIN, ) @@ -46,6 +40,12 @@ class RainMachineFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): errors=errors if errors else {}, ) + @staticmethod + @callback + def async_get_options_flow(config_entry): + """Define the config flow to handle options.""" + return RainMachineOptionsFlowHandler(config_entry) + async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" if not user_input: @@ -77,11 +77,33 @@ class RainMachineFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): CONF_PASSWORD: user_input[CONF_PASSWORD], CONF_PORT: user_input[CONF_PORT], CONF_SSL: user_input.get(CONF_SSL, True), - CONF_SCAN_INTERVAL: user_input.get( - CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL.total_seconds() - ), CONF_ZONE_RUN_TIME: user_input.get( CONF_ZONE_RUN_TIME, DEFAULT_ZONE_RUN ), }, ) + + +class RainMachineOptionsFlowHandler(config_entries.OptionsFlow): + """Handle a RainMachine options flow.""" + + def __init__(self, config_entry): + """Initialize.""" + self.config_entry = config_entry + + async def async_step_init(self, user_input=None): + """Manage the options.""" + if user_input is not None: + return self.async_create_entry(title="", data=user_input) + + return self.async_show_form( + step_id="init", + data_schema=vol.Schema( + { + vol.Optional( + CONF_ZONE_RUN_TIME, + default=self.config_entry.options.get(CONF_ZONE_RUN_TIME), + ): cv.positive_int + } + ), + ) diff --git a/homeassistant/components/rainmachine/const.py b/homeassistant/components/rainmachine/const.py index a88573476ba..568108e23a6 100644 --- a/homeassistant/components/rainmachine/const.py +++ b/homeassistant/components/rainmachine/const.py @@ -1,22 +1,20 @@ """Define constants for the SimpliSafe component.""" -from datetime import timedelta +import logging + +LOGGER = logging.getLogger(__package__) DOMAIN = "rainmachine" CONF_ZONE_RUN_TIME = "zone_run_time" -DATA_CLIENT = "client" +DATA_CONTROLLER = "controller" +DATA_COORDINATOR = "coordinator" +DATA_LISTENER = "listener" DATA_PROGRAMS = "programs" DATA_PROVISION_SETTINGS = "provision.settings" DATA_RESTRICTIONS_CURRENT = "restrictions.current" DATA_RESTRICTIONS_UNIVERSAL = "restrictions.universal" DATA_ZONES = "zones" -DATA_ZONES_DETAILS = "zones_details" DEFAULT_PORT = 8080 -DEFAULT_SCAN_INTERVAL = timedelta(seconds=60) DEFAULT_ZONE_RUN = 60 * 10 - -PROGRAM_UPDATE_TOPIC = f"{DOMAIN}_program_update" -SENSOR_UPDATE_TOPIC = f"{DOMAIN}_data_update" -ZONE_UPDATE_TOPIC = f"{DOMAIN}_zone_update" diff --git a/homeassistant/components/rainmachine/manifest.json b/homeassistant/components/rainmachine/manifest.json index 07321801381..5d03155deac 100644 --- a/homeassistant/components/rainmachine/manifest.json +++ b/homeassistant/components/rainmachine/manifest.json @@ -3,6 +3,6 @@ "name": "RainMachine", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/rainmachine", - "requirements": ["regenmaschine==2.1.0"], + "requirements": ["regenmaschine==3.0.0"], "codeowners": ["@bachya"] } diff --git a/homeassistant/components/rainmachine/sensor.py b/homeassistant/components/rainmachine/sensor.py index ef1b88e6489..4533397fb54 100644 --- a/homeassistant/components/rainmachine/sensor.py +++ b/homeassistant/components/rainmachine/sensor.py @@ -1,15 +1,21 @@ """This platform provides support for sensor data from RainMachine.""" +from functools import partial +from typing import Callable + +from regenmaschine.controller import Controller + +from homeassistant.config_entries import ConfigEntry from homeassistant.const import TEMP_CELSIUS, VOLUME_CUBIC_METERS -from homeassistant.core import callback -from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from . import RainMachineEntity from .const import ( - DATA_CLIENT, + DATA_CONTROLLER, + DATA_COORDINATOR, DATA_PROVISION_SETTINGS, DATA_RESTRICTIONS_UNIVERSAL, - DOMAIN as RAINMACHINE_DOMAIN, - SENSOR_UPDATE_TOPIC, + DOMAIN, ) TYPE_FLOW_SENSOR_CLICK_M3 = "flow_sensor_clicks_cubic_meter" @@ -62,20 +68,37 @@ SENSORS = { } -async def async_setup_entry(hass, entry, async_add_entities): +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: Callable +) -> None: """Set up RainMachine sensors based on a config entry.""" - rainmachine = hass.data[RAINMACHINE_DOMAIN][DATA_CLIENT][entry.entry_id] + controller = hass.data[DOMAIN][DATA_CONTROLLER][entry.entry_id] + coordinators = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id] + + @callback + def async_get_sensor(api_category: str) -> partial: + """Generate the appropriate sensor object for an API category.""" + if api_category == DATA_PROVISION_SETTINGS: + return partial( + ProvisionSettingsSensor, + coordinators[DATA_PROVISION_SETTINGS], + ) + + return partial( + UniversalRestrictionsSensor, + coordinators[DATA_RESTRICTIONS_UNIVERSAL], + ) + async_add_entities( [ - RainMachineSensor( - rainmachine, + async_get_sensor(api_category)( + controller, sensor_type, name, icon, unit, device_class, enabled_by_default, - api_category, ) for ( sensor_type, @@ -86,23 +109,21 @@ async def async_setup_entry(hass, entry, async_add_entities): class RainMachineSensor(RainMachineEntity): - """A sensor implementation for raincloud device.""" + """Define a general RainMachine sensor.""" def __init__( self, - rainmachine, - sensor_type, - name, - icon, - unit, - device_class, - enabled_by_default, - api_category, - ): + coordinator: DataUpdateCoordinator, + controller: Controller, + sensor_type: str, + name: str, + icon: str, + unit: str, + device_class: str, + enabled_by_default: bool, + ) -> None: """Initialize.""" - super().__init__(rainmachine) - - self._api_category = api_category + super().__init__(coordinator, controller) self._device_class = device_class self._enabled_by_default = enabled_by_default self._icon = icon @@ -112,7 +133,7 @@ class RainMachineSensor(RainMachineEntity): self._unit = unit @property - def entity_registry_enabled_default(self): + def entity_registry_enabled_default(self) -> bool: """Determine whether an entity is enabled by default.""" return self._enabled_by_default @@ -129,56 +150,47 @@ class RainMachineSensor(RainMachineEntity): @property def unique_id(self) -> str: """Return a unique, Home Assistant friendly identifier for this entity.""" - return "{}_{}".format( - self.rainmachine.device_mac.replace(":", ""), self._sensor_type - ) + return f"{self._unique_id}_{self._sensor_type}" @property - def unit_of_measurement(self): + def unit_of_measurement(self) -> str: """Return the unit the value is expressed in.""" return self._unit - async def async_added_to_hass(self): - """Register callbacks.""" - self.async_on_remove( - async_dispatcher_connect(self.hass, SENSOR_UPDATE_TOPIC, self._update_state) - ) - await self.rainmachine.async_register_sensor_api_interest(self._api_category) - self.update_from_latest_data() - async def async_will_remove_from_hass(self): - """Disconnect dispatcher listeners and deregister API interest.""" - super().async_will_remove_from_hass() - self.rainmachine.async_deregister_sensor_api_interest(self._api_category) +class ProvisionSettingsSensor(RainMachineSensor): + """Define a sensor that handles provisioning data.""" @callback - def update_from_latest_data(self): - """Update the sensor's state.""" + def update_from_latest_data(self) -> None: + """Update the state.""" if self._sensor_type == TYPE_FLOW_SENSOR_CLICK_M3: - self._state = self.rainmachine.data[DATA_PROVISION_SETTINGS]["system"].get( + self._state = self.coordinator.data["system"].get( "flowSensorClicksPerCubicMeter" ) elif self._sensor_type == TYPE_FLOW_SENSOR_CONSUMED_LITERS: - clicks = self.rainmachine.data[DATA_PROVISION_SETTINGS]["system"].get( - "flowSensorWateringClicks" + clicks = self.coordinator.data["system"].get("flowSensorWateringClicks") + clicks_per_m3 = self.coordinator.data["system"].get( + "flowSensorClicksPerCubicMeter" ) - clicks_per_m3 = self.rainmachine.data[DATA_PROVISION_SETTINGS][ - "system" - ].get("flowSensorClicksPerCubicMeter") if clicks and clicks_per_m3: self._state = (clicks * 1000) / clicks_per_m3 else: self._state = None elif self._sensor_type == TYPE_FLOW_SENSOR_START_INDEX: - self._state = self.rainmachine.data[DATA_PROVISION_SETTINGS]["system"].get( - "flowSensorStartIndex" - ) + self._state = self.coordinator.data["system"].get("flowSensorStartIndex") elif self._sensor_type == TYPE_FLOW_SENSOR_WATERING_CLICKS: - self._state = self.rainmachine.data[DATA_PROVISION_SETTINGS]["system"].get( + self._state = self.coordinator.data["system"].get( "flowSensorWateringClicks" ) - elif self._sensor_type == TYPE_FREEZE_TEMP: - self._state = self.rainmachine.data[DATA_RESTRICTIONS_UNIVERSAL][ - "freezeProtectTemp" - ] + + +class UniversalRestrictionsSensor(RainMachineSensor): + """Define a sensor that handles universal restrictions data.""" + + @callback + def update_from_latest_data(self) -> None: + """Update the state.""" + if self._sensor_type == TYPE_FREEZE_TEMP: + self._state = self.coordinator.data["freezeProtectTemp"] diff --git a/homeassistant/components/rainmachine/strings.json b/homeassistant/components/rainmachine/strings.json index d0a6adf4687..1f5a21d37d8 100644 --- a/homeassistant/components/rainmachine/strings.json +++ b/homeassistant/components/rainmachine/strings.json @@ -16,5 +16,15 @@ "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } + }, + "options": { + "step": { + "init": { + "title": "Configure RainMachine", + "data": { + "zone_run_time": "Default zone run time (in seconds)" + } + } + } } } diff --git a/homeassistant/components/rainmachine/switch.py b/homeassistant/components/rainmachine/switch.py index c0dc450ee2b..5c54000a15f 100644 --- a/homeassistant/components/rainmachine/switch.py +++ b/homeassistant/components/rainmachine/switch.py @@ -1,27 +1,27 @@ """This component provides support for RainMachine programs and zones.""" from datetime import datetime -import logging +from typing import Callable, Coroutine +from regenmaschine.controller import Controller from regenmaschine.errors import RequestError from homeassistant.components.switch import SwitchEntity +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_ID -from homeassistant.core import callback -from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from . import RainMachineEntity +from . import RainMachineEntity, async_update_programs_and_zones from .const import ( - DATA_CLIENT, + CONF_ZONE_RUN_TIME, + DATA_CONTROLLER, + DATA_COORDINATOR, DATA_PROGRAMS, DATA_ZONES, - DATA_ZONES_DETAILS, - DOMAIN as RAINMACHINE_DOMAIN, - PROGRAM_UPDATE_TOPIC, - ZONE_UPDATE_TOPIC, + DOMAIN, + LOGGER, ) -_LOGGER = logging.getLogger(__name__) - ATTR_AREA = "area" ATTR_CS_ON = "cs_on" ATTR_CURRENT_CYCLE = "current_cycle" @@ -99,36 +99,56 @@ SWITCH_TYPE_PROGRAM = "program" SWITCH_TYPE_ZONE = "zone" -async def async_setup_entry(hass, entry, async_add_entities): +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: Callable +) -> None: """Set up RainMachine switches based on a config entry.""" - rainmachine = hass.data[RAINMACHINE_DOMAIN][DATA_CLIENT][entry.entry_id] + controller = hass.data[DOMAIN][DATA_CONTROLLER][entry.entry_id] + programs_coordinator = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id][ + DATA_PROGRAMS + ] + zones_coordinator = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id][DATA_ZONES] entities = [] - for program in rainmachine.data[DATA_PROGRAMS]: - entities.append(RainMachineProgram(rainmachine, program)) - for zone in rainmachine.data[DATA_ZONES]: - entities.append(RainMachineZone(rainmachine, zone)) + for uid, program in programs_coordinator.data.items(): + entities.append( + RainMachineProgram( + programs_coordinator, controller, uid, program["name"], entry + ) + ) + for uid, zone in zones_coordinator.data.items(): + entities.append( + RainMachineZone(zones_coordinator, controller, uid, zone["name"], entry) + ) - async_add_entities(entities, True) + async_add_entities(entities) class RainMachineSwitch(RainMachineEntity, SwitchEntity): """A class to represent a generic RainMachine switch.""" - def __init__(self, rainmachine, switch_data): + def __init__( + self, + coordinator: DataUpdateCoordinator, + controller: Controller, + uid: int, + name: str, + entry: ConfigEntry, + ) -> None: """Initialize a generic RainMachine switch.""" - super().__init__(rainmachine) - + super().__init__(coordinator, controller) + self._data = coordinator.data[uid] + self._entry = entry + self._is_active = True self._is_on = False - self._name = switch_data["name"] - self._switch_data = switch_data - self._rainmachine_entity_id = switch_data["uid"] - self._switch_type = None + self._name = name + self._switch_type = type(self).__name__ + self._uid = uid @property def available(self) -> bool: """Return True if entity is available.""" - return self._switch_data["active"] + return self._is_active and self.coordinator.last_update_success @property def icon(self) -> str: @@ -143,18 +163,14 @@ class RainMachineSwitch(RainMachineEntity, SwitchEntity): @property def unique_id(self) -> str: """Return a unique, Home Assistant friendly identifier for this entity.""" - return "{}_{}_{}".format( - self.rainmachine.device_mac.replace(":", ""), - self._switch_type, - self._rainmachine_entity_id, - ) + return f"{self._unique_id}_{self._switch_type}_{self._uid}" - async def _async_run_switch_coroutine(self, api_coro) -> None: + async def _async_run_switch_coroutine(self, api_coro: Coroutine) -> None: """Run a coroutine to toggle the switch.""" try: resp = await api_coro except RequestError as err: - _LOGGER.error( + LOGGER.error( 'Error while toggling %s "%s": %s', self._switch_type, self.unique_id, @@ -163,7 +179,7 @@ class RainMachineSwitch(RainMachineEntity, SwitchEntity): return if resp["statusCode"] != 0: - _LOGGER.error( + LOGGER.error( 'Error while toggling %s "%s": %s', self._switch_type, self.unique_id, @@ -171,69 +187,60 @@ class RainMachineSwitch(RainMachineEntity, SwitchEntity): ) return - self.hass.async_create_task(self.rainmachine.async_update_programs_and_zones()) + # Because of how inextricably linked programs and zones are, anytime one is + # toggled, we make sure to update the data of both coordinators: + self.hass.async_create_task( + async_update_programs_and_zones(self.hass, self._entry) + ) + + @callback + def update_from_latest_data(self) -> None: + """Update the state.""" + self._data = self.coordinator.data[self._uid] + self._is_active = self._data["active"] class RainMachineProgram(RainMachineSwitch): """A RainMachine program.""" - def __init__(self, rainmachine, switch_data): - """Initialize a generic RainMachine switch.""" - super().__init__(rainmachine, switch_data) - self._switch_type = SWITCH_TYPE_PROGRAM - @property def zones(self) -> list: """Return a list of active zones associated with this program.""" - return [z for z in self._switch_data["wateringTimes"] if z["active"]] - - async def async_added_to_hass(self): - """Register callbacks.""" - self.async_on_remove( - async_dispatcher_connect( - self.hass, PROGRAM_UPDATE_TOPIC, self._update_state - ) - ) + return [z for z in self._data["wateringTimes"] if z["active"]] async def async_turn_off(self, **kwargs) -> None: """Turn the program off.""" await self._async_run_switch_coroutine( - self.rainmachine.controller.programs.stop(self._rainmachine_entity_id) + self._controller.programs.stop(self._uid) ) async def async_turn_on(self, **kwargs) -> None: """Turn the program on.""" await self._async_run_switch_coroutine( - self.rainmachine.controller.programs.start(self._rainmachine_entity_id) + self._controller.programs.start(self._uid) ) @callback def update_from_latest_data(self) -> None: - """Update info for the program.""" - [self._switch_data] = [ - p - for p in self.rainmachine.data[DATA_PROGRAMS] - if p["uid"] == self._rainmachine_entity_id - ] + """Update the state.""" + super().update_from_latest_data() - self._is_on = bool(self._switch_data["status"]) + self._is_on = bool(self._data["status"]) - try: + if self._data.get("nextRun") is not None: next_run = datetime.strptime( - "{} {}".format( - self._switch_data["nextRun"], self._switch_data["startTime"] - ), + f"{self._data['nextRun']} {self._data['startTime']}", "%Y-%m-%d %H:%M", ).isoformat() - except ValueError: + else: next_run = None self._attrs.update( { - ATTR_ID: self._switch_data["uid"], + ATTR_ID: self._uid, ATTR_NEXT_RUN: next_run, - ATTR_SOAK: self._switch_data.get("soak"), - ATTR_STATUS: RUN_STATUS_MAP[self._switch_data["status"]], + ATTR_SOAK: self.coordinator.data[self._uid].get("soak"), + ATTR_STATUS: RUN_STATUS_MAP[self.coordinator.data[self._uid]["status"]], ATTR_ZONES: ", ".join(z["name"] for z in self.zones), } ) @@ -242,67 +249,41 @@ class RainMachineProgram(RainMachineSwitch): class RainMachineZone(RainMachineSwitch): """A RainMachine zone.""" - def __init__(self, rainmachine, switch_data): - """Initialize a RainMachine zone.""" - super().__init__(rainmachine, switch_data) - self._switch_type = SWITCH_TYPE_ZONE - - async def async_added_to_hass(self): - """Register callbacks.""" - self.async_on_remove( - async_dispatcher_connect( - self.hass, PROGRAM_UPDATE_TOPIC, self._update_state - ) - ) - self.async_on_remove( - async_dispatcher_connect(self.hass, ZONE_UPDATE_TOPIC, self._update_state) - ) - async def async_turn_off(self, **kwargs) -> None: """Turn the zone off.""" - await self._async_run_switch_coroutine( - self.rainmachine.controller.zones.stop(self._rainmachine_entity_id) - ) + await self._async_run_switch_coroutine(self._controller.zones.stop(self._uid)) async def async_turn_on(self, **kwargs) -> None: """Turn the zone on.""" await self._async_run_switch_coroutine( - self.rainmachine.controller.zones.start( - self._rainmachine_entity_id, self.rainmachine.default_zone_runtime + self._controller.zones.start( + self._uid, + self._entry.options[CONF_ZONE_RUN_TIME], ) ) @callback def update_from_latest_data(self) -> None: - """Update info for the zone.""" - [self._switch_data] = [ - z - for z in self.rainmachine.data[DATA_ZONES] - if z["uid"] == self._rainmachine_entity_id - ] - [details] = [ - z - for z in self.rainmachine.data[DATA_ZONES_DETAILS] - if z["uid"] == self._rainmachine_entity_id - ] + """Update the state.""" + super().update_from_latest_data() - self._is_on = bool(self._switch_data["state"]) + self._is_on = bool(self._data["state"]) self._attrs.update( { - ATTR_STATUS: RUN_STATUS_MAP[self._switch_data["state"]], - ATTR_AREA: details.get("waterSense").get("area"), - ATTR_CURRENT_CYCLE: self._switch_data.get("cycle"), - ATTR_FIELD_CAPACITY: details.get("waterSense").get("fieldCapacity"), - ATTR_ID: self._switch_data["uid"], - ATTR_NO_CYCLES: self._switch_data.get("noOfCycles"), - ATTR_PRECIP_RATE: details.get("waterSense").get("precipitationRate"), - ATTR_RESTRICTIONS: self._switch_data.get("restriction"), - ATTR_SLOPE: SLOPE_TYPE_MAP.get(details.get("slope")), - ATTR_SOIL_TYPE: SOIL_TYPE_MAP.get(details.get("sun")), - ATTR_SPRINKLER_TYPE: SPRINKLER_TYPE_MAP.get(details.get("group_id")), - ATTR_SUN_EXPOSURE: SUN_EXPOSURE_MAP.get(details.get("sun")), - ATTR_TIME_REMAINING: self._switch_data.get("remaining"), - ATTR_VEGETATION_TYPE: VEGETATION_MAP.get(self._switch_data.get("type")), + ATTR_STATUS: RUN_STATUS_MAP[self._data["state"]], + ATTR_AREA: self._data.get("waterSense").get("area"), + ATTR_CURRENT_CYCLE: self._data.get("cycle"), + ATTR_FIELD_CAPACITY: self._data.get("waterSense").get("fieldCapacity"), + ATTR_ID: self._data["uid"], + ATTR_NO_CYCLES: self._data.get("noOfCycles"), + ATTR_PRECIP_RATE: self._data.get("waterSense").get("precipitationRate"), + ATTR_RESTRICTIONS: self._data.get("restriction"), + ATTR_SLOPE: SLOPE_TYPE_MAP.get(self._data.get("slope")), + ATTR_SOIL_TYPE: SOIL_TYPE_MAP.get(self._data.get("sun")), + ATTR_SPRINKLER_TYPE: SPRINKLER_TYPE_MAP.get(self._data.get("group_id")), + ATTR_SUN_EXPOSURE: SUN_EXPOSURE_MAP.get(self._data.get("sun")), + ATTR_TIME_REMAINING: self._data.get("remaining"), + ATTR_VEGETATION_TYPE: VEGETATION_MAP.get(self._data.get("type")), } ) diff --git a/homeassistant/components/rainmachine/translations/bg.json b/homeassistant/components/rainmachine/translations/bg.json index a31785cad00..0ced0b2f334 100644 --- a/homeassistant/components/rainmachine/translations/bg.json +++ b/homeassistant/components/rainmachine/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "error": { - "identifier_exists": "\u041f\u0440\u043e\u0444\u0438\u043b\u044a\u0442 \u0435 \u0432\u0435\u0447\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d", - "invalid_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/ca.json b/homeassistant/components/rainmachine/translations/ca.json index cc77b66aef0..9472211f8df 100644 --- a/homeassistant/components/rainmachine/translations/ca.json +++ b/homeassistant/components/rainmachine/translations/ca.json @@ -4,9 +4,7 @@ "already_configured": "El dispositiu ja est\u00e0 configurat" }, "error": { - "identifier_exists": "El compte ja ha estat configurat", - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Credencials inv\u00e0lides" + "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { "user": { @@ -18,5 +16,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 883e731f838..a40987b5a96 100644 --- a/homeassistant/components/rainmachine/translations/cs.json +++ b/homeassistant/components/rainmachine/translations/cs.json @@ -4,9 +4,7 @@ "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" }, "error": { - "identifier_exists": "\u00da\u010det je ji\u017e nastaven", - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje" + "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { "user": { @@ -18,5 +16,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/da.json b/homeassistant/components/rainmachine/translations/da.json index a9b2fcedd2f..32d9819a34f 100644 --- a/homeassistant/components/rainmachine/translations/da.json +++ b/homeassistant/components/rainmachine/translations/da.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "Denne RainMachine-controller er allerede konfigureret." }, - "error": { - "identifier_exists": "Konto er allerede registreret", - "invalid_credentials": "Ugyldige legitimationsoplysninger" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/de.json b/homeassistant/components/rainmachine/translations/de.json index 35cd1d1bbf5..92df52bb148 100644 --- a/homeassistant/components/rainmachine/translations/de.json +++ b/homeassistant/components/rainmachine/translations/de.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "Dieser RainMachine-Kontroller ist bereits konfiguriert." }, - "error": { - "identifier_exists": "Konto bereits registriert", - "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen" - }, "step": { "user": { "data": { @@ -17,5 +13,12 @@ "title": "Informationen eingeben" } } + }, + "options": { + "step": { + "init": { + "title": "RainMachine konfigurieren" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/en.json b/homeassistant/components/rainmachine/translations/en.json index d734cbd5d38..f65463626e4 100644 --- a/homeassistant/components/rainmachine/translations/en.json +++ b/homeassistant/components/rainmachine/translations/en.json @@ -4,9 +4,7 @@ "already_configured": "Device is already configured" }, "error": { - "identifier_exists": "Account is already configured", - "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid credentials" + "invalid_auth": "Invalid authentication" }, "step": { "user": { @@ -18,5 +16,15 @@ "title": "Fill in your information" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Default zone run time (in seconds)" + }, + "title": "Configure RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/es-419.json b/homeassistant/components/rainmachine/translations/es-419.json index 0767c509bf9..0e3aa7e73e8 100644 --- a/homeassistant/components/rainmachine/translations/es-419.json +++ b/homeassistant/components/rainmachine/translations/es-419.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "Este controlador RainMachine ya est\u00e1 configurado." }, - "error": { - "identifier_exists": "Cuenta ya registrada", - "invalid_credentials": "Credenciales no v\u00e1lidas" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/es.json b/homeassistant/components/rainmachine/translations/es.json index fc27a8b3089..9562aa59928 100644 --- a/homeassistant/components/rainmachine/translations/es.json +++ b/homeassistant/components/rainmachine/translations/es.json @@ -4,9 +4,7 @@ "already_configured": "El dispositivo ya est\u00e1 configurado" }, "error": { - "identifier_exists": "La cuenta ya ha sido configurada", - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_credentials": "Credenciales no v\u00e1lidas" + "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { "user": { @@ -18,5 +16,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/et.json b/homeassistant/components/rainmachine/translations/et.json index 1b17200b762..e3eb3e60462 100644 --- a/homeassistant/components/rainmachine/translations/et.json +++ b/homeassistant/components/rainmachine/translations/et.json @@ -4,9 +4,7 @@ "already_configured": "Seade on juba h\u00e4\u00e4lestatud" }, "error": { - "identifier_exists": "Konto on juba seadistatud", - "invalid_auth": "Tuvastamise viga", - "invalid_credentials": "Sobimatu mandaat" + "invalid_auth": "Tuvastamise viga" }, "step": { "user": { @@ -14,7 +12,18 @@ "ip_address": "Hostinimi v\u00f5i IP-aadress", "password": "Salas\u00f5na", "port": "" - } + }, + "title": "Sisesta oma teave" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Vaiketsooni k\u00e4itamisaeg (sekundites)" + }, + "title": "Seadista RainMachine" } } } diff --git a/homeassistant/components/rainmachine/translations/fi.json b/homeassistant/components/rainmachine/translations/fi.json index 61c91d5e97d..a0d0d42fcab 100644 --- a/homeassistant/components/rainmachine/translations/fi.json +++ b/homeassistant/components/rainmachine/translations/fi.json @@ -1,9 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Tili on jo rekister\u00f6ity", - "invalid_credentials": "Virheelliset tunnistetiedot" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/fr.json b/homeassistant/components/rainmachine/translations/fr.json index 34c769faac7..02b7dbc2699 100644 --- a/homeassistant/components/rainmachine/translations/fr.json +++ b/homeassistant/components/rainmachine/translations/fr.json @@ -4,8 +4,7 @@ "already_configured": "Ce contr\u00f4leur RainMachine est d\u00e9j\u00e0 configur\u00e9." }, "error": { - "identifier_exists": "Compte d\u00e9j\u00e0 enregistr\u00e9", - "invalid_credentials": "Informations d'identification invalides" + "invalid_auth": "Authentification invalide" }, "step": { "user": { @@ -17,5 +16,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/hu.json b/homeassistant/components/rainmachine/translations/hu.json index 8f5b985bfe9..be68eed63e3 100644 --- a/homeassistant/components/rainmachine/translations/hu.json +++ b/homeassistant/components/rainmachine/translations/hu.json @@ -1,9 +1,5 @@ { "config": { - "error": { - "identifier_exists": "A fi\u00f3k m\u00e1r regisztr\u00e1lt", - "invalid_credentials": "\u00c9rv\u00e9nytelen hiteles\u00edt\u0151 adatok" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/it.json b/homeassistant/components/rainmachine/translations/it.json index 7850ea19c33..72e377dd95d 100644 --- a/homeassistant/components/rainmachine/translations/it.json +++ b/homeassistant/components/rainmachine/translations/it.json @@ -4,9 +4,7 @@ "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato" }, "error": { - "identifier_exists": "L'account \u00e8 gi\u00e0 configurato", - "invalid_auth": "Autenticazione non valida", - "invalid_credentials": "Credenziali non valide" + "invalid_auth": "Autenticazione non valida" }, "step": { "user": { @@ -18,5 +16,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/rainmachine/translations/ko.json b/homeassistant/components/rainmachine/translations/ko.json index 981849cee7b..e1c78ae8247 100644 --- a/homeassistant/components/rainmachine/translations/ko.json +++ b/homeassistant/components/rainmachine/translations/ko.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "\uc774 RainMachine \ucee8\ud2b8\ub864\ub7ec\ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, - "error": { - "identifier_exists": "\uacc4\uc815\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "invalid_credentials": "\ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/lb.json b/homeassistant/components/rainmachine/translations/lb.json index d0f41ddf3f9..2bceddafdb2 100644 --- a/homeassistant/components/rainmachine/translations/lb.json +++ b/homeassistant/components/rainmachine/translations/lb.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_configured": "D\u00ebse RainMachine Kontroller ass scho konfigur\u00e9iert." + "already_configured": "Apparat ass scho konfigur\u00e9iert." }, "error": { - "identifier_exists": "Konto ass scho registr\u00e9iert", - "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_credentials": "Ong\u00eblteg Login Informatioune" + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "user": { @@ -18,5 +16,12 @@ "title": "F\u00ebllt \u00e4r Informatiounen aus" } } + }, + "options": { + "step": { + "init": { + "title": "RainMachine konfigur\u00e9ieren" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/nl.json b/homeassistant/components/rainmachine/translations/nl.json index 3d13a48712b..adaa8cb5f30 100644 --- a/homeassistant/components/rainmachine/translations/nl.json +++ b/homeassistant/components/rainmachine/translations/nl.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "Deze RainMachine controller is al geconfigureerd." }, - "error": { - "identifier_exists": "Account bestaat al", - "invalid_credentials": "Ongeldige gebruikersgegevens" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/no.json b/homeassistant/components/rainmachine/translations/no.json index 164602862c5..214b50404a6 100644 --- a/homeassistant/components/rainmachine/translations/no.json +++ b/homeassistant/components/rainmachine/translations/no.json @@ -4,9 +4,7 @@ "already_configured": "Enheten er allerede konfigurert" }, "error": { - "identifier_exists": "Kontoen er allerede konfigurert", - "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig legitimasjon" + "invalid_auth": "Ugyldig godkjenning" }, "step": { "user": { @@ -18,5 +16,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 a1b7c01725e..ff8918660f8 100644 --- a/homeassistant/components/rainmachine/translations/pl.json +++ b/homeassistant/components/rainmachine/translations/pl.json @@ -4,9 +4,7 @@ "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" }, "error": { - "identifier_exists": "Konto jest ju\u017c skonfigurowane", - "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce" + "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { "user": { @@ -18,5 +16,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/pt-BR.json b/homeassistant/components/rainmachine/translations/pt-BR.json index 8b78ef25eb3..e876d367575 100644 --- a/homeassistant/components/rainmachine/translations/pt-BR.json +++ b/homeassistant/components/rainmachine/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Conta j\u00e1 cadastrada", - "invalid_credentials": "Credenciais inv\u00e1lidas" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/pt.json b/homeassistant/components/rainmachine/translations/pt.json index 3bd58fccc2f..e6c1baf1ca6 100644 --- a/homeassistant/components/rainmachine/translations/pt.json +++ b/homeassistant/components/rainmachine/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "error": { - "identifier_exists": "Conta j\u00e1 registada", - "invalid_credentials": "Credenciais inv\u00e1lidas" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/ru.json b/homeassistant/components/rainmachine/translations/ru.json index 3bb1a95f647..08ce690d22f 100644 --- a/homeassistant/components/rainmachine/translations/ru.json +++ b/homeassistant/components/rainmachine/translations/ru.json @@ -4,9 +4,7 @@ "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." }, "error": { - "identifier_exists": "\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_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { "user": { @@ -18,5 +16,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/sl.json b/homeassistant/components/rainmachine/translations/sl.json index e34b14b2a97..7527f5fce35 100644 --- a/homeassistant/components/rainmachine/translations/sl.json +++ b/homeassistant/components/rainmachine/translations/sl.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "Ta regulator RainMachine je \u017ee konfiguriran." }, - "error": { - "identifier_exists": "Ra\u010dun \u017ee registriran", - "invalid_credentials": "Neveljavne poverilnice" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/sv.json b/homeassistant/components/rainmachine/translations/sv.json index a41d65fd09f..5077b9bb967 100644 --- a/homeassistant/components/rainmachine/translations/sv.json +++ b/homeassistant/components/rainmachine/translations/sv.json @@ -3,10 +3,6 @@ "abort": { "already_configured": "Denna RainMachine-enhet \u00e4r redan konfigurerad" }, - "error": { - "identifier_exists": "Kontot \u00e4r redan registrerat", - "invalid_credentials": "Ogiltiga autentiseringsuppgifter" - }, "step": { "user": { "data": { @@ -17,5 +13,12 @@ "title": "Fyll i dina uppgifter" } } + }, + "options": { + "step": { + "init": { + "title": "Konfigurera RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/tr.json b/homeassistant/components/rainmachine/translations/tr.json new file mode 100644 index 00000000000..20f74cae994 --- /dev/null +++ b/homeassistant/components/rainmachine/translations/tr.json @@ -0,0 +1,12 @@ +{ + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Varsay\u0131lan b\u00f6lge \u00e7al\u0131\u015fma s\u00fcresi (saniye cinsinden)" + }, + "title": "RainMachine'i konf\u0131g\u00fcre et" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/zh-Hans.json b/homeassistant/components/rainmachine/translations/zh-Hans.json index e7171ca2867..68f84441d29 100644 --- a/homeassistant/components/rainmachine/translations/zh-Hans.json +++ b/homeassistant/components/rainmachine/translations/zh-Hans.json @@ -1,9 +1,5 @@ { "config": { - "error": { - "identifier_exists": "\u8d26\u6237\u5df2\u6ce8\u518c", - "invalid_credentials": "\u65e0\u6548\u7684\u8eab\u4efd\u8ba4\u8bc1" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/rainmachine/translations/zh-Hant.json b/homeassistant/components/rainmachine/translations/zh-Hant.json index bb4184b078b..cefc44956c7 100644 --- a/homeassistant/components/rainmachine/translations/zh-Hant.json +++ b/homeassistant/components/rainmachine/translations/zh-Hant.json @@ -4,9 +4,7 @@ "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "identifier_exists": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u6191\u8b49\u7121\u6548" + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { "user": { @@ -18,5 +16,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/recollect_waste/manifest.json b/homeassistant/components/recollect_waste/manifest.json index b04917d450c..bed07f919ef 100644 --- a/homeassistant/components/recollect_waste/manifest.json +++ b/homeassistant/components/recollect_waste/manifest.json @@ -2,6 +2,6 @@ "domain": "recollect_waste", "name": "ReCollect Waste", "documentation": "https://www.home-assistant.io/integrations/recollect_waste", - "requirements": ["recollect-waste==1.0.1"], + "requirements": ["aiorecollect==0.2.1"], "codeowners": [] } diff --git a/homeassistant/components/recollect_waste/sensor.py b/homeassistant/components/recollect_waste/sensor.py index bc1ace5369f..d360ff8f301 100644 --- a/homeassistant/components/recollect_waste/sensor.py +++ b/homeassistant/components/recollect_waste/sensor.py @@ -1,18 +1,21 @@ """Support for Recollect Waste curbside collection pickup.""" -from datetime import timedelta +from datetime import date, timedelta import logging -import recollect_waste +from aiorecollect import Client +from aiorecollect.errors import RecollectError import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import CONF_NAME -import homeassistant.helpers.config_validation as cv +from homeassistant.helpers import aiohttp_client, config_validation as cv from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) ATTR_PICKUP_TYPES = "pickup_types" ATTR_AREA_NAME = "area_name" +ATTR_NEXT_PICKUP_TYPES = "next_pickup_types" +ATTR_NEXT_PICKUP_DATE = "next_pickup_date" CONF_PLACE_ID = "place_id" CONF_SERVICE_ID = "service_id" DEFAULT_NAME = "recollect_waste" @@ -29,21 +32,20 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Recollect Waste platform.""" - client = recollect_waste.RecollectWasteClient( - config[CONF_PLACE_ID], config[CONF_SERVICE_ID] - ) + session = aiohttp_client.async_get_clientsession(hass) + client = Client(config[CONF_PLACE_ID], config[CONF_SERVICE_ID], session=session) # Ensure the client can connect to the API successfully # with given place_id and service_id. try: - client.get_next_pickup() - except recollect_waste.RecollectWasteException as ex: - _LOGGER.error("Recollect Waste platform error. %s", ex) + await client.async_get_next_pickup_event() + except RecollectError as err: + _LOGGER.error("Error setting up Recollect sensor platform: %s", err) return - add_entities([RecollectWasteSensor(config.get(CONF_NAME), client)], True) + async_add_entities([RecollectWasteSensor(config.get(CONF_NAME), client)], True) class RecollectWasteSensor(Entity): @@ -81,16 +83,25 @@ class RecollectWasteSensor(Entity): """Icon to use in the frontend.""" return ICON - def update(self): + async def async_update(self): """Update device state.""" try: - pickup_event = self.client.get_next_pickup() - self._state = pickup_event.event_date - self._attributes.update( - { - ATTR_PICKUP_TYPES: pickup_event.pickup_types, - ATTR_AREA_NAME: pickup_event.area_name, - } + pickup_event_array = await self.client.async_get_pickup_events( + start_date=date.today(), end_date=date.today() + timedelta(weeks=4) ) - except recollect_waste.RecollectWasteException as ex: - _LOGGER.error("Recollect Waste platform error. %s", ex) + except RecollectError as err: + _LOGGER.error("Error while requesting data from Recollect: %s", err) + return + + pickup_event = pickup_event_array[0] + next_pickup_event = pickup_event_array[1] + next_date = str(next_pickup_event.date) + self._state = pickup_event.date + self._attributes.update( + { + ATTR_PICKUP_TYPES: pickup_event.pickup_types, + ATTR_AREA_NAME: pickup_event.area_name, + ATTR_NEXT_PICKUP_TYPES: next_pickup_event.pickup_types, + ATTR_NEXT_PICKUP_DATE: next_date, + } + ) diff --git a/homeassistant/components/recollect_waste/translations/ca.json b/homeassistant/components/recollect_waste/translations/ca.json new file mode 100644 index 00000000000..395fe5b9daa --- /dev/null +++ b/homeassistant/components/recollect_waste/translations/ca.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "already_configured": "El dispositiu ja est\u00e0 configurat" + }, + "error": { + "invalid_place_or_service_id": "ID de lloc o de servei inv\u00e0lid" + }, + "step": { + "user": { + "data": { + "place_id": "ID de lloc", + "service_id": "ID de servei" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/recollect_waste/translations/cs.json b/homeassistant/components/recollect_waste/translations/cs.json new file mode 100644 index 00000000000..57bdeaa80da --- /dev/null +++ b/homeassistant/components/recollect_waste/translations/cs.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" + }, + "error": { + "invalid_place_or_service_id": "Neplatn\u00e9 m\u00edsto nebo ID slu\u017eby" + }, + "step": { + "user": { + "data": { + "place_id": "ID m\u00edsta", + "service_id": "ID slu\u017eby" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/recollect_waste/translations/es.json b/homeassistant/components/recollect_waste/translations/es.json new file mode 100644 index 00000000000..5771c9da9a9 --- /dev/null +++ b/homeassistant/components/recollect_waste/translations/es.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "already_configured": "El dispositivo ya est\u00e1 configurado" + }, + "error": { + "invalid_place_or_service_id": "ID de servicio o lugar no v\u00e1lidos" + }, + "step": { + "user": { + "data": { + "place_id": "ID de lugar", + "service_id": "ID de servicio" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/recollect_waste/translations/et.json b/homeassistant/components/recollect_waste/translations/et.json new file mode 100644 index 00000000000..e1402d12e42 --- /dev/null +++ b/homeassistant/components/recollect_waste/translations/et.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "already_configured": "Seade on juba h\u00e4\u00e4lestatud" + }, + "error": { + "invalid_place_or_service_id": "Sobimatu asukoha v\u00f5i teenuse ID" + }, + "step": { + "user": { + "data": { + "place_id": "Asukoha ID", + "service_id": "Teenuse ID" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/recollect_waste/translations/no.json b/homeassistant/components/recollect_waste/translations/no.json new file mode 100644 index 00000000000..6c4932505ba --- /dev/null +++ b/homeassistant/components/recollect_waste/translations/no.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "already_configured": "Enheten er allerede konfigurert" + }, + "error": { + "invalid_place_or_service_id": "Ugyldig sted eller tjeneste ID" + }, + "step": { + "user": { + "data": { + "place_id": "Sted ID", + "service_id": "Tjeneste ID" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/recollect_waste/translations/pl.json b/homeassistant/components/recollect_waste/translations/pl.json new file mode 100644 index 00000000000..013d0028790 --- /dev/null +++ b/homeassistant/components/recollect_waste/translations/pl.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" + }, + "error": { + "invalid_place_or_service_id": "Nieprawid\u0142owy identyfikator \"Place\" lub \"Service\"" + }, + "step": { + "user": { + "data": { + "place_id": "Identyfikator \"Place\" (place_id)", + "service_id": "Identyfikator \"Service\" (service_id)" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/recollect_waste/translations/ru.json b/homeassistant/components/recollect_waste/translations/ru.json new file mode 100644 index 00000000000..21e926ec9e1 --- /dev/null +++ b/homeassistant/components/recollect_waste/translations/ru.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." + }, + "error": { + "invalid_place_or_service_id": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 ID \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0441\u043b\u0443\u0436\u0431\u044b." + }, + "step": { + "user": { + "data": { + "place_id": "ID \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f", + "service_id": "ID \u0441\u043b\u0443\u0436\u0431\u044b" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/remote/translations/pl.json b/homeassistant/components/remote/translations/pl.json index 3c319ff548c..109c30fc2bb 100644 --- a/homeassistant/components/remote/translations/pl.json +++ b/homeassistant/components/remote/translations/pl.json @@ -1,17 +1,17 @@ { "device_automation": { "action_type": { - "toggle": "Prze\u0142\u0105cz {entity_name}", + "toggle": "prze\u0142\u0105cz {entity_name}", "turn_off": "wy\u0142\u0105cz {entity_name}", "turn_on": "w\u0142\u0105cz {entity_name}" }, "condition_type": { - "is_off": "{entity_name} jest wy\u0142\u0105czony", - "is_on": "{entity_name} jest w\u0142\u0105czony" + "is_off": "pilot {entity_name} jest wy\u0142\u0105czony", + "is_on": "pilot {entity_name} jest w\u0142\u0105czony" }, "trigger_type": { - "turned_off": "{entity_name} wy\u0142\u0105czy si\u0119", - "turned_on": "{entity_name} w\u0142\u0105czy si\u0119" + "turned_off": "nast\u0105pi wy\u0142\u0105czenie {entity_name}", + "turned_on": "nast\u0105pi w\u0142\u0105czenie {entity_name}" } }, "state": { diff --git a/homeassistant/components/rfxtrx/__init__.py b/homeassistant/components/rfxtrx/__init__.py index 5f8d14710e3..9eaa705bf3e 100644 --- a/homeassistant/components/rfxtrx/__init__.py +++ b/homeassistant/components/rfxtrx/__init__.py @@ -27,16 +27,15 @@ from homeassistant.const import ( LENGTH_MILLIMETERS, PERCENTAGE, POWER_WATT, + PRECIPITATION_MILLIMETERS_PER_HOUR, PRESSURE_HPA, SIGNAL_STRENGTH_DECIBELS_MILLIWATT, SPEED_METERS_PER_SECOND, TEMP_CELSIUS, - TIME_HOURS, UV_INDEX, VOLT, ) from homeassistant.core import callback -from homeassistant.exceptions import ConfigEntryNotReady import homeassistant.helpers.config_validation as cv from homeassistant.helpers.restore_state import RestoreEntity @@ -70,7 +69,7 @@ DATA_TYPES = OrderedDict( ("Humidity", PERCENTAGE), ("Barometer", PRESSURE_HPA), ("Wind direction", DEGREE), - ("Rain rate", f"{LENGTH_MILLIMETERS}/{TIME_HOURS}"), + ("Rain rate", PRECIPITATION_MILLIMETERS_PER_HOUR), ("Energy usage", POWER_WATT), ("Total usage", ENERGY_KILO_WATT_HOUR), ("Sound", None), @@ -191,7 +190,14 @@ async def async_setup_entry(hass, entry: config_entries.ConfigEntry): hass.data[DOMAIN][DATA_CLEANUP_CALLBACKS] = [] - await async_setup_internal(hass, entry) + try: + await async_setup_internal(hass, entry) + except asyncio.TimeoutError: + # Library currently doesn't support reload + _LOGGER.error( + "Connection timeout: failed to receive response from RFXtrx device" + ) + return False for domain in DOMAINS: hass.async_create_task( @@ -263,11 +269,8 @@ async def async_setup_internal(hass, entry: config_entries.ConfigEntry): config = entry.data # Initialize library - try: - async with async_timeout.timeout(5): - rfx_object = await hass.async_add_executor_job(_create_rfx, config) - except asyncio.TimeoutError as err: - raise ConfigEntryNotReady from err + async with async_timeout.timeout(30): + rfx_object = await hass.async_add_executor_job(_create_rfx, config) # Setup some per device config devices = _get_device_lookup(config[CONF_DEVICES]) diff --git a/homeassistant/components/rfxtrx/strings.json b/homeassistant/components/rfxtrx/strings.json index 9e976999157..574cff29ba1 100644 --- a/homeassistant/components/rfxtrx/strings.json +++ b/homeassistant/components/rfxtrx/strings.json @@ -1,5 +1,4 @@ { - "title": "Rfxtrx", "config": { "abort": { "already_configured": "[%key:common::config_flow::abort::single_instance_allowed%]", diff --git a/homeassistant/components/rfxtrx/translations/ca.json b/homeassistant/components/rfxtrx/translations/ca.json index 5861878e079..6c4e920df02 100644 --- a/homeassistant/components/rfxtrx/translations/ca.json +++ b/homeassistant/components/rfxtrx/translations/ca.json @@ -69,6 +69,5 @@ "title": "Configuraci\u00f3 de les opcions del dispositiu" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/cs.json b/homeassistant/components/rfxtrx/translations/cs.json index 64073787db5..706d4499fb2 100644 --- a/homeassistant/components/rfxtrx/translations/cs.json +++ b/homeassistant/components/rfxtrx/translations/cs.json @@ -41,6 +41,7 @@ "invalid_event_code": "Neplatn\u00fd k\u00f3d ud\u00e1losti", "invalid_input_2262_off": "Neplatn\u00fd vstup pro vyp\u00ednac\u00ed p\u0159\u00edkaz", "invalid_input_2262_on": "Neplatn\u00fd vstup pro zap\u00ednac\u00ed p\u0159\u00edkaz", + "invalid_input_off_delay": "Neplatn\u00e1 hodnota pro zpo\u017ed\u011bn\u00ed vypnut\u00ed", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { @@ -49,17 +50,21 @@ "automatic_add": "Povolit automatick\u00e9 p\u0159id\u00e1n\u00ed", "debug": "Povolit lad\u011bn\u00ed", "device": "Vyberte za\u0159\u00edzen\u00ed, kter\u00e9 chcete nastavit", + "event_code": "Zadejte k\u00f3d ud\u00e1losti, kterou chcete p\u0159idat", "remove_device": "Vyberte za\u0159\u00edzen\u00ed, kter\u00e9 chcete odstranit" }, "title": "Mo\u017enosti Rfxtrx" }, "set_device_options": { "data": { - "replace_device": "Vyberte za\u0159\u00edzen\u00ed, kter\u00e9 chcete vym\u011bnit" + "fire_event": "Povolit ud\u00e1lost za\u0159\u00edzen\u00ed", + "off_delay": "Zpo\u017ed\u011bn\u00ed vypnut\u00ed", + "off_delay_enabled": "Povolit zpo\u017ed\u011bn\u00ed vypnut\u00ed", + "replace_device": "Vyberte za\u0159\u00edzen\u00ed, kter\u00e9 chcete vym\u011bnit", + "signal_repetitions": "Po\u010det opakov\u00e1n\u00ed sign\u00e1lu" }, "title": "Nastaven\u00ed mo\u017enost\u00ed za\u0159\u00edzen\u00ed" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/de.json b/homeassistant/components/rfxtrx/translations/de.json index c4b378db213..6d934ed0e60 100644 --- a/homeassistant/components/rfxtrx/translations/de.json +++ b/homeassistant/components/rfxtrx/translations/de.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Ger\u00e4t ist bereits konfiguriert" + "already_configured": "Ger\u00e4t ist bereits konfiguriert. Nur eine Konfiguration m\u00f6glich." }, "step": { "setup_network": { diff --git a/homeassistant/components/rfxtrx/translations/el.json b/homeassistant/components/rfxtrx/translations/el.json index fcf3a9ec83b..1ad4a767b32 100644 --- a/homeassistant/components/rfxtrx/translations/el.json +++ b/homeassistant/components/rfxtrx/translations/el.json @@ -62,6 +62,5 @@ "title": "\u03a1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03c0\u03b1\u03c1\u03b1\u03bc\u03ad\u03c4\u03c1\u03c9\u03bd \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ce\u03bd \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae\u03c2" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/en.json b/homeassistant/components/rfxtrx/translations/en.json index 5bc019699b7..3f8fcf12702 100644 --- a/homeassistant/components/rfxtrx/translations/en.json +++ b/homeassistant/components/rfxtrx/translations/en.json @@ -69,6 +69,5 @@ "title": "Configure device options" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/es.json b/homeassistant/components/rfxtrx/translations/es.json index f150e74802a..86bad8f096f 100644 --- a/homeassistant/components/rfxtrx/translations/es.json +++ b/homeassistant/components/rfxtrx/translations/es.json @@ -69,6 +69,5 @@ "title": "Configurar las opciones del dispositivo" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/et.json b/homeassistant/components/rfxtrx/translations/et.json index 03a066c6cdc..1ade1f112c2 100644 --- a/homeassistant/components/rfxtrx/translations/et.json +++ b/homeassistant/components/rfxtrx/translations/et.json @@ -69,6 +69,5 @@ "title": "Seadista seadme valikud" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/fr.json b/homeassistant/components/rfxtrx/translations/fr.json index 5155bf6dacf..baf8d0f5148 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,17 +39,35 @@ "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" }, "title": "Configurer les options de l'appareil" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/it.json b/homeassistant/components/rfxtrx/translations/it.json index 678047af145..a97cfdd2ce4 100644 --- a/homeassistant/components/rfxtrx/translations/it.json +++ b/homeassistant/components/rfxtrx/translations/it.json @@ -75,6 +75,5 @@ } } }, - "other": "altri", - "title": "Rfxtrx" + "other": "altri" } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/lb.json b/homeassistant/components/rfxtrx/translations/lb.json index 6e9b0fcb9c0..f5441eeb298 100644 --- a/homeassistant/components/rfxtrx/translations/lb.json +++ b/homeassistant/components/rfxtrx/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Apparat ass scho konfigur\u00e9iert", + "already_configured": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech.", "cannot_connect": "Feeler beim verbannen" }, "error": { @@ -34,10 +34,12 @@ }, "options": { "error": { + "already_configured_device": "Apparat ass scho konfigur\u00e9iert", "invalid_event_code": "Ong\u00ebltegen Evenement Code", "invalid_input_2262_off": "Ong\u00eblteg Agab fir Kommando Aus", "invalid_input_2262_on": "Ong\u00eblteg Agab fir Kommando Un", - "invalid_input_off_delay": "Ong\u00eblteg Agab fir Aus Verz\u00f6gerung" + "invalid_input_off_delay": "Ong\u00eblteg Agab fir Aus Verz\u00f6gerung", + "unknown": "Onerwaarte Feeler" }, "step": { "prompt_options": { @@ -64,6 +66,5 @@ "title": "Apparat Optioune konfigur\u00e9ieren" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/nl.json b/homeassistant/components/rfxtrx/translations/nl.json index 76e26d514b5..0dc56206f66 100644 --- a/homeassistant/components/rfxtrx/translations/nl.json +++ b/homeassistant/components/rfxtrx/translations/nl.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "already_configured": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." + "already_configured": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk.", + "cannot_connect": "Kon niet verbinden" }, "error": { "cannot_connect": "Kan geen verbinding maken" @@ -10,8 +11,21 @@ "setup_network": { "data": { "port": "Poort" - } + }, + "title": "Selecteer verbindingsadres" + }, + "user": { + "data": { + "type": "Verbindingstype" + }, + "title": "Selecteer verbindingstype" } } + }, + "options": { + "error": { + "already_configured_device": "Apparaat is al geconfigureerd", + "unknown": "Onverwachte fout" + } } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/no.json b/homeassistant/components/rfxtrx/translations/no.json index 369bd2381ec..33233840720 100644 --- a/homeassistant/components/rfxtrx/translations/no.json +++ b/homeassistant/components/rfxtrx/translations/no.json @@ -53,7 +53,7 @@ "event_code": "Angi hendelseskode for \u00e5 legge til", "remove_device": "Velg enhet du vil slette" }, - "title": "[VOID] alternativer" + "title": "[%key:component::rfxtrx::title%] alternativer" }, "set_device_options": { "data": { @@ -69,6 +69,5 @@ "title": "Konfigurer enhetsalternativer" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/pl.json b/homeassistant/components/rfxtrx/translations/pl.json index 56304959145..bf17d6c5166 100644 --- a/homeassistant/components/rfxtrx/translations/pl.json +++ b/homeassistant/components/rfxtrx/translations/pl.json @@ -21,7 +21,7 @@ "host": "Nazwa hosta lub adres IP", "port": "Port" }, - "title": "Wybierz adres po\u0142\u0105czenia" + "title": "Wybierz adres dla po\u0142\u0105czenia" }, "setup_serial": { "data": { @@ -81,6 +81,5 @@ } } }, - "other": "inne", - "title": "Rfxtrx" + "other": "inne" } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/ru.json b/homeassistant/components/rfxtrx/translations/ru.json index 0926734657d..361b051ac2c 100644 --- a/homeassistant/components/rfxtrx/translations/ru.json +++ b/homeassistant/components/rfxtrx/translations/ru.json @@ -69,6 +69,5 @@ "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/zh-Hant.json b/homeassistant/components/rfxtrx/translations/zh-Hant.json index dac2a6850b0..827def7f302 100644 --- a/homeassistant/components/rfxtrx/translations/zh-Hant.json +++ b/homeassistant/components/rfxtrx/translations/zh-Hant.json @@ -69,6 +69,5 @@ "title": "\u8a2d\u5b9a\u8a2d\u5099\u9078\u9805" } } - }, - "title": "Rfxtrx" + } } \ No newline at end of file diff --git a/homeassistant/components/ring/translations/et.json b/homeassistant/components/ring/translations/et.json index faf6035290e..cca3632c741 100644 --- a/homeassistant/components/ring/translations/et.json +++ b/homeassistant/components/ring/translations/et.json @@ -8,11 +8,18 @@ "unknown": "Ootamatu t\u00f5rge" }, "step": { + "2fa": { + "data": { + "2fa": "Kaheastmeline autentimiskood" + }, + "title": "Kaheastmeline tuvastamine (2FA)" + }, "user": { "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "Logi sisse Ringi kontoga" } } } diff --git a/homeassistant/components/risco/binary_sensor.py b/homeassistant/components/risco/binary_sensor.py index 757a30252c2..ba01b70686b 100644 --- a/homeassistant/components/risco/binary_sensor.py +++ b/homeassistant/components/risco/binary_sensor.py @@ -6,7 +6,7 @@ from homeassistant.components.binary_sensor import ( from homeassistant.helpers import entity_platform from .const import DATA_COORDINATOR, DOMAIN -from .entity import RiscoEntity +from .entity import RiscoEntity, binary_sensor_unique_id SERVICE_BYPASS_ZONE = "bypass_zone" SERVICE_UNBYPASS_ZONE = "unbypass_zone" @@ -25,7 +25,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities): RiscoBinarySensor(coordinator, zone_id, zone) for zone_id, zone in coordinator.data.zones.items() ] - async_add_entities(entities, False) @@ -58,12 +57,12 @@ class RiscoBinarySensor(BinarySensorEntity, RiscoEntity): @property def unique_id(self): """Return a unique id for this zone.""" - return f"{self._risco.site_uuid}_zone_{self._zone_id}" + return binary_sensor_unique_id(self._risco, self._zone_id) @property def device_state_attributes(self): """Return the state attributes.""" - return {"bypassed": self._zone.bypassed} + return {"zone_id": self._zone_id, "bypassed": self._zone.bypassed} @property def is_on(self): diff --git a/homeassistant/components/risco/entity.py b/homeassistant/components/risco/entity.py index 17e27caf18b..04b521156b1 100644 --- a/homeassistant/components/risco/entity.py +++ b/homeassistant/components/risco/entity.py @@ -2,6 +2,11 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity +def binary_sensor_unique_id(risco, zone_id): + """Return unique id for the binary sensor.""" + return f"{risco.site_uuid}_zone_{zone_id}" + + class RiscoEntity(CoordinatorEntity): """Risco entity base class.""" diff --git a/homeassistant/components/risco/sensor.py b/homeassistant/components/risco/sensor.py index 3b4ee882b3c..62ef6643551 100644 --- a/homeassistant/components/risco/sensor.py +++ b/homeassistant/components/risco/sensor.py @@ -1,8 +1,10 @@ """Sensor for Risco Events.""" +from homeassistant.components.binary_sensor import DOMAIN as BS_DOMAIN from homeassistant.const import DEVICE_CLASS_TIMESTAMP from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN, EVENTS_COORDINATOR +from .entity import binary_sensor_unique_id CATEGORIES = { 2: "Alarm", @@ -29,22 +31,29 @@ async def async_setup_entry(hass, config_entry, async_add_entities): """Set up sensors for device.""" coordinator = hass.data[DOMAIN][config_entry.entry_id][EVENTS_COORDINATOR] sensors = [ - RiscoSensor(coordinator, id, [], name) for id, name in CATEGORIES.items() + RiscoSensor(coordinator, id, [], name, config_entry.entry_id) + for id, name in CATEGORIES.items() ] - sensors.append(RiscoSensor(coordinator, None, CATEGORIES.keys(), "Other")) + sensors.append( + RiscoSensor( + coordinator, None, CATEGORIES.keys(), "Other", config_entry.entry_id + ) + ) async_add_entities(sensors) class RiscoSensor(CoordinatorEntity): """Sensor for Risco events.""" - def __init__(self, coordinator, category_id, excludes, name) -> None: + def __init__(self, coordinator, category_id, excludes, name, entry_id) -> None: """Initialize sensor.""" super().__init__(coordinator) self._event = None self._category_id = category_id self._excludes = excludes self._name = name + self._entry_id = entry_id + self._entity_registry = None @property def name(self): @@ -58,6 +67,9 @@ class RiscoSensor(CoordinatorEntity): async def async_added_to_hass(self): """When entity is added to hass.""" + self._entity_registry = ( + await self.hass.helpers.entity_registry.async_get_registry() + ) self.async_on_remove( self.coordinator.async_add_listener(self._refresh_from_coordinator) ) @@ -88,7 +100,18 @@ class RiscoSensor(CoordinatorEntity): if self._event is None: return None - return {atr: getattr(self._event, atr, None) for atr in EVENT_ATTRIBUTES} + attrs = {atr: getattr(self._event, atr, None) for atr in EVENT_ATTRIBUTES} + if self._event.zone_id is not None: + zone_unique_id = binary_sensor_unique_id( + self.coordinator.risco, self._event.zone_id + ) + zone_entity_id = self._entity_registry.async_get_entity_id( + BS_DOMAIN, DOMAIN, zone_unique_id + ) + if zone_entity_id is not None: + attrs["zone_entity_id"] = zone_entity_id + + return attrs @property def device_class(self): diff --git a/homeassistant/components/risco/translations/de.json b/homeassistant/components/risco/translations/de.json index b0bae40bf4e..a2c942db57f 100644 --- a/homeassistant/components/risco/translations/de.json +++ b/homeassistant/components/risco/translations/de.json @@ -4,6 +4,7 @@ "user": { "data": { "password": "Passwort", + "pin": "PIN Code", "username": "Benutzername" } } diff --git a/homeassistant/components/risco/translations/et.json b/homeassistant/components/risco/translations/et.json index d94cc2d4300..9bd35ec22db 100644 --- a/homeassistant/components/risco/translations/et.json +++ b/homeassistant/components/risco/translations/et.json @@ -23,14 +23,32 @@ "ha_to_risco": { "data": { "armed_away": "Valves eemal", + "armed_custom_bypass": "Valves, eranditega", "armed_home": "Valves kodus", "armed_night": "Valves \u00f6ine" - } + }, + "description": "Valige millisesse olekusse l\u00fcltub Risco alarm kui valvestada Home Assistant", + "title": "Lisa Risco olekud Home Assistanti olekutesse" }, "init": { "data": { - "code_arm_required": "N\u00f5ua valvestamiseks PIN koodi" - } + "code_arm_required": "N\u00f5ua valvestamiseks PIN koodi", + "code_disarm_required": "N\u00f5ua valve mahav\u00f5tmiseks PIN koodi", + "scan_interval": "Kui tihti k\u00fcsitleda Riscot (sekundites)" + }, + "title": "Seadista valikud" + }, + "risco_to_ha": { + "data": { + "A": "Grupp A", + "B": "Grupp B", + "C": "Grupp C", + "D": "Grupp D", + "arm": "Valvestatud (AWAY)", + "partial_arm": "Osaliselt valvestatud (STAY)" + }, + "description": "Vali millises oleku Home Assistant saab iga Risco olekumuutuse korral", + "title": "Lisa Risco olekud Home Assistanti olekutesse" } } } diff --git a/homeassistant/components/risco/translations/nl.json b/homeassistant/components/risco/translations/nl.json index 875adfeb756..34bcb4ab98a 100644 --- a/homeassistant/components/risco/translations/nl.json +++ b/homeassistant/components/risco/translations/nl.json @@ -3,6 +3,11 @@ "abort": { "already_configured": "Apparaat is al geconfigureerd" }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { diff --git a/homeassistant/components/roku/__init__.py b/homeassistant/components/roku/__init__.py index 663823d71b4..739e345a637 100644 --- a/homeassistant/components/roku/__init__.py +++ b/homeassistant/components/roku/__init__.py @@ -6,11 +6,10 @@ from typing import Any, Dict 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 @@ from .const import ( 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 @@ _LOGGER = logging.getLogger(__name__) 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/browse_media.py b/homeassistant/components/roku/browse_media.py index b5be3e99d9a..8110174450e 100644 --- a/homeassistant/components/roku/browse_media.py +++ b/homeassistant/components/roku/browse_media.py @@ -34,7 +34,7 @@ EXPANDABLE_MEDIA_TYPES = [ ] -def build_item_response(coordinator, payload): +def build_item_response(coordinator, payload, get_thumbnail_url=None): """Create response payload for the provided media query.""" search_id = payload["search_id"] search_type = payload["search_type"] @@ -75,13 +75,13 @@ def build_item_response(coordinator, payload): title=title, can_play=search_type in PLAYABLE_MEDIA_TYPES and search_id, can_expand=True, - children=[item_payload(item, coordinator) for item in media], + children=[item_payload(item, coordinator, get_thumbnail_url) for item in media], children_media_class=children_media_class, thumbnail=thumbnail, ) -def item_payload(item, coordinator): +def item_payload(item, coordinator, get_thumbnail_url=None): """ Create response payload for a single media item. @@ -92,7 +92,8 @@ def item_payload(item, coordinator): if "app_id" in item: media_content_type = MEDIA_TYPE_APP media_content_id = item["app_id"] - thumbnail = coordinator.roku.app_icon_url(item["app_id"]) + if get_thumbnail_url: + thumbnail = get_thumbnail_url(media_content_type, media_content_id) elif "channel_number" in item: media_content_type = MEDIA_TYPE_CHANNEL media_content_id = item["channel_number"] @@ -115,7 +116,7 @@ def item_payload(item, coordinator): ) -def library_payload(coordinator): +def library_payload(coordinator, get_thumbnail_url=None): """ Create response payload to describe contents of a specific library. @@ -147,6 +148,7 @@ def library_payload(coordinator): item_payload( {"title": item["title"], "type": item["type"]}, coordinator, + get_thumbnail_url, ) ) diff --git a/homeassistant/components/roku/config_flow.py b/homeassistant/components/roku/config_flow.py index 662e22605c8..6e494ce2692 100644 --- a/homeassistant/components/roku/config_flow.py +++ b/homeassistant/components/roku/config_flow.py @@ -61,12 +61,6 @@ class RokuConfigFlow(ConfigFlow, domain=DOMAIN): 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/homeassistant/components/roku/media_player.py b/homeassistant/components/roku/media_player.py index 0e035106824..e1662972cf6 100644 --- a/homeassistant/components/roku/media_player.py +++ b/homeassistant/components/roku/media_player.py @@ -238,16 +238,30 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity): """Emulate opening the search screen and entering the search keyword.""" await self.coordinator.roku.search(keyword) + async def async_get_browse_image( + self, media_content_type, media_content_id, media_image_id=None + ): + """Fetch media browser image to serve via proxy.""" + if media_content_type == MEDIA_TYPE_APP and media_content_id: + image_url = self.coordinator.roku.app_icon_url(media_content_id) + return await self._async_fetch_image(image_url) + + return (None, None) + async def async_browse_media(self, media_content_type=None, media_content_id=None): """Implement the websocket media browsing helper.""" + + def _get_thumbnail_url(*args, **kwargs): + return self.get_browse_image_url(*args, **kwargs) + if media_content_type in [None, "library"]: - return library_payload(self.coordinator) + return library_payload(self.coordinator, _get_thumbnail_url) payload = { "search_type": media_content_type, "search_id": media_content_id, } - response = build_item_response(self.coordinator, payload) + response = build_item_response(self.coordinator, payload, _get_thumbnail_url) if response is None: raise BrowseError( diff --git a/homeassistant/components/roku/translations/et.json b/homeassistant/components/roku/translations/et.json index 7a67f4ac3c4..e4869d044c8 100644 --- a/homeassistant/components/roku/translations/et.json +++ b/homeassistant/components/roku/translations/et.json @@ -7,6 +7,7 @@ "error": { "cannot_connect": "\u00dchendamine nurjus" }, + "flow_title": "", "step": { "ssdp_confirm": { "description": "Kas soovid seadistada {name}?", @@ -15,7 +16,8 @@ "user": { "data": { "host": "" - } + }, + "description": "Sisesta oma Roku teave." } } } diff --git a/homeassistant/components/roku/translations/nl.json b/homeassistant/components/roku/translations/nl.json index 1d793df1bf4..6b0927178fe 100644 --- a/homeassistant/components/roku/translations/nl.json +++ b/homeassistant/components/roku/translations/nl.json @@ -10,6 +10,10 @@ "flow_title": "Roku: {name}", "step": { "ssdp_confirm": { + "data": { + "one": "Leeg", + "other": "Leeg" + }, "description": "Wilt u {name} instellen?", "title": "Roku" }, diff --git a/homeassistant/components/roomba/manifest.json b/homeassistant/components/roomba/manifest.json index 3d710467b58..9b0e3f21983 100644 --- a/homeassistant/components/roomba/manifest.json +++ b/homeassistant/components/roomba/manifest.json @@ -4,6 +4,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/roomba", "requirements": ["roombapy==1.6.1"], - "dependencies": [], "codeowners": ["@pschmitt", "@cyr-ius", "@shenxn"] } diff --git a/homeassistant/components/roomba/translations/et.json b/homeassistant/components/roomba/translations/et.json index cca6ecc05ec..92da58fa146 100644 --- a/homeassistant/components/roomba/translations/et.json +++ b/homeassistant/components/roomba/translations/et.json @@ -6,8 +6,23 @@ "step": { "user": { "data": { + "blid": "", + "continuous": "Pidev", + "delay": "Viivitus", "host": "", "password": "Salas\u00f5na" + }, + "description": "Praegu on BLID ja parooli toomine k\u00e4sitsi protsess. J\u00e4rgi dokumentatsioonis toodud juhiseid aadressil: https://www.home-assistant.io/integrations/roomba/#retrieving-your-credentials", + "title": "\u00dchendu seadmega" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "continuous": "Pidev", + "delay": "Viivitus" } } } diff --git a/homeassistant/components/roomba/translations/lb.json b/homeassistant/components/roomba/translations/lb.json index 9b811774f6e..d3fc631f5df 100644 --- a/homeassistant/components/roomba/translations/lb.json +++ b/homeassistant/components/roomba/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol." + "cannot_connect": "Feeler beim verbannen" }, "step": { "user": { diff --git a/homeassistant/components/roon/config_flow.py b/homeassistant/components/roon/config_flow.py index 7fac3186c03..f8af2bac0e6 100644 --- a/homeassistant/components/roon/config_flow.py +++ b/homeassistant/components/roon/config_flow.py @@ -2,7 +2,7 @@ import asyncio import logging -from roon import RoonApi +from roonapi import RoonApi import voluptuous as vol from homeassistant import config_entries, core, exceptions diff --git a/homeassistant/components/roon/manifest.json b/homeassistant/components/roon/manifest.json index d6bf70e427b..4f5601a7f30 100644 --- a/homeassistant/components/roon/manifest.json +++ b/homeassistant/components/roon/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/roon", "requirements": [ - "roonapi==0.0.21" + "roonapi==0.0.25" ], "codeowners": [ "@pavoni" diff --git a/homeassistant/components/roon/media_browser.py b/homeassistant/components/roon/media_browser.py new file mode 100644 index 00000000000..0d744befb5c --- /dev/null +++ b/homeassistant/components/roon/media_browser.py @@ -0,0 +1,163 @@ +"""Support to interface with the Roon API.""" +import logging + +from homeassistant.components.media_player import BrowseMedia +from homeassistant.components.media_player.const import ( + MEDIA_CLASS_DIRECTORY, + MEDIA_CLASS_PLAYLIST, + MEDIA_CLASS_TRACK, +) +from homeassistant.components.media_player.errors import BrowseError + + +class UnknownMediaType(BrowseError): + """Unknown media type.""" + + +EXCLUDE_ITEMS = { + "Play Album", + "Play Artist", + "Play Playlist", + "Play Composer", + "Play Now", + "Play From Here", + "Queue", + "Start Radio", + "Add Next", + "Play Radio", + "Play Work", + "Settings", + "Search", + "Search Tidal", + "Search Qobuz", +} + +# Maximum number of items to pull back from the API +ITEM_LIMIT = 3000 + +_LOGGER = logging.getLogger(__name__) + + +def browse_media(zone_id, roon_server, media_content_type=None, media_content_id=None): + """Implement the websocket media browsing helper.""" + try: + _LOGGER.debug("browse_media: %s: %s", media_content_type, media_content_id) + if media_content_type in [None, "library"]: + return library_payload(roon_server, zone_id, media_content_id) + + except UnknownMediaType as err: + raise BrowseError( + f"Media not found: {media_content_type} / {media_content_id}" + ) from err + + +def item_payload(roon_server, item, list_image_id): + """Create response payload for a single media item.""" + + title = item["title"] + subtitle = item.get("subtitle") + if subtitle is None: + display_title = title + else: + display_title = f"{title} ({subtitle})" + + image_id = item.get("image_key") or list_image_id + + image = None + if image_id: + image = roon_server.roonapi.get_image(image_id) + + media_content_id = item["item_key"] + media_content_type = "library" + + hint = item.get("hint") + if hint == "list": + media_class = MEDIA_CLASS_DIRECTORY + can_expand = True + elif hint == "action_list": + media_class = MEDIA_CLASS_PLAYLIST + can_expand = False + elif hint == "action": + media_content_type = "track" + media_class = MEDIA_CLASS_TRACK + can_expand = False + else: + # Roon API says to treat unknown as a list + media_class = MEDIA_CLASS_DIRECTORY + can_expand = True + _LOGGER.warning("Unknown hint %s - %s", title, hint) + + payload = { + "title": display_title, + "media_class": media_class, + "media_content_id": media_content_id, + "media_content_type": media_content_type, + "can_play": True, + "can_expand": can_expand, + "thumbnail": image, + } + + return BrowseMedia(**payload) + + +def library_payload(roon_server, zone_id, media_content_id): + """Create response payload for the library.""" + + opts = { + "hierarchy": "browse", + "zone_or_output_id": zone_id, + "count": ITEM_LIMIT, + } + + # Roon starts browsing for a zone where it left off - so start from the top unless otherwise specified + if media_content_id is None or media_content_id == "Explore": + opts["pop_all"] = True + content_id = "Explore" + else: + opts["item_key"] = media_content_id + content_id = media_content_id + + result_header = roon_server.roonapi.browse_browse(opts) + _LOGGER.debug("Result header %s", result_header) + + header = result_header["list"] + title = header.get("title") + + subtitle = header.get("subtitle") + if subtitle is None: + list_title = title + else: + list_title = f"{title} ({subtitle})" + + total_count = header["count"] + + library_image_id = header.get("image_key") + + library_info = BrowseMedia( + title=list_title, + media_content_id=content_id, + media_content_type="library", + media_class=MEDIA_CLASS_DIRECTORY, + can_play=False, + can_expand=True, + children=[], + ) + + result_detail = roon_server.roonapi.browse_load(opts) + _LOGGER.debug("Result detail %s", result_detail) + + items = result_detail["items"] + count = len(items) + + if count < total_count: + _LOGGER.debug( + "Exceeded limit of %d, loaded %d/%d", ITEM_LIMIT, count, total_count + ) + + for item in items: + if item.get("title") in EXCLUDE_ITEMS: + continue + entry = item_payload(roon_server, item, library_image_id) + library_info.children.append(entry) + + return library_info diff --git a/homeassistant/components/roon/media_player.py b/homeassistant/components/roon/media_player.py index a4bd374dcce..e0ae86b781a 100644 --- a/homeassistant/components/roon/media_player.py +++ b/homeassistant/components/roon/media_player.py @@ -1,8 +1,11 @@ """MediaPlayer platform for Roon integration.""" import logging +import voluptuous as vol + from homeassistant.components.media_player import MediaPlayerEntity from homeassistant.components.media_player.const import ( + SUPPORT_BROWSE_MEDIA, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY, @@ -25,6 +28,7 @@ from homeassistant.const import ( STATE_PLAYING, ) from homeassistant.core import callback +from homeassistant.helpers import config_validation as cv, entity_platform from homeassistant.helpers.dispatcher import ( async_dispatcher_connect, async_dispatcher_send, @@ -33,9 +37,11 @@ from homeassistant.util import convert from homeassistant.util.dt import utcnow from .const import DOMAIN +from .media_browser import browse_media SUPPORT_ROON = ( - SUPPORT_PAUSE + SUPPORT_BROWSE_MEDIA + | SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_STOP | SUPPORT_PREVIOUS_TRACK @@ -52,12 +58,38 @@ SUPPORT_ROON = ( _LOGGER = logging.getLogger(__name__) +SERVICE_JOIN = "join" +SERVICE_UNJOIN = "unjoin" +SERVICE_TRANSFER = "transfer" + +ATTR_JOIN = "join_ids" +ATTR_UNJOIN = "unjoin_ids" +ATTR_TRANSFER = "transfer_id" + async def async_setup_entry(hass, config_entry, async_add_entities): """Set up Roon MediaPlayer from Config Entry.""" roon_server = hass.data[DOMAIN][config_entry.entry_id] media_players = set() + # Register entity services + platform = entity_platform.current_platform.get() + platform.async_register_entity_service( + SERVICE_JOIN, + {vol.Required(ATTR_JOIN): vol.All(cv.ensure_list, [cv.entity_id])}, + "join", + ) + platform.async_register_entity_service( + SERVICE_UNJOIN, + {vol.Optional(ATTR_UNJOIN): vol.All(cv.ensure_list, [cv.entity_id])}, + "unjoin", + ) + platform.async_register_entity_service( + SERVICE_TRANSFER, + {vol.Required(ATTR_TRANSFER): cv.entity_id}, + "async_transfer", + ) + @callback def async_update_media_player(player_data): """Add or update Roon MediaPlayer.""" @@ -115,6 +147,7 @@ class RoonDevice(MediaPlayerEntity): self.async_update_callback, ) ) + self._server.add_player_id(self.entity_id, self.name) @callback def async_update_callback(self, player_data): @@ -466,9 +499,127 @@ class RoonDevice(MediaPlayerEntity): self._server.roonapi.queue_playlist(self.zone_id, media_id) elif media_type == "genre": self._server.roonapi.play_genre(self.zone_id, media_id) + elif media_type in ("library", "track"): + self._server.roonapi.play_id(self.zone_id, media_id) else: _LOGGER.error( "Playback requested of unsupported type: %s --> %s", media_type, media_id, ) + + def join(self, join_ids): + """Add another Roon player to this player's join group.""" + + zone_data = self._server.roonapi.zone_by_output_id(self._output_id) + if zone_data is None: + _LOGGER.error("No zone data for %s", self.name) + return + + sync_available = {} + for zone in self._server.zones.values(): + for output in zone["outputs"]: + if ( + zone["display_name"] != self.name + and output["output_id"] + in self.player_data["can_group_with_output_ids"] + and zone["display_name"] not in sync_available + ): + sync_available[zone["display_name"]] = output["output_id"] + + names = [] + for entity_id in join_ids: + name = self._server.roon_name(entity_id) + if name is None: + _LOGGER.error("No roon player found for %s", entity_id) + return + if name not in sync_available: + _LOGGER.error( + "Can't join player %s with %s because it's not in the join available list %s", + name, + self.name, + list(sync_available), + ) + return + names.append(name) + + _LOGGER.debug("Joining %s to %s", names, self.name) + self._server.roonapi.group_outputs( + [self._output_id] + [sync_available[name] for name in names] + ) + + def unjoin(self, unjoin_ids=None): + """Remove a Roon player to this player's join group.""" + + zone_data = self._server.roonapi.zone_by_output_id(self._output_id) + if zone_data is None: + _LOGGER.error("No zone data for %s", self.name) + return + + join_group = { + output["display_name"]: output["output_id"] + for output in zone_data["outputs"] + if output["display_name"] != self.name + } + + if unjoin_ids is None: + # unjoin everything + names = list(join_group) + else: + names = [] + for entity_id in unjoin_ids: + name = self._server.roon_name(entity_id) + if name is None: + _LOGGER.error("No roon player found for %s", entity_id) + return + + if name not in join_group: + _LOGGER.error( + "Can't unjoin player %s from %s because it's not in the joined group %s", + name, + self.name, + list(join_group), + ) + return + names.append(name) + + _LOGGER.debug("Unjoining %s from %s", names, self.name) + self._server.roonapi.ungroup_outputs([join_group[name] for name in names]) + + async def async_transfer(self, transfer_id): + """Transfer playback from this roon player to another.""" + + name = self._server.roon_name(transfer_id) + if name is None: + _LOGGER.error("No roon player found for %s", transfer_id) + return + + zone_ids = { + output["display_name"]: output["zone_id"] + for output in self._server.zones.values() + if output["display_name"] != self.name + } + + transfer_id = zone_ids.get(name) + if transfer_id is None: + _LOGGER.error( + "Can't transfer from %s to %s because destination is not known %s", + self.name, + transfer_id, + list(zone_ids), + ) + + _LOGGER.debug("Transferring from %s to %s", self.name, name) + await self.hass.async_add_executor_job( + self._server.roonapi.transfer_zone, self._zone_id, transfer_id + ) + + async def async_browse_media(self, media_content_type=None, media_content_id=None): + """Implement the websocket media browsing helper.""" + return await self.hass.async_add_executor_job( + browse_media, + self.zone_id, + self._server, + media_content_type, + media_content_id, + ) diff --git a/homeassistant/components/roon/server.py b/homeassistant/components/roon/server.py index df6051c287a..0229f3492be 100644 --- a/homeassistant/components/roon/server.py +++ b/homeassistant/components/roon/server.py @@ -2,7 +2,7 @@ import asyncio import logging -from roon import RoonApi +from roonapi import RoonApi from homeassistant.const import CONF_API_KEY, CONF_HOST from homeassistant.helpers.dispatcher import async_dispatcher_send @@ -26,6 +26,7 @@ class RoonServer: self.all_playlists = [] self.offline_devices = set() self._exit = False + self._roon_name_by_id = {} @property def host(self): @@ -69,6 +70,14 @@ class RoonServer: """Return list of zones.""" return self.roonapi.zones + def add_player_id(self, entity_id, roon_name): + """Register a roon player.""" + self._roon_name_by_id[entity_id] = roon_name + + def roon_name(self, entity_id): + """Get the name of the roon player from entity_id.""" + return self._roon_name_by_id.get(entity_id) + def stop_roon(self): """Stop background worker.""" self.roonapi.stop() diff --git a/homeassistant/components/roon/services.yaml b/homeassistant/components/roon/services.yaml new file mode 100644 index 00000000000..ec096effe5b --- /dev/null +++ b/homeassistant/components/roon/services.yaml @@ -0,0 +1,29 @@ +join: + description: Group players together. + fields: + entity_id: + description: id of the player that will be the master of the group. + example: "media_player.study" + join_ids: + description: id(s) of the players that will join the master. + example: "['media_player.bedroom', 'media_player.kitchen']" + +unjoin: + description: Remove players from a group. + fields: + entity_id: + description: id of the player that is the master of the group.. + example: "media_player.study" + unjoin_ids: + description: Optional id(s) of the players that will be unjoined from the group. If not specified, all players will be unjoined from the master. + example: "['media_player.bedroom', 'media_player.kitchen']" + +transfer: + description: Transfer playback from one player to another. + fields: + entity_id: + description: id of the source player. + example: "media_player.bedroom" + transfer_id: + description: id of the destination player. + example: "media_player.study" diff --git a/homeassistant/components/roon/strings.json b/homeassistant/components/roon/strings.json index 741fc01605f..8164f47ade8 100644 --- a/homeassistant/components/roon/strings.json +++ b/homeassistant/components/roon/strings.json @@ -1,9 +1,7 @@ { - "title": "Roon", "config": { "step": { "user": { - "title": "Configure Roon Server", "description": "Please enter your Roon server Hostname or IP.", "data": { "host": "[%key:common::config_flow::data::host%]" diff --git a/homeassistant/components/roon/translations/ca.json b/homeassistant/components/roon/translations/ca.json index b783c9a6229..3a1de2208b6 100644 --- a/homeassistant/components/roon/translations/ca.json +++ b/homeassistant/components/roon/translations/ca.json @@ -17,10 +17,8 @@ "data": { "host": "Amfitri\u00f3" }, - "description": "Introdueix el nom d'amfitri\u00f3 o la IP del servidor Roon", - "title": "Configura un servidor Roon" + "description": "Introdueix el nom d'amfitri\u00f3 o la IP del servidor Roon" } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/cs.json b/homeassistant/components/roon/translations/cs.json index 899bc285de4..a15e75066a9 100644 --- a/homeassistant/components/roon/translations/cs.json +++ b/homeassistant/components/roon/translations/cs.json @@ -10,16 +10,15 @@ }, "step": { "link": { + "description": "Mus\u00edte povolit Home Assistant v Roon. Po kliknut\u00ed na Odeslat p\u0159ejd\u011bte do aplikace Roon Core, otev\u0159ete Nastaven\u00ed a na z\u00e1lo\u017ece Roz\u0161\u00ed\u0159en\u00ed povolte Home Assistant.", "title": "Autorizujte HomeAssistant v Roon" }, "user": { "data": { "host": "Hostitel" }, - "description": "Zadejte pros\u00edm n\u00e1zev hostitele nebo IP adresu va\u0161eho Roon serveru.", - "title": "Nastaven\u00ed serveru Roon" + "description": "Zadejte pros\u00edm n\u00e1zev hostitele nebo IP adresu va\u0161eho Roon serveru." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/de.json b/homeassistant/components/roon/translations/de.json index 00f85d6c1b6..9e6453222a9 100644 --- a/homeassistant/components/roon/translations/de.json +++ b/homeassistant/components/roon/translations/de.json @@ -3,6 +3,5 @@ "error": { "duplicate_entry": "Dieser Host wurde bereits hinzugef\u00fcgt." } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/el.json b/homeassistant/components/roon/translations/el.json index 4a17e5f1288..fd197369cb8 100644 --- a/homeassistant/components/roon/translations/el.json +++ b/homeassistant/components/roon/translations/el.json @@ -9,10 +9,8 @@ "title": "\u0395\u03be\u03bf\u03c5\u03c3\u03b9\u03bf\u03b4\u03bf\u03c4\u03ae\u03c3\u03c4\u03b5 \u03c4\u03bf HomeAssistant \u03c3\u03c4\u03bf Roon" }, "user": { - "description": "\u0395\u03b9\u03c3\u03b1\u03b3\u03ac\u03b3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03cc\u03bd\u03bf\u03bc\u03b1 \u03ba\u03b5\u03bd\u03c4\u03c1\u03b9\u03ba\u03bf\u03cd \u03c5\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03c4\u03ae \u03ae \u03c4\u03b7\u03bd IP \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae Roon.", - "title": "\u0394\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae Roon" + "description": "\u0395\u03b9\u03c3\u03b1\u03b3\u03ac\u03b3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03cc\u03bd\u03bf\u03bc\u03b1 \u03ba\u03b5\u03bd\u03c4\u03c1\u03b9\u03ba\u03bf\u03cd \u03c5\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03c4\u03ae \u03ae \u03c4\u03b7\u03bd IP \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae Roon." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/en.json b/homeassistant/components/roon/translations/en.json index b7ae64f0de1..99f2b65bd13 100644 --- a/homeassistant/components/roon/translations/en.json +++ b/homeassistant/components/roon/translations/en.json @@ -17,10 +17,8 @@ "data": { "host": "Host" }, - "description": "Please enter your Roon server Hostname or IP.", - "title": "Configure Roon Server" + "description": "Please enter your Roon server Hostname or IP." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/es.json b/homeassistant/components/roon/translations/es.json index 9c8f4346118..daf3200a0e4 100644 --- a/homeassistant/components/roon/translations/es.json +++ b/homeassistant/components/roon/translations/es.json @@ -17,10 +17,8 @@ "data": { "host": "Host" }, - "description": "Introduce el nombre de Host o IP del servidor Roon.", - "title": "Configurar el Servidor Roon" + "description": "Introduce el nombre de Host o IP del servidor Roon." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/et.json b/homeassistant/components/roon/translations/et.json index 7c2ca0d1bb1..dfe3ad53f48 100644 --- a/homeassistant/components/roon/translations/et.json +++ b/homeassistant/components/roon/translations/et.json @@ -9,6 +9,10 @@ "unknown": "Tundmatu viga" }, "step": { + "link": { + "description": "Pead Roonis koduabilise volitama. Kui oled kl\u00f5psanud nuppu Esita, mine rakendusse Roon Core, ava Seaded ja luba vahekaardil Laiendused Home Assistant.", + "title": "Volita HomeAssistant Roonis" + }, "user": { "data": { "host": "" @@ -16,6 +20,5 @@ "description": "Sisesta oma Rooni serveri hostinimi v\u00f5i IP." } } - }, - "title": "[VOID]\n" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/fr.json b/homeassistant/components/roon/translations/fr.json index f41c7728954..7e61b556d39 100644 --- a/homeassistant/components/roon/translations/fr.json +++ b/homeassistant/components/roon/translations/fr.json @@ -17,10 +17,8 @@ "data": { "host": "H\u00f4te" }, - "description": "Veuillez entrer votre nom d\u2019h\u00f4te ou votre adresse IP sur votre serveur Roon.", - "title": "Configurer le serveur Roon" + "description": "Veuillez entrer votre nom d\u2019h\u00f4te ou votre adresse IP sur votre serveur Roon." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/it.json b/homeassistant/components/roon/translations/it.json index cfa1f7a3844..5f63482c3c3 100644 --- a/homeassistant/components/roon/translations/it.json +++ b/homeassistant/components/roon/translations/it.json @@ -17,10 +17,8 @@ "data": { "host": "Host" }, - "description": "Inserisci il nome host o l'IP del tuo server Roon.", - "title": "Configurare Il server Roon" + "description": "Inserisci il nome host o l'IP del tuo server Roon." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/ko.json b/homeassistant/components/roon/translations/ko.json index cdffd6e88ae..ae483b0b098 100644 --- a/homeassistant/components/roon/translations/ko.json +++ b/homeassistant/components/roon/translations/ko.json @@ -17,8 +17,7 @@ "data": { "host": "\ud638\uc2a4\ud2b8" }, - "description": "Roon \uc11c\ubc84 Hostname \ub610\ub294 IP\ub97c \uc785\ub825\ud558\uc2ed\uc2dc\uc624.", - "title": "Roon \uc11c\ubc84 \uad6c\uc131" + "description": "Roon \uc11c\ubc84 Hostname \ub610\ub294 IP\ub97c \uc785\ub825\ud558\uc2ed\uc2dc\uc624." } } } diff --git a/homeassistant/components/roon/translations/lb.json b/homeassistant/components/roon/translations/lb.json index e8c3bc1825b..a8fef968e81 100644 --- a/homeassistant/components/roon/translations/lb.json +++ b/homeassistant/components/roon/translations/lb.json @@ -17,10 +17,8 @@ "data": { "host": "Host" }, - "description": "G\u00ebff den Numm oder IP-Adress vun dengem Roon Server un.", - "title": "Roon Server ariichten" + "description": "G\u00ebff den Numm oder IP-Adress vun dengem Roon Server un." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/nl.json b/homeassistant/components/roon/translations/nl.json index 73abdb3d49b..535c56a2f98 100644 --- a/homeassistant/components/roon/translations/nl.json +++ b/homeassistant/components/roon/translations/nl.json @@ -17,10 +17,8 @@ "data": { "host": "Host" }, - "description": "Voer de hostnaam of het IP-adres van uw Roon-server in.", - "title": "Configureer Roon Server" + "description": "Voer de hostnaam of het IP-adres van uw Roon-server in." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/no.json b/homeassistant/components/roon/translations/no.json index 92176c8aac0..acfb900218b 100644 --- a/homeassistant/components/roon/translations/no.json +++ b/homeassistant/components/roon/translations/no.json @@ -17,10 +17,8 @@ "data": { "host": "Vert" }, - "description": "Vennligst skriv inn Roon-serverens vertsnavn eller IP.", - "title": "Konfigurer Roon Server" + "description": "Vennligst skriv inn Roon-serverens vertsnavn eller IP." } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/pl.json b/homeassistant/components/roon/translations/pl.json index e0dd3345216..e63c5f6b55c 100644 --- a/homeassistant/components/roon/translations/pl.json +++ b/homeassistant/components/roon/translations/pl.json @@ -17,10 +17,8 @@ "data": { "host": "Nazwa hosta lub adres IP" }, - "description": "Wprowad\u017a nazw\u0119 hosta lub adres IP swojego serwera Roon.", - "title": "Konfiguracja serwera Roon" + "description": "Wprowad\u017a nazw\u0119 hosta lub adres IP swojego serwera Roon." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/pt-BR.json b/homeassistant/components/roon/translations/pt-BR.json index 5a11826f285..cbcba0352a9 100644 --- a/homeassistant/components/roon/translations/pt-BR.json +++ b/homeassistant/components/roon/translations/pt-BR.json @@ -17,10 +17,8 @@ "data": { "host": "Host" }, - "description": "Por favor, digite seu hostname ou IP do servidor Roon.", - "title": "Configurar Servidor Roon" + "description": "Por favor, digite seu hostname ou IP do servidor Roon." } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/ru.json b/homeassistant/components/roon/translations/ru.json index cfed11dd4cf..abfbea2ccde 100644 --- a/homeassistant/components/roon/translations/ru.json +++ b/homeassistant/components/roon/translations/ru.json @@ -17,10 +17,8 @@ "data": { "host": "\u0425\u043e\u0441\u0442" }, - "description": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 IP-\u0430\u0434\u0440\u0435\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Roon", - "title": "\u0421\u0435\u0440\u0432\u0435\u0440 Roon" + "description": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 IP-\u0430\u0434\u0440\u0435\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Roon" } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/roon/translations/zh-Hant.json b/homeassistant/components/roon/translations/zh-Hant.json index 894da32c39c..00b152205f3 100644 --- a/homeassistant/components/roon/translations/zh-Hant.json +++ b/homeassistant/components/roon/translations/zh-Hant.json @@ -17,10 +17,8 @@ "data": { "host": "\u4e3b\u6a5f\u7aef" }, - "description": "\u8acb\u8f38\u5165 Roon \u4f3a\u670d\u5668\u4e3b\u6a5f\u540d\u7a31\u6216 IP\u3002", - "title": "\u8a2d\u5b9a Roon \u4f3a\u670d\u5668" + "description": "\u8acb\u8f38\u5165 Roon \u4f3a\u670d\u5668\u4e3b\u6a5f\u540d\u7a31\u6216 IP\u3002" } } - }, - "title": "Roon" + } } \ No newline at end of file diff --git a/homeassistant/components/rpi_power/translations/et.json b/homeassistant/components/rpi_power/translations/et.json index d79ef1ad554..fdf32414ba7 100644 --- a/homeassistant/components/rpi_power/translations/et.json +++ b/homeassistant/components/rpi_power/translations/et.json @@ -2,7 +2,7 @@ "config": { "abort": { "no_devices_found": "Ei leia selle komponendi jaoks vajalikku s\u00fcsteemiklassi. Veenduge, et teie kernel on v\u00e4rske ja riistvara on toetatud", - "single_instance_allowed": "Seadistused on juba tehtud. Korraga saab olla ainult \u00fcks konfiguratsioon." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "step": { "confirm": { diff --git a/homeassistant/components/rpi_power/translations/lb.json b/homeassistant/components/rpi_power/translations/lb.json index 1b4c77f4fda..3e145432bae 100644 --- a/homeassistant/components/rpi_power/translations/lb.json +++ b/homeassistant/components/rpi_power/translations/lb.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "no_devices_found": "Kann d\u00e9i Systemklass fir d\u00ebs noutwendeg Komponent net fannen, stell s\u00e9cher dass de Kernel rezent ass an d'Hardware \u00ebnnerst\u00ebtzt g\u00ebtt." + "no_devices_found": "Kann d\u00e9i Systemklass fir d\u00ebs noutwendeg Komponent net fannen, stell s\u00e9cher dass de Kernel rezent ass an d'Hardware \u00ebnnerst\u00ebtzt g\u00ebtt.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." } }, "title": "Raspberry Pi Netzdeel Checker" diff --git a/homeassistant/components/ruckus_unleashed/strings.json b/homeassistant/components/ruckus_unleashed/strings.json index d4814f84231..d6e3212b4ea 100644 --- a/homeassistant/components/ruckus_unleashed/strings.json +++ b/homeassistant/components/ruckus_unleashed/strings.json @@ -1,5 +1,4 @@ { - "title": "Ruckus Unleashed", "config": { "step": { "user": { @@ -19,4 +18,4 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } } -} \ No newline at end of file +} diff --git a/homeassistant/components/ruckus_unleashed/translations/ca.json b/homeassistant/components/ruckus_unleashed/translations/ca.json index 773151ac1bc..df8218bab3e 100644 --- a/homeassistant/components/ruckus_unleashed/translations/ca.json +++ b/homeassistant/components/ruckus_unleashed/translations/ca.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Ruckus Unleashed" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/cs.json b/homeassistant/components/ruckus_unleashed/translations/cs.json index b9dac7e6778..0f02cd974c2 100644 --- a/homeassistant/components/ruckus_unleashed/translations/cs.json +++ b/homeassistant/components/ruckus_unleashed/translations/cs.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Ruckus Unleashed" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/de.json b/homeassistant/components/ruckus_unleashed/translations/de.json index 94b8d6526d1..1b5c5cb760e 100644 --- a/homeassistant/components/ruckus_unleashed/translations/de.json +++ b/homeassistant/components/ruckus_unleashed/translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Ger\u00e4t ist bereits konfiguriert" + }, "error": { "unknown": "Unerwarteter Fehler" }, diff --git a/homeassistant/components/ruckus_unleashed/translations/en.json b/homeassistant/components/ruckus_unleashed/translations/en.json index b916b420aec..f15fe84c3ed 100644 --- a/homeassistant/components/ruckus_unleashed/translations/en.json +++ b/homeassistant/components/ruckus_unleashed/translations/en.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Ruckus Unleashed" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/es.json b/homeassistant/components/ruckus_unleashed/translations/es.json index 371c4ea3852..2609ee07eaf 100644 --- a/homeassistant/components/ruckus_unleashed/translations/es.json +++ b/homeassistant/components/ruckus_unleashed/translations/es.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Ruckus Unleashed" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/et.json b/homeassistant/components/ruckus_unleashed/translations/et.json index 7ebfa29e4db..1f0816be706 100644 --- a/homeassistant/components/ruckus_unleashed/translations/et.json +++ b/homeassistant/components/ruckus_unleashed/translations/et.json @@ -17,6 +17,5 @@ } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/fr.json b/homeassistant/components/ruckus_unleashed/translations/fr.json new file mode 100644 index 00000000000..45620fe7795 --- /dev/null +++ b/homeassistant/components/ruckus_unleashed/translations/fr.json @@ -0,0 +1,21 @@ +{ + "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" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/it.json b/homeassistant/components/ruckus_unleashed/translations/it.json index e33f59bd74d..e9356485e08 100644 --- a/homeassistant/components/ruckus_unleashed/translations/it.json +++ b/homeassistant/components/ruckus_unleashed/translations/it.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Ruckus Unleashed" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/lb.json b/homeassistant/components/ruckus_unleashed/translations/lb.json new file mode 100644 index 00000000000..e235a2f9047 --- /dev/null +++ b/homeassistant/components/ruckus_unleashed/translations/lb.json @@ -0,0 +1,21 @@ +{ + "config": { + "abort": { + "already_configured": "Apparat ass scho konfigur\u00e9iert" + }, + "error": { + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", + "unknown": "Onerwaarte Feeler" + }, + "step": { + "user": { + "data": { + "host": "Host", + "password": "Passwuert", + "username": "Benotzernumm" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/nl.json b/homeassistant/components/ruckus_unleashed/translations/nl.json new file mode 100644 index 00000000000..7482a0bbe7c --- /dev/null +++ b/homeassistant/components/ruckus_unleashed/translations/nl.json @@ -0,0 +1,17 @@ +{ + "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "invalid_auth": "Ongeldige authenticatie" + }, + "step": { + "user": { + "data": { + "password": "Wachtwoord" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/no.json b/homeassistant/components/ruckus_unleashed/translations/no.json index bf7f9170872..249711bb912 100644 --- a/homeassistant/components/ruckus_unleashed/translations/no.json +++ b/homeassistant/components/ruckus_unleashed/translations/no.json @@ -17,6 +17,5 @@ } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/pl.json b/homeassistant/components/ruckus_unleashed/translations/pl.json index 90fe091cbe5..25dab56796c 100644 --- a/homeassistant/components/ruckus_unleashed/translations/pl.json +++ b/homeassistant/components/ruckus_unleashed/translations/pl.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Ruckus Unleashed" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/ru.json b/homeassistant/components/ruckus_unleashed/translations/ru.json index 70331cb8936..6f71ee41376 100644 --- a/homeassistant/components/ruckus_unleashed/translations/ru.json +++ b/homeassistant/components/ruckus_unleashed/translations/ru.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Ruckus Unleashed" + } } \ No newline at end of file diff --git a/homeassistant/components/ruckus_unleashed/translations/zh-Hans.json b/homeassistant/components/ruckus_unleashed/translations/zh-Hans.json index b6a239d7b99..d5cc919a9ac 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/ruckus_unleashed/translations/zh-Hant.json b/homeassistant/components/ruckus_unleashed/translations/zh-Hant.json index a6cc1c3c0b9..8bf65ef6ee6 100644 --- a/homeassistant/components/ruckus_unleashed/translations/zh-Hant.json +++ b/homeassistant/components/ruckus_unleashed/translations/zh-Hant.json @@ -17,6 +17,5 @@ } } } - }, - "title": "Ruckus Unleashed" + } } \ No newline at end of file diff --git a/homeassistant/components/samsungtv/translations/ca.json b/homeassistant/components/samsungtv/translations/ca.json index 9b0b9a37844..bba625bc815 100644 --- a/homeassistant/components/samsungtv/translations/ca.json +++ b/homeassistant/components/samsungtv/translations/ca.json @@ -5,7 +5,6 @@ "already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs", "auth_missing": "Home Assistant no est\u00e0 autenticat per connectar-se amb aquest televisor Samsung. V\u00e9s a la configuraci\u00f3 del televisor per autoritzar a Home Assistant.", "cannot_connect": "Ha fallat la connexi\u00f3", - "not_successful": "No s'ha pogut connectar amb el dispositiu el televisor Samsung.", "not_supported": "Actualment aquest televisor Samsung no \u00e9s compatible." }, "flow_title": "Televisor Samsung: {model}", diff --git a/homeassistant/components/samsungtv/translations/cs.json b/homeassistant/components/samsungtv/translations/cs.json index 25675464169..f141dc3a09b 100644 --- a/homeassistant/components/samsungtv/translations/cs.json +++ b/homeassistant/components/samsungtv/translations/cs.json @@ -5,7 +5,6 @@ "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", "auth_missing": "Home Assistant nem\u00e1 opr\u00e1vn\u011bn\u00ed k p\u0159ipojen\u00ed k t\u00e9to televizi Samsung. Zkontrolujte nastaven\u00ed sv\u00e9 televize a povolte Home Assistant.", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "not_successful": "Nelze se p\u0159ipojit k t\u00e9to televizi Samsung.", "not_supported": "Tato televize Samsung nen\u00ed aktu\u00e1ln\u011b podporov\u00e1na." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/da.json b/homeassistant/components/samsungtv/translations/da.json index 925abbe66ef..9ca829b7679 100644 --- a/homeassistant/components/samsungtv/translations/da.json +++ b/homeassistant/components/samsungtv/translations/da.json @@ -4,7 +4,6 @@ "already_configured": "Dette Samsung-tv er allerede konfigureret.", "already_in_progress": "Samsung-tv-konfiguration er allerede i gang.", "auth_missing": "Home Assistant er ikke godkendt til at oprette forbindelse til dette Samsung-tv. Tjek dit tvs indstillinger for at godkende Home Assistant.", - "not_successful": "Kan ikke oprette forbindelse til denne Samsung tv-enhed.", "not_supported": "Dette Samsung TV underst\u00f8ttes i \u00f8jeblikket ikke." }, "flow_title": "Samsung-tv: {model}", diff --git a/homeassistant/components/samsungtv/translations/de.json b/homeassistant/components/samsungtv/translations/de.json index 38d6365205b..c083048e4cd 100644 --- a/homeassistant/components/samsungtv/translations/de.json +++ b/homeassistant/components/samsungtv/translations/de.json @@ -4,7 +4,6 @@ "already_configured": "Dieser Samsung TV ist bereits konfiguriert", "already_in_progress": "Der Konfigurationsablauf f\u00fcr Samsung TV wird bereits ausgef\u00fchrt.", "auth_missing": "Home Assistant ist nicht berechtigt, eine Verbindung zu diesem Samsung TV herzustellen. \u00dcberpr\u00fcfe die Einstellungen deines Fernsehger\u00e4ts, um Home Assistant zu autorisieren.", - "not_successful": "Es kann keine Verbindung zu diesem Samsung-Fernsehger\u00e4t hergestellt werden.", "not_supported": "Dieses Samsung TV-Ger\u00e4t wird derzeit nicht unterst\u00fctzt." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/en.json b/homeassistant/components/samsungtv/translations/en.json index ff33876b93a..5c84880380e 100644 --- a/homeassistant/components/samsungtv/translations/en.json +++ b/homeassistant/components/samsungtv/translations/en.json @@ -5,7 +5,6 @@ "already_in_progress": "Configuration flow is already in progress", "auth_missing": "Home Assistant is not authorized to connect to this Samsung TV. Please check your TV's settings to authorize Home Assistant.", "cannot_connect": "Failed to connect", - "not_successful": "Unable to connect to this Samsung TV device.", "not_supported": "This Samsung TV device is currently not supported." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/es-419.json b/homeassistant/components/samsungtv/translations/es-419.json index c4938543d4a..dfe7793a235 100644 --- a/homeassistant/components/samsungtv/translations/es-419.json +++ b/homeassistant/components/samsungtv/translations/es-419.json @@ -4,7 +4,6 @@ "already_configured": "Esta televisi\u00f3n Samsung ya est\u00e1 configurado.", "already_in_progress": "La configuraci\u00f3n de la televisi\u00f3n Samsung ya est\u00e1 en progreso.", "auth_missing": "Home Assistant no est\u00e1 autorizado para conectarse a esta televisi\u00f3n Samsung. Verifique la configuraci\u00f3n de su televisi\u00f3n para autorizar Home Assistant.", - "not_successful": "No se puede conectar a este dispositivo de TV Samsung.", "not_supported": "Este dispositivo Samsung TV no es compatible actualmente." }, "flow_title": "Televisi\u00f3n Samsung: {model}", diff --git a/homeassistant/components/samsungtv/translations/es.json b/homeassistant/components/samsungtv/translations/es.json index 97160de1a1e..ceb37aaee1b 100644 --- a/homeassistant/components/samsungtv/translations/es.json +++ b/homeassistant/components/samsungtv/translations/es.json @@ -5,7 +5,6 @@ "already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en proceso", "auth_missing": "Home Assistant no est\u00e1 autorizado para conectarse a este televisor Samsung. Revisa la configuraci\u00f3n de tu televisor para autorizar a Home Assistant.", "cannot_connect": "No se pudo conectar", - "not_successful": "No se puede conectar a este dispositivo Samsung TV.", "not_supported": "Esta televisi\u00f3n Samsung actualmente no es compatible." }, "flow_title": "Televisor Samsung: {model}", diff --git a/homeassistant/components/samsungtv/translations/et.json b/homeassistant/components/samsungtv/translations/et.json index 8d3a14710ce..e1c9bc9dd46 100644 --- a/homeassistant/components/samsungtv/translations/et.json +++ b/homeassistant/components/samsungtv/translations/et.json @@ -3,8 +3,11 @@ "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", "already_in_progress": "Seadistamine on juba k\u00e4imas", - "cannot_connect": "\u00dchendamine nurjus" + "auth_missing": "Home Assistant-il pole selle Samsungi teleriga \u00fchenduse loomiseks luba. Koduabilise autoriseerimiseks kontrolli oma teleri seadeid.", + "cannot_connect": "\u00dchendamine nurjus", + "not_supported": "Seda Samsungi tv-seadet praegu ei toetata." }, + "flow_title": "Samsungi teler: {model}", "step": { "confirm": { "description": "Kas soovid seadistada Samsung TV-d {model} ? Kui seda pole kunagi enne Home Assistantiga \u00fchendatud, n\u00e4ed oma teleris h\u00fcpikakent, mis k\u00fcsib tuvastamist. Selle teleri k\u00e4sitsi seadistused kirjutatakse \u00fcle.", @@ -12,8 +15,10 @@ }, "user": { "data": { - "host": "" - } + "host": "", + "name": "Nimi" + }, + "description": "Sisesta Samsungi teleri teave. Kui sa pole kunagi enne Home Assistanti \u00fchendanud, peaksid oma teleris n\u00e4gema h\u00fcpikakent, mis k\u00fcsib autoriseerimist." } } } diff --git a/homeassistant/components/samsungtv/translations/fr.json b/homeassistant/components/samsungtv/translations/fr.json index 43fa17aa315..15a529c94b2 100644 --- a/homeassistant/components/samsungtv/translations/fr.json +++ b/homeassistant/components/samsungtv/translations/fr.json @@ -4,7 +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.", - "not_successful": "Impossible de se connecter \u00e0 cet appareil Samsung TV.", + "cannot_connect": "\u00c9chec de connexion", "not_supported": "Ce t\u00e9l\u00e9viseur Samsung n'est actuellement pas pris en charge." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/hu.json b/homeassistant/components/samsungtv/translations/hu.json index 8c47eb3ed2a..15eabd20d3d 100644 --- a/homeassistant/components/samsungtv/translations/hu.json +++ b/homeassistant/components/samsungtv/translations/hu.json @@ -4,7 +4,6 @@ "already_configured": "Ez a Samsung TV m\u00e1r konfigur\u00e1lva van.", "already_in_progress": "A Samsung TV konfigur\u00e1l\u00e1sa m\u00e1r folyamatban van.", "auth_missing": "A Home Assistant nem jogosult csatlakozni ehhez a Samsung TV-hez. Ellen\u0151rizd a TV be\u00e1ll\u00edt\u00e1sait a Home Assistant enged\u00e9lyez\u00e9s\u00e9hez.", - "not_successful": "Nem lehet csatlakozni ehhez a Samsung TV k\u00e9sz\u00fcl\u00e9khez.", "not_supported": "Ez a Samsung TV k\u00e9sz\u00fcl\u00e9k jelenleg nem t\u00e1mogatott." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/it.json b/homeassistant/components/samsungtv/translations/it.json index 4abbcce70c0..605685913ad 100644 --- a/homeassistant/components/samsungtv/translations/it.json +++ b/homeassistant/components/samsungtv/translations/it.json @@ -5,7 +5,6 @@ "already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso", "auth_missing": "Home Assistant non \u00e8 autorizzato a connettersi a questo Samsung TV. Controlla le impostazioni del tuo TV per autorizzare Home Assistant.", "cannot_connect": "Impossibile connettersi", - "not_successful": "Impossibile connettersi a questo dispositivo Samsung TV.", "not_supported": "Questo dispositivo Samsung TV non \u00e8 attualmente supportato." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/ko.json b/homeassistant/components/samsungtv/translations/ko.json index b635057750b..1c7e0b29808 100644 --- a/homeassistant/components/samsungtv/translations/ko.json +++ b/homeassistant/components/samsungtv/translations/ko.json @@ -4,7 +4,6 @@ "already_configured": "\uc774 \uc0bc\uc131 TV \ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "already_in_progress": "\uc0bc\uc131 TV \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4.", "auth_missing": "Home Assistant \uac00 \ud574\ub2f9 \uc0bc\uc131 TV \uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc788\ub294 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. TV \uc124\uc815\uc744 \ud655\uc778\ud558\uc5ec Home Assistant \ub97c \uc2b9\uc778\ud574\uc8fc\uc138\uc694.", - "not_successful": "\uc0bc\uc131 TV \uae30\uae30\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", "not_supported": "\uc774 \uc0bc\uc131 TV \ubaa8\ub378\uc740 \ud604\uc7ac \uc9c0\uc6d0\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4." }, "flow_title": "\uc0bc\uc131 TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/lb.json b/homeassistant/components/samsungtv/translations/lb.json index 275aa853686..110b063b6e8 100644 --- a/homeassistant/components/samsungtv/translations/lb.json +++ b/homeassistant/components/samsungtv/translations/lb.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_configured": "D\u00ebs Samsung TV ass scho konfigur\u00e9iert.", - "already_in_progress": "Konfiguratioun fir d\u00ebs Samsung TV ass schonn am gaang.", + "already_configured": "Apparat ass scho konfigur\u00e9iert.", + "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaang.", "auth_missing": "Home Assistant ass net authentifiz\u00e9iert fir sech mat d\u00ebsem Samsung TV ze verbannen. Iwwerpr\u00e9if d'Astellunge vum Fernseh fir Home Assistant z'erlaben.", "cannot_connect": "Feeler beim verbannen", - "not_successful": "Keng Verbindung mat d\u00ebsem Samsung TV Apparat m\u00e9iglech.", "not_supported": "D\u00ebsen Samsung TV Modell g\u00ebtt momentan net \u00ebnnerst\u00ebtzt" }, "flow_title": "Samsnung TV:{model}", diff --git a/homeassistant/components/samsungtv/translations/nl.json b/homeassistant/components/samsungtv/translations/nl.json index cd3a1421969..d1e2a9abaa2 100644 --- a/homeassistant/components/samsungtv/translations/nl.json +++ b/homeassistant/components/samsungtv/translations/nl.json @@ -5,7 +5,6 @@ "already_in_progress": "Samsung TV configuratie is al in uitvoering.", "auth_missing": "Home Assistant is niet geautoriseerd om verbinding te maken met deze Samsung TV.", "cannot_connect": "Kan geen verbinding maken", - "not_successful": "Niet in staat om verbinding te maken met dit Samsung TV toestel.", "not_supported": "Deze Samsung TV wordt momenteel niet ondersteund." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/no.json b/homeassistant/components/samsungtv/translations/no.json index c48dac2561d..5d53619a96a 100644 --- a/homeassistant/components/samsungtv/translations/no.json +++ b/homeassistant/components/samsungtv/translations/no.json @@ -5,7 +5,6 @@ "already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede", "auth_missing": "Home Assistant er ikke godkjent til \u00e5 koble til denne Samsung-TV. Vennligst kontroller innstillingene for TV-en for \u00e5 godkjenne Home Assistent.", "cannot_connect": "Tilkobling mislyktes", - "not_successful": "Kan ikke koble til denne Samsung TV-enheten.", "not_supported": "Denne Samsung TV-enhetene st\u00f8ttes forel\u00f8pig ikke." }, "flow_title": "", diff --git a/homeassistant/components/samsungtv/translations/pl.json b/homeassistant/components/samsungtv/translations/pl.json index e5ef0ec792f..0257827abed 100644 --- a/homeassistant/components/samsungtv/translations/pl.json +++ b/homeassistant/components/samsungtv/translations/pl.json @@ -5,7 +5,6 @@ "already_in_progress": "Konfiguracja jest ju\u017c w toku", "auth_missing": "Home Assistant nie ma uprawnie\u0144 do po\u0142\u0105czenia si\u0119 z tym telewizorem Samsung. Sprawd\u017a ustawienia telewizora, aby autoryzowa\u0107 Home Assistant.", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "not_successful": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 urz\u0105dzeniem Samsung TV", "not_supported": "Ten telewizor Samsung nie jest obecnie obs\u0142ugiwany" }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/ru.json b/homeassistant/components/samsungtv/translations/ru.json index 8af4f95404c..983e7417d6b 100644 --- a/homeassistant/components/samsungtv/translations/ru.json +++ b/homeassistant/components/samsungtv/translations/ru.json @@ -5,7 +5,6 @@ "already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.", "auth_missing": "Home Assistant \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u044d\u0442\u043e\u043c\u0443 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440\u0430.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "not_successful": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443.", "not_supported": "\u042d\u0442\u0430 \u043c\u043e\u0434\u0435\u043b\u044c \u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440\u0430 \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/sl.json b/homeassistant/components/samsungtv/translations/sl.json index 1002be5efd1..1a94ce59833 100644 --- a/homeassistant/components/samsungtv/translations/sl.json +++ b/homeassistant/components/samsungtv/translations/sl.json @@ -4,7 +4,6 @@ "already_configured": "Ta televizor Samsung je \u017ee konfiguriran.", "already_in_progress": "Konfiguracija Samsung TV je \u017ee v teku.", "auth_missing": "Home Assistant nima dovoljenja za povezavo s tem televizorjem Samsung. Preverite nastavitve televizorja, da ga pooblastite.", - "not_successful": "Povezave s to napravo Samsung TV ni mogo\u010de vzpostaviti.", "not_supported": "Ta naprava Samsung TV trenutno ni podprta." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/sv.json b/homeassistant/components/samsungtv/translations/sv.json index 5caa8daa275..3558559c4b6 100644 --- a/homeassistant/components/samsungtv/translations/sv.json +++ b/homeassistant/components/samsungtv/translations/sv.json @@ -4,7 +4,6 @@ "already_configured": "Denna Samsung TV \u00e4r redan konfigurerad.", "already_in_progress": "Samsung TV-konfiguration p\u00e5g\u00e5r redan.", "auth_missing": "Home Assistant har inte beh\u00f6righet att ansluta till denna Samsung TV. Kontrollera tv:ns inst\u00e4llningar f\u00f6r att godk\u00e4nna Home Assistant.", - "not_successful": "Det g\u00e5r inte att ansluta till denna Samsung TV-enhet.", "not_supported": "Denna Samsung TV-enhet st\u00f6ds f\u00f6r n\u00e4rvarande inte." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/tr.json b/homeassistant/components/samsungtv/translations/tr.json index 296579c17f4..50e6b21d120 100644 --- a/homeassistant/components/samsungtv/translations/tr.json +++ b/homeassistant/components/samsungtv/translations/tr.json @@ -4,7 +4,6 @@ "already_configured": "Bu Samsung TV zaten ayarlanm\u0131\u015f.", "already_in_progress": "Samsung TV ayar\u0131 zaten s\u00fcr\u00fcyor.", "auth_missing": "Home Assistant'\u0131n bu Samsung TV'ye ba\u011flanma izni yok. Home Assistant'\u0131 yetkilendirmek i\u00e7in l\u00fctfen TV'nin ayarlar\u0131n\u0131 kontrol et.", - "not_successful": "Bu Samsung TV cihaz\u0131na ba\u011flan\u0131lam\u0131yor.", "not_supported": "Bu Samsung TV cihaz\u0131 \u015fu anda desteklenmiyor." }, "flow_title": "Samsung TV: {model}", diff --git a/homeassistant/components/samsungtv/translations/zh-Hant.json b/homeassistant/components/samsungtv/translations/zh-Hant.json index 198a4fdb983..e932e18a2b5 100644 --- a/homeassistant/components/samsungtv/translations/zh-Hant.json +++ b/homeassistant/components/samsungtv/translations/zh-Hant.json @@ -5,7 +5,6 @@ "already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d", "auth_missing": "Home Assistant \u672a\u7372\u5f97\u9a57\u8b49\u4ee5\u9023\u7dda\u81f3\u6b64\u4e09\u661f\u96fb\u8996\u3002\u8acb\u6aa2\u67e5\u60a8\u7684\u96fb\u8996\u8a2d\u5b9a\u4ee5\u76e1\u8208\u9a57\u8b49\u3002", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "not_successful": "\u7121\u6cd5\u9023\u7dda\u81f3\u4e09\u661f\u96fb\u8996\u8a2d\u5099\u3002", "not_supported": "\u4e0d\u652f\u63f4\u6b64\u6b3e\u4e09\u661f\u96fb\u8996\u3002" }, "flow_title": "\u4e09\u661f\u96fb\u8996\uff1a{model}", diff --git a/homeassistant/components/scsgate/__init__.py b/homeassistant/components/scsgate/__init__.py index 71a439fe6f9..f64106049de 100644 --- a/homeassistant/components/scsgate/__init__.py +++ b/homeassistant/components/scsgate/__init__.py @@ -139,7 +139,7 @@ class SCSGate: def is_device_registered(self, device_id): """Check whether a device is already registered or not.""" with self._devices_to_register_lock: - if device_id in self._devices_to_register.keys(): + if device_id in self._devices_to_register: return False with self._device_being_registered_lock: diff --git a/homeassistant/components/scsgate/cover.py b/homeassistant/components/scsgate/cover.py index e5442226d80..2b7615bb780 100644 --- a/homeassistant/components/scsgate/cover.py +++ b/homeassistant/components/scsgate/cover.py @@ -27,7 +27,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): scsgate = hass.data[DOMAIN] if devices: - for _, entity_info in devices.items(): + for entity_info in devices.values(): if entity_info[CONF_SCS_ID] in scsgate.devices: continue diff --git a/homeassistant/components/scsgate/light.py b/homeassistant/components/scsgate/light.py index 949041534a8..cf5488c132e 100644 --- a/homeassistant/components/scsgate/light.py +++ b/homeassistant/components/scsgate/light.py @@ -23,7 +23,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): scsgate = hass.data[DOMAIN] if devices: - for _, entity_info in devices.items(): + for entity_info in devices.values(): if entity_info[CONF_SCS_ID] in scsgate.devices: continue diff --git a/homeassistant/components/scsgate/switch.py b/homeassistant/components/scsgate/switch.py index da69eb0b058..f5719aa24dc 100644 --- a/homeassistant/components/scsgate/switch.py +++ b/homeassistant/components/scsgate/switch.py @@ -42,7 +42,7 @@ def _setup_traditional_switches(logger, config, scsgate, add_entities_callback): switches = [] if traditional: - for _, entity_info in traditional.items(): + for entity_info in traditional.values(): if entity_info[CONF_SCS_ID] in scsgate.devices: continue @@ -65,7 +65,7 @@ def _setup_scenario_switches(logger, config, scsgate, hass): scenario = config.get(CONF_SCENARIO) if scenario: - for _, entity_info in scenario.items(): + for entity_info in scenario.values(): if entity_info[CONF_SCS_ID] in scsgate.devices: continue diff --git a/homeassistant/components/search/__init__.py b/homeassistant/components/search/__init__.py index a3bbd3844aa..81e33aa24b5 100644 --- a/homeassistant/components/search/__init__.py +++ b/homeassistant/components/search/__init__.py @@ -122,6 +122,10 @@ class Searcher: """Resolve an area.""" for device in device_registry.async_entries_for_area(self._device_reg, area_id): self._add_or_resolve("device", device.id) + for entity_entry in entity_registry.async_entries_for_area( + self._entity_reg, area_id + ): + self._add_or_resolve("entity", entity_entry.entity_id) @callback def _resolve_device(self, device_id) -> None: diff --git a/homeassistant/components/sense/binary_sensor.py b/homeassistant/components/sense/binary_sensor.py index 62fe0d01d4e..bc06721ae5e 100644 --- a/homeassistant/components/sense/binary_sensor.py +++ b/homeassistant/components/sense/binary_sensor.py @@ -133,6 +133,9 @@ class SenseDevice(BinarySensorEntity): @callback def _async_update_from_data(self): """Get the latest data, update state. Must not do I/O.""" + new_state = bool(self._sense_devices_data.get_device_by_id(self._id)) + if self._available and self._state == new_state: + return self._available = True - self._state = bool(self._sense_devices_data.get_device_by_id(self._id)) + self._state = new_state self.async_write_ha_state() diff --git a/homeassistant/components/sense/sensor.py b/homeassistant/components/sense/sensor.py index 197168f9199..25fa5943bd5 100644 --- a/homeassistant/components/sense/sensor.py +++ b/homeassistant/components/sense/sensor.py @@ -195,11 +195,14 @@ class SenseActiveSensor(Entity): @callback def _async_update_from_data(self): """Update the sensor from the data. Must not do I/O.""" - self._state = round( + new_state = round( self._data.active_solar_power if self._is_production else self._data.active_power ) + if self._available and self._state == new_state: + return + self._state = new_state self._available = True self.async_write_ha_state() @@ -276,8 +279,11 @@ class SenseVoltageSensor(Entity): @callback def _async_update_from_data(self): """Update the sensor from the data. Must not do I/O.""" - self._state = round(self._data.active_voltage[self._voltage_index], 1) + new_state = round(self._data.active_voltage[self._voltage_index], 1) + if self._available and self._state == new_state: + return self._available = True + self._state = new_state self.async_write_ha_state() @@ -438,8 +444,11 @@ class SenseEnergyDevice(Entity): """Get the latest data, update state. Must not do I/O.""" device_data = self._sense_devices_data.get_device_by_id(self._id) if not device_data or "w" not in device_data: - self._state = 0 + new_state = 0 else: - self._state = int(device_data["w"]) + new_state = int(device_data["w"]) + if self._available and self._state == new_state: + return + self._state = new_state self._available = True self.async_write_ha_state() diff --git a/homeassistant/components/sense/translations/et.json b/homeassistant/components/sense/translations/et.json index ce3dbf463d0..aec4f3655a5 100644 --- a/homeassistant/components/sense/translations/et.json +++ b/homeassistant/components/sense/translations/et.json @@ -11,8 +11,10 @@ "step": { "user": { "data": { + "email": "E-post", "password": "Salas\u00f5na" - } + }, + "title": "\u00dchendu oma Sense Energy Monitor'iga" } } } diff --git a/homeassistant/components/sense/translations/lb.json b/homeassistant/components/sense/translations/lb.json index 3627eb72dab..a71e6ceac9b 100644 --- a/homeassistant/components/sense/translations/lb.json +++ b/homeassistant/components/sense/translations/lb.json @@ -4,8 +4,8 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9iert w.e.g. nach emol.", - "invalid_auth": "Ong\u00eblteg Authentifikatiouns", + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, "step": { diff --git a/homeassistant/components/sense/translations/no.json b/homeassistant/components/sense/translations/no.json index 7fdf326e868..ec9502eed23 100644 --- a/homeassistant/components/sense/translations/no.json +++ b/homeassistant/components/sense/translations/no.json @@ -14,7 +14,7 @@ "email": "E-post", "password": "Passord" }, - "title": "Koble til din Sense Energi Monitor" + "title": "Koble til din Sense Energy Monitor" } } } diff --git a/homeassistant/components/sensor/translations/no.json b/homeassistant/components/sensor/translations/no.json index e957aef5b87..b3e8dc199f6 100644 --- a/homeassistant/components/sensor/translations/no.json +++ b/homeassistant/components/sensor/translations/no.json @@ -2,8 +2,8 @@ "device_automation": { "condition_type": { "is_battery_level": "Gjeldende {entity_name} batteriniv\u00e5", - "is_current": "Gjeldende {entity_name} gjeldende", - "is_energy": "Gjeldende {entity_name} energi", + "is_current": "Gjeldende {entity_name} str\u00f8m", + "is_energy": "Gjeldende {entity_name} effekt", "is_humidity": "Gjeldende {entity_name} fuktighet", "is_illuminance": "Gjeldende {entity_name} belysningsstyrke", "is_power": "Gjeldende {entity_name}-effekt", @@ -13,12 +13,12 @@ "is_temperature": "Gjeldende {entity_name} temperatur", "is_timestamp": "Gjeldende {entity_name} tidsstempel", "is_value": "Gjeldende {entity_name} verdi", - "is_voltage": "Gjeldende spenning p\u00e5 {entity_name}" + "is_voltage": "Gjeldende {entity_name} spenning" }, "trigger_type": { "battery_level": "{entity_name} batteriniv\u00e5 endres", "current": "{entity_name} gjeldende endringer", - "energy": "{entity_name} energiendringer", + "energy": "{entity_name} effektendringer", "humidity": "{entity_name} fuktighets endringer", "illuminance": "{entity_name} belysningsstyrke endringer", "power": "{entity_name} effektendringer", diff --git a/homeassistant/components/sensor/translations/pl.json b/homeassistant/components/sensor/translations/pl.json index aa2d9f4ca11..a8fb604cc53 100644 --- a/homeassistant/components/sensor/translations/pl.json +++ b/homeassistant/components/sensor/translations/pl.json @@ -2,23 +2,23 @@ "device_automation": { "condition_type": { "is_battery_level": "obecny poziom na\u0142adowania baterii {entity_name}", - "is_current": "Bie\u017c\u0105cy pr\u0105d {entity_name}", - "is_energy": "Bie\u017c\u0105ca energia {entity_name}", + "is_current": "obecne nat\u0119\u017cenie pr\u0105du {entity_name}", + "is_energy": "obecna energia {entity_name}", "is_humidity": "obecna wilgotno\u015b\u0107 {entity_name}", "is_illuminance": "obecne nat\u0119\u017cenie o\u015bwietlenia {entity_name}", "is_power": "obecna moc {entity_name}", - "is_power_factor": "Bie\u017c\u0105cy wsp\u00f3\u0142czynnik mocy {entity_name}", + "is_power_factor": "obecny wsp\u00f3\u0142czynnik mocy {entity_name}", "is_pressure": "obecne ci\u015bnienie {entity_name}", "is_signal_strength": "obecna si\u0142a sygna\u0142u {entity_name}", "is_temperature": "obecna temperatura {entity_name}", "is_timestamp": "obecny znacznik czasu {entity_name}", "is_value": "obecna warto\u015b\u0107 {entity_name}", - "is_voltage": "Bie\u017c\u0105ce napi\u0119cie {entity_name}" + "is_voltage": "obecne napi\u0119cie {entity_name}" }, "trigger_type": { "battery_level": "zmieni si\u0119 poziom baterii {entity_name}", "current": "zmieni si\u0119 nat\u0119\u017cenie pr\u0105du w {entity_name}", - "energy": "zmieni si\u0119 moc pr\u0105du w {entity_name}", + "energy": "zmieni si\u0119 energia {entity_name}", "humidity": "zmieni si\u0119 wilgotno\u015b\u0107 {entity_name}", "illuminance": "zmieni si\u0119 nat\u0119\u017cenie o\u015bwietlenia {entity_name}", "power": "zmieni si\u0119 moc {entity_name}", diff --git a/homeassistant/components/sentry/manifest.json b/homeassistant/components/sentry/manifest.json index 6a79e2bad5d..1257c60e75a 100644 --- a/homeassistant/components/sentry/manifest.json +++ b/homeassistant/components/sentry/manifest.json @@ -3,6 +3,6 @@ "name": "Sentry", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/sentry", - "requirements": ["sentry-sdk==0.19.1"], + "requirements": ["sentry-sdk==0.19.2"], "codeowners": ["@dcramer", "@frenck"] } diff --git a/homeassistant/components/sentry/translations/ca.json b/homeassistant/components/sentry/translations/ca.json index 7b24dba7c77..25d5a5bf37e 100644 --- a/homeassistant/components/sentry/translations/ca.json +++ b/homeassistant/components/sentry/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry ja est\u00e0 configurat", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "error": { diff --git a/homeassistant/components/sentry/translations/cs.json b/homeassistant/components/sentry/translations/cs.json index 0906281270c..ad96aeba53c 100644 --- a/homeassistant/components/sentry/translations/cs.json +++ b/homeassistant/components/sentry/translations/cs.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry je ji\u017e nastaveno", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "error": { diff --git a/homeassistant/components/sentry/translations/da.json b/homeassistant/components/sentry/translations/da.json index c84a80d0ccb..689bdad67ac 100644 --- a/homeassistant/components/sentry/translations/da.json +++ b/homeassistant/components/sentry/translations/da.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured": "Sentry er allerede konfigureret" - }, "error": { "bad_dsn": "Ugyldigt DSN", "unknown": "Uventet fejl" diff --git a/homeassistant/components/sentry/translations/de.json b/homeassistant/components/sentry/translations/de.json index 6e6d640cd45..c36bbf258b0 100644 --- a/homeassistant/components/sentry/translations/de.json +++ b/homeassistant/components/sentry/translations/de.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured": "Sentry ist bereits konfiguriert" - }, "error": { "bad_dsn": "Ung\u00fcltiger DSN", "unknown": "Unerwarteter Fehler" diff --git a/homeassistant/components/sentry/translations/en.json b/homeassistant/components/sentry/translations/en.json index 9ffeb30000b..f00116c85d9 100644 --- a/homeassistant/components/sentry/translations/en.json +++ b/homeassistant/components/sentry/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry is already configured", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "error": { diff --git a/homeassistant/components/sentry/translations/es-419.json b/homeassistant/components/sentry/translations/es-419.json index 7d207a3d5f2..dd6866f7610 100644 --- a/homeassistant/components/sentry/translations/es-419.json +++ b/homeassistant/components/sentry/translations/es-419.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured": "Sentry ya est\u00e1 configurado" - }, "error": { "bad_dsn": "DSN inv\u00e1lido", "unknown": "Error inesperado" diff --git a/homeassistant/components/sentry/translations/es.json b/homeassistant/components/sentry/translations/es.json index 47caae6c541..a2b5cc31f9a 100644 --- a/homeassistant/components/sentry/translations/es.json +++ b/homeassistant/components/sentry/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry ya est\u00e1 configurado", "single_instance_allowed": "Ya configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "error": { diff --git a/homeassistant/components/sentry/translations/et.json b/homeassistant/components/sentry/translations/et.json index ac75dd8fb6d..5c501b2b0aa 100644 --- a/homeassistant/components/sentry/translations/et.json +++ b/homeassistant/components/sentry/translations/et.json @@ -1,16 +1,36 @@ { "config": { "abort": { - "already_configured": "Sentry on juba h\u00e4\u00e4lestatud", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "error": { + "bad_dsn": "Kehtetu DSN", "unknown": "Ootamatu t\u00f5rge" }, "step": { "user": { + "data": { + "dsn": "" + }, + "description": "Sisesta oma Sentry DSN", "title": "" } } + }, + "options": { + "step": { + "init": { + "data": { + "environment": "Keskkonna valikuline nimi.", + "event_custom_components": "S\u00fcndmuste saatmine kohandatud komponentidest", + "event_handled": "K\u00e4ivitatud s\u00fcndmuste saatmine", + "event_third_party_packages": "S\u00fcndmuste saatmine kolmanda osapoole pakettidest", + "logging_event_level": "M\u00e4\u00e4ra Sentry s\u00fcndmuse logitase", + "logging_level": "M\u00e4\u00e4ra Sentry andme\u00fchikute logitase", + "tracing": "Luba j\u00f5udluse j\u00e4lgimine", + "tracing_sample_rate": "J\u00e4lgimise sagedus: vahemikus 0,0 kuni 1,0 (1,0 = 100%)" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/sentry/translations/fr.json b/homeassistant/components/sentry/translations/fr.json index 073a3cd0963..913da4b373d 100644 --- a/homeassistant/components/sentry/translations/fr.json +++ b/homeassistant/components/sentry/translations/fr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry est d\u00e9j\u00e0 configur\u00e9", "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { diff --git a/homeassistant/components/sentry/translations/hu.json b/homeassistant/components/sentry/translations/hu.json index d79de976a83..64ee672a02f 100644 --- a/homeassistant/components/sentry/translations/hu.json +++ b/homeassistant/components/sentry/translations/hu.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured": "Az Sentry m\u00e1r konfigur\u00e1lva van" - }, "error": { "bad_dsn": "\u00c9rv\u00e9nytelen DSN", "unknown": "V\u00e1ratlan hiba" diff --git a/homeassistant/components/sentry/translations/it.json b/homeassistant/components/sentry/translations/it.json index 2f022129022..8386f78afa2 100644 --- a/homeassistant/components/sentry/translations/it.json +++ b/homeassistant/components/sentry/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry \u00e8 gi\u00e0 configurato", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "error": { diff --git a/homeassistant/components/sentry/translations/ko.json b/homeassistant/components/sentry/translations/ko.json index f3adbefa3d7..963695dabfd 100644 --- a/homeassistant/components/sentry/translations/ko.json +++ b/homeassistant/components/sentry/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured": "Sentry \uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "error": { "bad_dsn": "DSN \uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "unknown": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" diff --git a/homeassistant/components/sentry/translations/lb.json b/homeassistant/components/sentry/translations/lb.json index 169461e52f7..3041a7eb156 100644 --- a/homeassistant/components/sentry/translations/lb.json +++ b/homeassistant/components/sentry/translations/lb.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry ass scho konfigur\u00e9iert", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { diff --git a/homeassistant/components/sentry/translations/nl.json b/homeassistant/components/sentry/translations/nl.json index 779c62dca22..37437dfe836 100644 --- a/homeassistant/components/sentry/translations/nl.json +++ b/homeassistant/components/sentry/translations/nl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry is al geconfigureerd", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "error": { diff --git a/homeassistant/components/sentry/translations/no.json b/homeassistant/components/sentry/translations/no.json index 6048bde74e1..31f4ef30d12 100644 --- a/homeassistant/components/sentry/translations/no.json +++ b/homeassistant/components/sentry/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry er allerede konfigurert", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "error": { diff --git a/homeassistant/components/sentry/translations/pl.json b/homeassistant/components/sentry/translations/pl.json index 7c82528efb6..497d4f3c7ae 100644 --- a/homeassistant/components/sentry/translations/pl.json +++ b/homeassistant/components/sentry/translations/pl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Us\u0142uga jest ju\u017c skonfigurowana", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "error": { diff --git a/homeassistant/components/sentry/translations/pt-BR.json b/homeassistant/components/sentry/translations/pt-BR.json index bf8bc5ef72e..b4f025eaf6d 100644 --- a/homeassistant/components/sentry/translations/pt-BR.json +++ b/homeassistant/components/sentry/translations/pt-BR.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured": "O Sentry j\u00e1 est\u00e1 configurado" - }, "error": { "bad_dsn": "DSN inv\u00e1lido", "unknown": "Erro inesperado" diff --git a/homeassistant/components/sentry/translations/ru.json b/homeassistant/components/sentry/translations/ru.json index ab8023e505c..eb6cbd0310c 100644 --- a/homeassistant/components/sentry/translations/ru.json +++ b/homeassistant/components/sentry/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "error": { diff --git a/homeassistant/components/sentry/translations/sl.json b/homeassistant/components/sentry/translations/sl.json index 114eaa6c9f9..5a448c5b673 100644 --- a/homeassistant/components/sentry/translations/sl.json +++ b/homeassistant/components/sentry/translations/sl.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured": "Sentry je \u017ee nastavljen" - }, "error": { "bad_dsn": "Neveljaven DSN", "unknown": "Nepri\u010dakovana napaka" diff --git a/homeassistant/components/sentry/translations/sv.json b/homeassistant/components/sentry/translations/sv.json index 1d07a82818c..d04ea24b72a 100644 --- a/homeassistant/components/sentry/translations/sv.json +++ b/homeassistant/components/sentry/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured": "Sentry har redan konfigurerats" - }, "error": { "bad_dsn": "Ogiltig DSN", "unknown": "Ov\u00e4ntat fel" diff --git a/homeassistant/components/sentry/translations/zh-Hant.json b/homeassistant/components/sentry/translations/zh-Hant.json index 5c77442a03e..a63efaf6dc2 100644 --- a/homeassistant/components/sentry/translations/zh-Hant.json +++ b/homeassistant/components/sentry/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Sentry \u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "error": { diff --git a/homeassistant/components/sharkiq/translations/ca.json b/homeassistant/components/sharkiq/translations/ca.json index d707ebded59..9ae6a703835 100644 --- a/homeassistant/components/sharkiq/translations/ca.json +++ b/homeassistant/components/sharkiq/translations/ca.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "El compte ja ha estat configurat", - "already_configured_account": "El compte ja ha estat configurat", "cannot_connect": "Ha fallat la connexi\u00f3", "reauth_successful": "Re-autenticaci\u00f3 realitzada correctament", "unknown": "Error inesperat" diff --git a/homeassistant/components/sharkiq/translations/cs.json b/homeassistant/components/sharkiq/translations/cs.json index 0d01e11bc6b..6569221a679 100644 --- a/homeassistant/components/sharkiq/translations/cs.json +++ b/homeassistant/components/sharkiq/translations/cs.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "\u00da\u010det je ji\u017e nastaven", - "already_configured_account": "\u00da\u010det je ji\u017e nastaven", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "reauth_successful": "Op\u011btovn\u00e9 ov\u011b\u0159en\u00ed bylo \u00fasp\u011b\u0161n\u00e9", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" diff --git a/homeassistant/components/sharkiq/translations/en.json b/homeassistant/components/sharkiq/translations/en.json index 3f663270dc4..a8a9bf2d0a2 100644 --- a/homeassistant/components/sharkiq/translations/en.json +++ b/homeassistant/components/sharkiq/translations/en.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Account is already configured", - "already_configured_account": "Account is already configured", "cannot_connect": "Failed to connect", "reauth_successful": "Re-authentication was successful", "unknown": "Unexpected error" diff --git a/homeassistant/components/sharkiq/translations/es.json b/homeassistant/components/sharkiq/translations/es.json index 2bf2e2baf5b..951537484bc 100644 --- a/homeassistant/components/sharkiq/translations/es.json +++ b/homeassistant/components/sharkiq/translations/es.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured_account": "La cuenta ya ha sido configurada", + "already_configured": "La cuenta ya est\u00e1 configurada", "cannot_connect": "No se pudo conectar", "reauth_successful": "La reautenticaci\u00f3n se realiz\u00f3 correctamente", "unknown": "Error inesperado" diff --git a/homeassistant/components/sharkiq/translations/et.json b/homeassistant/components/sharkiq/translations/et.json index 5eb8926aa80..40856f6c5de 100644 --- a/homeassistant/components/sharkiq/translations/et.json +++ b/homeassistant/components/sharkiq/translations/et.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Konto on juba seadistatud", - "already_configured_account": "Konto on juba seadistatud", "cannot_connect": "\u00dchendamine nurjus", "reauth_successful": "Taastuvastus oli edukas", "unknown": "Tundmatu viga" diff --git a/homeassistant/components/sharkiq/translations/fr.json b/homeassistant/components/sharkiq/translations/fr.json index b867170a4d2..5f05292ec2a 100644 --- a/homeassistant/components/sharkiq/translations/fr.json +++ b/homeassistant/components/sharkiq/translations/fr.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured_account": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", + "already_configured": "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", "unknown": "Erreur inattendue" diff --git a/homeassistant/components/sharkiq/translations/hu.json b/homeassistant/components/sharkiq/translations/hu.json deleted file mode 100644 index 9f2fd5d72f4..00000000000 --- a/homeassistant/components/sharkiq/translations/hu.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "abort": { - "already_configured_account": "A fi\u00f3k m\u00e1r konfigur\u00e1lva van" - } - } -} \ No newline at end of file diff --git a/homeassistant/components/sharkiq/translations/it.json b/homeassistant/components/sharkiq/translations/it.json index cb2b85e4d3e..4f7940cb5fc 100644 --- a/homeassistant/components/sharkiq/translations/it.json +++ b/homeassistant/components/sharkiq/translations/it.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured_account": "L'account \u00e8 gi\u00e0 configurato", + "already_configured": "L'account \u00e8 gi\u00e0 configurato", "cannot_connect": "Impossibile connettersi", "reauth_successful": "La riautenticazione ha avuto successo", "unknown": "Errore imprevisto" diff --git a/homeassistant/components/sharkiq/translations/ko.json b/homeassistant/components/sharkiq/translations/ko.json index d7e196c09fb..92649031534 100644 --- a/homeassistant/components/sharkiq/translations/ko.json +++ b/homeassistant/components/sharkiq/translations/ko.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured_account": "\uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.", "cannot_connect": "\uc5f0\uacb0 \uc2e4\ud328", "reauth_successful": "\uc561\uc138\uc2a4 \ud1a0\ud070\uc774 \uc131\uacf5\uc801\uc73c\ub85c \uc5c5\ub370\uc774\ud2b8\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "unknown": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc5d0\ub7ec" diff --git a/homeassistant/components/sharkiq/translations/lb.json b/homeassistant/components/sharkiq/translations/lb.json index 1da09e6b8ec..10c8b512dec 100644 --- a/homeassistant/components/sharkiq/translations/lb.json +++ b/homeassistant/components/sharkiq/translations/lb.json @@ -1,7 +1,10 @@ { "config": { "abort": { - "cannot_connect": "Feeler beim verbannen" + "already_configured": "Kont ass scho konfigur\u00e9iert", + "cannot_connect": "Feeler beim verbannen", + "reauth_successful": "Re-authentifikatioun war erfollegr\u00e4ich", + "unknown": "Onerwaarte Feeler" }, "error": { "cannot_connect": "Feeler beim verbannen", diff --git a/homeassistant/components/sharkiq/translations/nl.json b/homeassistant/components/sharkiq/translations/nl.json index 36d65ba63fc..96c10f3e2f0 100644 --- a/homeassistant/components/sharkiq/translations/nl.json +++ b/homeassistant/components/sharkiq/translations/nl.json @@ -1,11 +1,14 @@ { "config": { "abort": { - "already_configured_account": "Account is al geconfigureerd", - "cannot_connect": "Kan geen verbinding maken" + "already_configured": "Account is al geconfigureerd", + "cannot_connect": "Kan geen verbinding maken", + "unknown": "Onverwachte fout" }, "error": { - "cannot_connect": "Kan geen verbinding maken" + "cannot_connect": "Kan geen verbinding maken", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" }, "step": { "reauth": { diff --git a/homeassistant/components/sharkiq/translations/no.json b/homeassistant/components/sharkiq/translations/no.json index 32facb073d5..d04e5796542 100644 --- a/homeassistant/components/sharkiq/translations/no.json +++ b/homeassistant/components/sharkiq/translations/no.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Kontoen er allerede konfigurert", - "already_configured_account": "Kontoen er allerede konfigurert", "cannot_connect": "Tilkobling mislyktes", "reauth_successful": "Reautentisering var vellykket", "unknown": "Uventet feil" diff --git a/homeassistant/components/sharkiq/translations/pl.json b/homeassistant/components/sharkiq/translations/pl.json index 46b8a54d540..17b3f801807 100644 --- a/homeassistant/components/sharkiq/translations/pl.json +++ b/homeassistant/components/sharkiq/translations/pl.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Konto jest ju\u017c skonfigurowane", - "already_configured_account": "Konto jest ju\u017c skonfigurowane", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "reauth_successful": "Ponowne uwierzytelnienie powiod\u0142o si\u0119", "unknown": "Nieoczekiwany b\u0142\u0105d" diff --git a/homeassistant/components/sharkiq/translations/pt.json b/homeassistant/components/sharkiq/translations/pt.json index 973b6681d31..565b9f6c0e8 100644 --- a/homeassistant/components/sharkiq/translations/pt.json +++ b/homeassistant/components/sharkiq/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "already_configured_account": "Conta j\u00e1 configurada" - }, "error": { "cannot_connect": "Falha na liga\u00e7\u00e3o", "invalid_auth": "Autentica\u00e7\u00e3o inv\u00e1lida", diff --git a/homeassistant/components/sharkiq/translations/ru.json b/homeassistant/components/sharkiq/translations/ru.json index 8d0d11b7ffa..80af08a8958 100644 --- a/homeassistant/components/sharkiq/translations/ru.json +++ b/homeassistant/components/sharkiq/translations/ru.json @@ -2,7 +2,6 @@ "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.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "reauth_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." diff --git a/homeassistant/components/sharkiq/translations/zh-Hant.json b/homeassistant/components/sharkiq/translations/zh-Hant.json index 09aa01b73ec..f788367b702 100644 --- a/homeassistant/components/sharkiq/translations/zh-Hant.json +++ b/homeassistant/components/sharkiq/translations/zh-Hant.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "already_configured_account": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "cannot_connect": "\u9023\u7dda\u5931\u6557", "reauth_successful": "\u91cd\u65b0\u8a8d\u8b49\u6210\u529f", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" diff --git a/homeassistant/components/sharkiq/update_coordinator.py b/homeassistant/components/sharkiq/update_coordinator.py index 0651d0765cf..eff18064dcc 100644 --- a/homeassistant/components/sharkiq/update_coordinator.py +++ b/homeassistant/components/sharkiq/update_coordinator.py @@ -74,7 +74,7 @@ class SharkIqUpdateCoordinator(DataUpdateCoordinator): SharkIqNotAuthedError, SharkIqAuthExpiringError, ) as err: - _LOGGER.exception("Bad auth state") + _LOGGER.debug("Bad auth state. Attempting re-auth", exc_info=err) flow_context = { "source": "reauth", "unique_id": self._config_entry.unique_id, @@ -87,6 +87,7 @@ class SharkIqUpdateCoordinator(DataUpdateCoordinator): ] if not matching_flows: + _LOGGER.debug("Re-initializing flows. Attempting re-auth") self.hass.async_create_task( self.hass.config_entries.flow.async_init( DOMAIN, @@ -94,6 +95,8 @@ class SharkIqUpdateCoordinator(DataUpdateCoordinator): data=self._config_entry.data, ) ) + else: + _LOGGER.debug("Matching flow found") raise UpdateFailed(err) from err except Exception as err: # pylint: disable=broad-except diff --git a/homeassistant/components/shell_command/__init__.py b/homeassistant/components/shell_command/__init__.py index 0d221cb6b0b..1173d0477ab 100644 --- a/homeassistant/components/shell_command/__init__.py +++ b/homeassistant/components/shell_command/__init__.py @@ -114,6 +114,6 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: "Error running command: `%s`, return code: %s", cmd, process.returncode ) - for name in conf.keys(): + for name in conf: hass.services.async_register(DOMAIN, name, async_service_handler) return True diff --git a/homeassistant/components/shelly/__init__.py b/homeassistant/components/shelly/__init__.py index 628ee5a53cc..1f6ecdbd031 100644 --- a/homeassistant/components/shelly/__init__.py +++ b/homeassistant/components/shelly/__init__.py @@ -2,8 +2,8 @@ import asyncio from datetime import timedelta import logging +from socket import gethostbyname -import aiocoap import aioshelly import async_timeout @@ -14,44 +14,66 @@ from homeassistant.const import ( CONF_USERNAME, EVENT_HOMEASSISTANT_STOP, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady -from homeassistant.helpers import aiohttp_client, device_registry, update_coordinator +from homeassistant.helpers import ( + aiohttp_client, + device_registry, + singleton, + update_coordinator, +) -from .const import COAP_CONTEXT, DATA_CONFIG_ENTRY, DOMAIN +from .const import ( + DATA_CONFIG_ENTRY, + DOMAIN, + POLLING_TIMEOUT_MULTIPLIER, + SETUP_ENTRY_TIMEOUT_SEC, + SLEEP_PERIOD_MULTIPLIER, + UPDATE_PERIOD_MULTIPLIER, +) PLATFORMS = ["binary_sensor", "cover", "light", "sensor", "switch"] _LOGGER = logging.getLogger(__name__) -async def async_setup(hass: HomeAssistant, config: dict): - """Set up the Shelly component.""" - hass.data[DOMAIN] = {DATA_CONFIG_ENTRY: {}} - hass.data[DOMAIN][COAP_CONTEXT] = await aiocoap.Context.create_client_context() +@singleton.singleton("shelly_coap") +async def get_coap_context(hass): + """Get CoAP context to be used in all Shelly devices.""" + context = aioshelly.COAP() + await context.initialize() - async def shutdown_listener(*_): - """Home Assistant shutdown listener.""" - await hass.data[DOMAIN][COAP_CONTEXT].shutdown() + @callback + def shutdown_listener(ev): + context.close() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, shutdown_listener) + return context + + +async def async_setup(hass: HomeAssistant, config: dict): + """Set up the Shelly component.""" + hass.data[DOMAIN] = {DATA_CONFIG_ENTRY: {}} return True async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): """Set up Shelly from a config entry.""" temperature_unit = "C" if hass.config.units.is_metric else "F" + + ip_address = await hass.async_add_executor_job(gethostbyname, entry.data[CONF_HOST]) + options = aioshelly.ConnectionOptions( - entry.data[CONF_HOST], + ip_address, entry.data.get(CONF_USERNAME), entry.data.get(CONF_PASSWORD), temperature_unit, ) - coap_context = hass.data[DOMAIN][COAP_CONTEXT] + coap_context = await get_coap_context(hass) try: - async with async_timeout.timeout(10): + async with async_timeout.timeout(SETUP_ENTRY_TIMEOUT_SEC): device = await aioshelly.Device.create( aiohttp_client.async_get_clientsession(hass), coap_context, @@ -78,23 +100,43 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator): def __init__(self, hass, entry, device: aioshelly.Device): """Initialize the Shelly device wrapper.""" + sleep_mode = device.settings.get("sleep_mode") + + if sleep_mode: + sleep_period = sleep_mode["period"] + if sleep_mode["unit"] == "h": + sleep_period *= 60 # hours to minutes + + update_interval = ( + SLEEP_PERIOD_MULTIPLIER * sleep_period * 60 + ) # minutes to seconds + else: + update_interval = ( + UPDATE_PERIOD_MULTIPLIER * device.settings["coiot"]["update_period"] + ) + super().__init__( hass, _LOGGER, name=device.settings["name"] or device.settings["device"]["hostname"], - update_interval=timedelta(seconds=5), + update_interval=timedelta(seconds=update_interval), ) self.hass = hass self.entry = entry self.device = device + self.device.subscribe_updates(self.async_set_updated_data) + async def _async_update_data(self): """Fetch data.""" - + _LOGGER.debug("Polling Shelly Device - %s", self.name) try: - async with async_timeout.timeout(5): + async with async_timeout.timeout( + POLLING_TIMEOUT_MULTIPLIER + * self.device.settings["coiot"]["update_period"] + ): return await self.device.update() - except (aiocoap.error.Error, OSError) as err: + except OSError as err: raise update_coordinator.UpdateFailed("Error fetching data") from err @property @@ -122,6 +164,10 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator): sw_version=self.device.settings["fw"], ) + def shutdown(self): + """Shutdown the wrapper.""" + self.device.shutdown() + async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unload a config entry.""" @@ -134,6 +180,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): ) ) if unload_ok: - hass.data[DOMAIN][DATA_CONFIG_ENTRY].pop(entry.entry_id) + hass.data[DOMAIN][DATA_CONFIG_ENTRY].pop(entry.entry_id).shutdown() return unload_ok diff --git a/homeassistant/components/shelly/config_flow.py b/homeassistant/components/shelly/config_flow.py index 9076d5b7338..88e01f04bc5 100644 --- a/homeassistant/components/shelly/config_flow.py +++ b/homeassistant/components/shelly/config_flow.py @@ -1,8 +1,8 @@ """Config flow for Shelly integration.""" import asyncio import logging +from socket import gethostbyname -import aiocoap import aiohttp import aioshelly import async_timeout @@ -17,6 +17,7 @@ from homeassistant.const import ( ) from homeassistant.helpers import aiohttp_client +from . import get_coap_context from .const import DOMAIN # pylint:disable=unused-import _LOGGER = logging.getLogger(__name__) @@ -37,10 +38,13 @@ async def validate_input(hass: core.HomeAssistant, host, data): Data has the keys from DATA_SCHEMA with values provided by the user. """ + ip_address = await hass.async_add_executor_job(gethostbyname, host) + options = aioshelly.ConnectionOptions( - host, data.get(CONF_USERNAME), data.get(CONF_PASSWORD) + ip_address, data.get(CONF_USERNAME), data.get(CONF_PASSWORD) ) - coap_context = await aiocoap.Context.create_client_context() + coap_context = await get_coap_context(hass) + async with async_timeout.timeout(5): device = await aioshelly.Device.create( aiohttp_client.async_get_clientsession(hass), @@ -48,7 +52,7 @@ async def validate_input(hass: core.HomeAssistant, host, data): options, ) - await coap_context.shutdown() + device.shutdown() # Return info that you want to store in the config entry. return { diff --git a/homeassistant/components/shelly/const.py b/homeassistant/components/shelly/const.py index b40ada04b30..50af82c2b7d 100644 --- a/homeassistant/components/shelly/const.py +++ b/homeassistant/components/shelly/const.py @@ -1,5 +1,16 @@ """Constants for the Shelly integration.""" -COAP_CONTEXT = "coap_context" DATA_CONFIG_ENTRY = "config_entry" DOMAIN = "shelly" + +# Used to calculate the timeout in "_async_update_data" used for polling data from devices. +POLLING_TIMEOUT_MULTIPLIER = 1.2 + +# Timeout used for initial entry setup in "async_setup_entry". +SETUP_ENTRY_TIMEOUT_SEC = 10 + +# Multiplier used to calculate the "update_interval" for sleeping devices. +SLEEP_PERIOD_MULTIPLIER = 1.2 + +# Multiplier used to calculate the "update_interval" for non-sleeping devices. +UPDATE_PERIOD_MULTIPLIER = 2.2 diff --git a/homeassistant/components/shelly/entity.py b/homeassistant/components/shelly/entity.py index 8af95c0fb33..314ee48cf7e 100644 --- a/homeassistant/components/shelly/entity.py +++ b/homeassistant/components/shelly/entity.py @@ -1,63 +1,15 @@ """Shelly entity helper.""" -from collections import Counter from dataclasses import dataclass from typing import Any, Callable, Optional, Union import aioshelly -from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT from homeassistant.core import callback from homeassistant.helpers import device_registry, entity from . import ShellyDeviceWrapper from .const import DATA_CONFIG_ENTRY, DOMAIN - - -def temperature_unit(block_info: dict) -> str: - """Detect temperature unit.""" - if block_info[aioshelly.BLOCK_VALUE_UNIT] == "F": - return TEMP_FAHRENHEIT - return TEMP_CELSIUS - - -def shelly_naming(self, block, entity_type: str): - """Naming for switch and sensors.""" - - entity_name = self.wrapper.name - if not block: - return f"{entity_name} {self.description.name}" - - channels = 0 - mode = block.type + "s" - if "num_outputs" in self.wrapper.device.shelly: - channels = self.wrapper.device.shelly["num_outputs"] - if ( - self.wrapper.model in ["SHSW-21", "SHSW-25"] - and self.wrapper.device.settings["mode"] == "roller" - ): - channels = 1 - if block.type == "emeter" and "num_emeters" in self.wrapper.device.shelly: - channels = self.wrapper.device.shelly["num_emeters"] - if channels > 1 and block.type != "device": - # Shelly EM (SHEM) with firmware v1.8.1 doesn't have "name" key; will be fixed in next firmware release - if "name" in self.wrapper.device.settings[mode][int(block.channel)]: - entity_name = self.wrapper.device.settings[mode][int(block.channel)]["name"] - else: - entity_name = None - if not entity_name: - if self.wrapper.model == "SHEM-3": - base = ord("A") - else: - base = ord("1") - entity_name = f"{self.wrapper.name} channel {chr(int(block.channel)+base)}" - - if entity_type == "switch": - return entity_name - - if entity_type == "sensor": - return f"{entity_name} {self.description.name}" - - raise ValueError +from .utils import get_entity_name async def async_setup_entry_attribute_entities( @@ -84,11 +36,9 @@ async def async_setup_entry_attribute_entities( if not blocks: return - counts = Counter([item[1] for item in blocks]) - async_add_entities( [ - sensor_class(wrapper, block, sensor_id, description, counts[sensor_id]) + sensor_class(wrapper, block, sensor_id, description) for block, sensor_id, description in blocks ] ) @@ -117,7 +67,7 @@ class ShellyBlockEntity(entity.Entity): """Initialize Shelly entity.""" self.wrapper = wrapper self.block = block - self._name = shelly_naming(self, block, "switch") + self._name = get_entity_name(wrapper, block) @property def name(self): @@ -169,7 +119,6 @@ class ShellyBlockAttributeEntity(ShellyBlockEntity, entity.Entity): block: aioshelly.Block, attribute: str, description: BlockAttributeDescription, - same_type_count: int, ) -> None: """Initialize sensor.""" super().__init__(wrapper, block) @@ -184,7 +133,7 @@ class ShellyBlockAttributeEntity(ShellyBlockEntity, entity.Entity): self._unit = unit self._unique_id = f"{super().unique_id}-{self.attribute}" - self._name = shelly_naming(self, block, "sensor") + self._name = get_entity_name(wrapper, block, self.description.name) @property def unique_id(self): diff --git a/homeassistant/components/shelly/light.py b/homeassistant/components/shelly/light.py index 85763a51f2a..922d874a4cc 100644 --- a/homeassistant/components/shelly/light.py +++ b/homeassistant/components/shelly/light.py @@ -19,12 +19,29 @@ from homeassistant.util.color import ( from . import ShellyDeviceWrapper from .const import DATA_CONFIG_ENTRY, DOMAIN from .entity import ShellyBlockEntity +from .utils import async_remove_entity_by_domain async def async_setup_entry(hass, config_entry, async_add_entities): """Set up lights for device.""" wrapper = hass.data[DOMAIN][DATA_CONFIG_ENTRY][config_entry.entry_id] - blocks = [block for block in wrapper.device.blocks if block.type == "light"] + + blocks = [] + for block in wrapper.device.blocks: + if block.type == "light": + blocks.append(block) + elif block.type == "relay": + appliance_type = wrapper.device.settings["relays"][int(block.channel)].get( + "appliance_type" + ) + if appliance_type and appliance_type.lower() == "light": + blocks.append(block) + unique_id = ( + f'{wrapper.device.shelly["mac"]}-{block.type}_{block.channel}' + ) + await async_remove_entity_by_domain( + hass, "switch", unique_id, config_entry.entry_id + ) if not blocks: return diff --git a/homeassistant/components/shelly/manifest.json b/homeassistant/components/shelly/manifest.json index 98dcbfda568..00f9620b3c5 100644 --- a/homeassistant/components/shelly/manifest.json +++ b/homeassistant/components/shelly/manifest.json @@ -3,7 +3,7 @@ "name": "Shelly", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/shelly", - "requirements": ["aioshelly==0.4.0"], + "requirements": ["aioshelly==0.5.1"], "zeroconf": [{ "type": "_http._tcp.local.", "name": "shelly*" }], - "codeowners": ["@balloob", "@bieniu"] + "codeowners": ["@balloob", "@bieniu", "@thecode"] } diff --git a/homeassistant/components/shelly/sensor.py b/homeassistant/components/shelly/sensor.py index e82f167ca60..ddd61b6b613 100644 --- a/homeassistant/components/shelly/sensor.py +++ b/homeassistant/components/shelly/sensor.py @@ -15,8 +15,8 @@ from .entity import ( BlockAttributeDescription, ShellyBlockAttributeEntity, async_setup_entry_attribute_entities, - temperature_unit, ) +from .utils import temperature_unit SENSORS = { ("device", "battery"): BlockAttributeDescription( diff --git a/homeassistant/components/shelly/strings.json b/homeassistant/components/shelly/strings.json index 0efceba56a5..6a1cbbd5797 100644 --- a/homeassistant/components/shelly/strings.json +++ b/homeassistant/components/shelly/strings.json @@ -1,10 +1,9 @@ { - "title": "Shelly", "config": { "flow_title": "{name}", "step": { "user": { - "description": "Before set up, the battery-powered device must be woken up by pressing the button on the device.", + "description": "Before set up, battery-powered devices must be woken up by pressing the button on the device.", "data": { "host": "[%key:common::config_flow::data::host%]" } @@ -16,7 +15,7 @@ } }, "confirm_discovery": { - "description": "Do you want to set up the {model} at {host}?\n\nBefore set up, the battery-powered device must be woken up by pressing the button on the device." + "description": "Do you want to set up the {model} at {host}?\n\nBefore set up, battery-powered devices must be woken up by pressing the button on the device." } }, "error": { diff --git a/homeassistant/components/shelly/switch.py b/homeassistant/components/shelly/switch.py index 7d140528858..1f14053929d 100644 --- a/homeassistant/components/shelly/switch.py +++ b/homeassistant/components/shelly/switch.py @@ -7,6 +7,7 @@ from homeassistant.core import callback from . import ShellyDeviceWrapper from .const import DATA_CONFIG_ENTRY, DOMAIN from .entity import ShellyBlockEntity +from .utils import async_remove_entity_by_domain async def async_setup_entry(hass, config_entry, async_add_entities): @@ -20,7 +21,23 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ): return - relay_blocks = [block for block in wrapper.device.blocks if block.type == "relay"] + relay_blocks = [] + for block in wrapper.device.blocks: + if block.type == "relay": + appliance_type = wrapper.device.settings["relays"][int(block.channel)].get( + "appliance_type" + ) + if not appliance_type or appliance_type.lower() != "light": + relay_blocks.append(block) + unique_id = ( + f'{wrapper.device.shelly["mac"]}-{block.type}_{block.channel}' + ) + await async_remove_entity_by_domain( + hass, + "light", + unique_id, + config_entry.entry_id, + ) if not relay_blocks: return diff --git a/homeassistant/components/shelly/translations/ca.json b/homeassistant/components/shelly/translations/ca.json index 6df92102699..2bf17c2ba77 100644 --- a/homeassistant/components/shelly/translations/ca.json +++ b/homeassistant/components/shelly/translations/ca.json @@ -5,7 +5,6 @@ "unsupported_firmware": "El dispositiu utilitza una versi\u00f3 de programari no compatible." }, "error": { - "auth_not_supported": "Actualment els dispositius Shelly amb autenticaci\u00f3 no son compatibles.", "cannot_connect": "Ha fallat la connexi\u00f3", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", "unknown": "Error inesperat" @@ -13,7 +12,7 @@ "flow_title": "{name}", "step": { "confirm_discovery": { - "description": "Vols configurar {model} a {host}? \n\nAbans de configurar-lo, el dispositiu amb bateria ha d'estar despert, prem el bot\u00f3 del dispositiu per despertar-lo." + "description": "Vols configurar el {model} a {host}? \n\nAbans de configurar-lo, els dispositius amb bateria s'han de desperar prement el bot\u00f3 del dispositiu." }, "credentials": { "data": { @@ -25,9 +24,8 @@ "data": { "host": "Amfitri\u00f3" }, - "description": "Abans de configurar-lo, el dispositiu amb bateria ha d'estar despert, prem el bot\u00f3 del dispositiu per despertar-lo." + "description": "Abans de configurar-lo, els dispositius amb bateria s'han de desperar prement el bot\u00f3 del dispositiu." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/cs.json b/homeassistant/components/shelly/translations/cs.json index 3f9397d5cc0..41ca338ab9e 100644 --- a/homeassistant/components/shelly/translations/cs.json +++ b/homeassistant/components/shelly/translations/cs.json @@ -5,7 +5,6 @@ "unsupported_firmware": "Za\u0159\u00edzen\u00ed pou\u017e\u00edv\u00e1 nepodporovanou verzi firmwaru." }, "error": { - "auth_not_supported": "Za\u0159\u00edzen\u00ed Shelly vy\u017eaduj\u00edc\u00ed autentizaci nejsou aktu\u00e1ln\u011b podporov\u00e1na.", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" @@ -28,6 +27,5 @@ "description": "P\u0159ed nastaven\u00edm mus\u00ed b\u00fdt za\u0159\u00edzen\u00ed nap\u00e1jen\u00e9 z baterie probuzeno stisknut\u00edm tla\u010d\u00edtka na dan\u00e9m za\u0159\u00edzen\u00ed." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/de.json b/homeassistant/components/shelly/translations/de.json index aad0d1fa47d..dac21a6af74 100644 --- a/homeassistant/components/shelly/translations/de.json +++ b/homeassistant/components/shelly/translations/de.json @@ -14,6 +14,5 @@ } } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/el.json b/homeassistant/components/shelly/translations/el.json index 753e7ee7505..07355585617 100644 --- a/homeassistant/components/shelly/translations/el.json +++ b/homeassistant/components/shelly/translations/el.json @@ -3,9 +3,6 @@ "abort": { "unsupported_firmware": "\u0397 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b5\u03af \u03bc\u03b9\u03b1 \u03bc\u03b7 \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03b9\u03b6\u03cc\u03bc\u03b5\u03bd\u03b7 \u03ad\u03ba\u03b4\u03bf\u03c3\u03b7 \u03c5\u03bb\u03b9\u03ba\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03bc\u03b9\u03ba\u03bf\u03cd." }, - "error": { - "auth_not_supported": "\u039f\u03b9 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ad\u03c2 Shelly \u03c0\u03bf\u03c5 \u03b1\u03c0\u03b1\u03b9\u03c4\u03bf\u03cd\u03bd \u03ad\u03bb\u03b5\u03b3\u03c7\u03bf \u03c4\u03b1\u03c5\u03c4\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03bf\u03bd\u03c4\u03b1\u03b9 \u03c0\u03c1\u03bf\u03c2 \u03c4\u03bf \u03c0\u03b1\u03c1\u03cc\u03bd." - }, "flow_title": "Shelly: {\u03cc\u03bd\u03bf\u03bc\u03b1}", "step": { "confirm_discovery": { @@ -15,6 +12,5 @@ "description": "\u03a0\u03c1\u03b9\u03bd \u03b1\u03c0\u03cc \u03c4\u03b7 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7, \u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03bc\u03b5 \u03bc\u03c0\u03b1\u03c4\u03b1\u03c1\u03af\u03b1 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03be\u03c5\u03c0\u03bd\u03ae\u03c3\u03b5\u03b9 \u03c0\u03b1\u03c4\u03ce\u03bd\u03c4\u03b1\u03c2 \u03c4\u03bf \u03ba\u03bf\u03c5\u03bc\u03c0\u03af \u03c3\u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/en.json b/homeassistant/components/shelly/translations/en.json index e109a9ac6f3..edb6da27a99 100644 --- a/homeassistant/components/shelly/translations/en.json +++ b/homeassistant/components/shelly/translations/en.json @@ -5,7 +5,6 @@ "unsupported_firmware": "The device is using an unsupported firmware version." }, "error": { - "auth_not_supported": "Shelly devices requiring authentication are not currently supported.", "cannot_connect": "Failed to connect", "invalid_auth": "Invalid authentication", "unknown": "Unexpected error" @@ -13,7 +12,7 @@ "flow_title": "{name}", "step": { "confirm_discovery": { - "description": "Do you want to set up the {model} at {host}?\n\nBefore set up, the battery-powered device must be woken up by pressing the button on the device." + "description": "Do you want to set up the {model} at {host}?\n\nBefore set up, battery-powered devices must be woken up by pressing the button on the device." }, "credentials": { "data": { @@ -25,9 +24,8 @@ "data": { "host": "Host" }, - "description": "Before set up, the battery-powered device must be woken up by pressing the button on the device." + "description": "Before set up, battery-powered devices must be woken up by pressing the button on the device." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/es.json b/homeassistant/components/shelly/translations/es.json index bd9b5913e46..38c72f21dca 100644 --- a/homeassistant/components/shelly/translations/es.json +++ b/homeassistant/components/shelly/translations/es.json @@ -5,7 +5,6 @@ "unsupported_firmware": "El dispositivo est\u00e1 usando una versi\u00f3n de firmware no compatible." }, "error": { - "auth_not_supported": "Los dispositivos Shelly que requieren autenticaci\u00f3n no son compatibles actualmente.", "cannot_connect": "No se pudo conectar", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", "unknown": "Error inesperado" @@ -28,6 +27,5 @@ "description": "Antes de configurarlo, el dispositivo que funciona con bater\u00eda debe despertarse presionando el bot\u00f3n del dispositivo." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/et.json b/homeassistant/components/shelly/translations/et.json index 8c0a83e3a90..12a662f6560 100644 --- a/homeassistant/components/shelly/translations/et.json +++ b/homeassistant/components/shelly/translations/et.json @@ -9,6 +9,7 @@ "invalid_auth": "Tuvastamine nurjus", "unknown": "Tundmatu viga" }, + "flow_title": "", "step": { "confirm_discovery": { "description": "Kas soovid seadistada {model} saidil {host} ?\n\n Enne seadistamist tuleb akutoitega seade \u00e4ratada vajutades seadmel nuppu." @@ -26,6 +27,5 @@ "description": "Enne seadistamist tuleb akutoitega seade \u00e4ratada vajutades seadme nuppu." } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/fr.json b/homeassistant/components/shelly/translations/fr.json index 0f62629d21a..e40da9f5e68 100644 --- a/homeassistant/components/shelly/translations/fr.json +++ b/homeassistant/components/shelly/translations/fr.json @@ -1,10 +1,10 @@ { "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.", "cannot_connect": "\u00c9chec de connexion", "invalid_auth": "Authentification invalide", "unknown": "Erreur inattendue" @@ -23,9 +23,9 @@ "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." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/it.json b/homeassistant/components/shelly/translations/it.json index 8f878924010..61f2f8ccd09 100644 --- a/homeassistant/components/shelly/translations/it.json +++ b/homeassistant/components/shelly/translations/it.json @@ -5,15 +5,14 @@ "unsupported_firmware": "Il dispositivo utilizza una versione del firmware non supportata." }, "error": { - "auth_not_supported": "I dispositivi Shelly che richiedono l'autenticazione non sono attualmente supportati.", "cannot_connect": "Impossibile connettersi", "invalid_auth": "Autenticazione non valida", "unknown": "Errore imprevisto" }, - "flow_title": "Shelly: {name}", + "flow_title": "{name}", "step": { "confirm_discovery": { - "description": "Vuoi impostare il {model} presso {host}?\n\nPrima di configurare, il dispositivo alimentato a batteria deve essere svegliato premendo il pulsante sul dispositivo." + "description": "Vuoi impostare {model} su {host} ?\n\n Prima della configurazione, i dispositivi alimentati a batteria devono essere riattivati premendo il pulsante sul dispositivo." }, "credentials": { "data": { @@ -25,9 +24,8 @@ "data": { "host": "Host" }, - "description": "Prima di configurare, il dispositivo alimentato a batteria deve essere svegliato premendo il pulsante sul dispositivo." + "description": "Prima della configurazione, i dispositivi alimentati a batteria devono essere riattivati premendo il pulsante sul dispositivo." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/lb.json b/homeassistant/components/shelly/translations/lb.json index fda3aa300c2..b358c1c7282 100644 --- a/homeassistant/components/shelly/translations/lb.json +++ b/homeassistant/components/shelly/translations/lb.json @@ -5,12 +5,11 @@ "unsupported_firmware": "Den Apparat benotzt eng net \u00ebnnerst\u00ebtzte Firmware Versioun." }, "error": { - "auth_not_supported": "Shelly Apparaten d\u00e9i eng Authentifikatioun ben\u00e9idegen ginn aktuell net \u00ebnnerst\u00ebtzt.", "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "unknown": "Onerwaarte Feeler" }, - "flow_title": "Shelly: {name}", + "flow_title": "{name}", "step": { "confirm_discovery": { "description": "Soll de {model} um {host} konfigur\u00e9iert ginn?\n\nVirum ariichten muss dat Batterie bedriwwen Ger\u00e4t aktiv\u00e9iert ginn andeems de Kn\u00e4ppchen um Apparat gedr\u00e9ckt g\u00ebtt." @@ -28,6 +27,5 @@ "description": "Virum ariichten muss dat Batterie bedriwwen Ger\u00e4t aktiv\u00e9iert ginn andeems de Kn\u00e4ppchen um Apparat gedr\u00e9ckt g\u00ebtt." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/nl.json b/homeassistant/components/shelly/translations/nl.json index 198fbe51183..ecdfa41e109 100644 --- a/homeassistant/components/shelly/translations/nl.json +++ b/homeassistant/components/shelly/translations/nl.json @@ -4,8 +4,8 @@ "already_configured": "Apparaat is al geconfigureerd" }, "error": { - "auth_not_supported": "Shelly apparaten die verificatie vereisen, worden momenteel niet ondersteund.", "cannot_connect": "Kan geen verbinding maken", + "invalid_auth": "Ongeldige authenticatie", "unknown": "Onverwachte fout" }, "flow_title": "Shelly: {name}", @@ -25,6 +25,5 @@ } } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/no.json b/homeassistant/components/shelly/translations/no.json index dbdb6192ba2..705c494a4c1 100644 --- a/homeassistant/components/shelly/translations/no.json +++ b/homeassistant/components/shelly/translations/no.json @@ -5,15 +5,14 @@ "unsupported_firmware": "Enheten bruker en ikke-st\u00f8ttet firmwareversjon." }, "error": { - "auth_not_supported": "Shelly-enheter som krever godkjenning st\u00f8ttes for \u00f8yeblikket ikke.", "cannot_connect": "Tilkobling mislyktes", "invalid_auth": "Ugyldig godkjenning", "unknown": "Uventet feil" }, - "flow_title": "", + "flow_title": "{name}", "step": { "confirm_discovery": { - "description": "Vil du konfigurere {model} p\u00e5 {host} ?\n\n F\u00f8r du setter opp, m\u00e5 den batteridrevne enheten vekkes ved \u00e5 trykke p\u00e5 knappen p\u00e5 enheten." + "description": "Vil du konfigurere {model} p\u00e5 {host} ?\n\n F\u00f8r du setter opp, m\u00e5 batteridrevne enheter vekkes ved \u00e5 trykke p\u00e5 knappen p\u00e5 enheten." }, "credentials": { "data": { @@ -25,9 +24,8 @@ "data": { "host": "Vert" }, - "description": "F\u00f8r du setter opp, m\u00e5 den batteridrevne enheten vekkes ved \u00e5 trykke p\u00e5 knappen p\u00e5 enheten." + "description": "F\u00f8r du setter opp, m\u00e5 batteridrevne enheter vekkes ved \u00e5 trykke p\u00e5 knappen p\u00e5 enheten." } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/pl.json b/homeassistant/components/shelly/translations/pl.json index c59ca677533..ebf6041d4ba 100644 --- a/homeassistant/components/shelly/translations/pl.json +++ b/homeassistant/components/shelly/translations/pl.json @@ -5,7 +5,6 @@ "unsupported_firmware": "Urz\u0105dzenie u\u017cywa nieobs\u0142ugiwanej wersji firmware" }, "error": { - "auth_not_supported": "Urz\u0105dzenia Shelly wymagaj\u0105ce uwierzytelnienia nie s\u0105 obecnie obs\u0142ugiwane", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "invalid_auth": "Niepoprawne uwierzytelnienie", "unknown": "Nieoczekiwany b\u0142\u0105d" @@ -13,7 +12,7 @@ "flow_title": "{name}", "step": { "confirm_discovery": { - "description": "Czy chcesz skonfigurowa\u0107 {model} ({host})?\n\nPrzed konfiguracj\u0105 urz\u0105dzenie zasilane bateryjnie nale\u017cy wybudzi\u0107, naciskaj\u0105c przycisk na urz\u0105dzeniu." + "description": "Czy chcesz skonfigurowa\u0107 {model} ({host})?\n\nPrzed skonfigurowaniem urz\u0105dzenia zasilane bateryjnie nale\u017cy, wybudzi\u0107 naciskaj\u0105c przycisk na urz\u0105dzeniu." }, "credentials": { "data": { @@ -25,9 +24,8 @@ "data": { "host": "Nazwa hosta lub adres IP" }, - "description": "Przed konfiguracj\u0105, urz\u0105dzenie zasilane bateryjnie nale\u017cy wybudzi\u0107, naciskaj\u0105c przycisk na urz\u0105dzeniu." + "description": "Przed skonfigurowaniem urz\u0105dzenia zasilane bateryjnie nale\u017cy, wybudzi\u0107 naciskaj\u0105c przycisk na urz\u0105dzeniu." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/pt.json b/homeassistant/components/shelly/translations/pt.json index 2252c7c1eb9..b02332eb0b0 100644 --- a/homeassistant/components/shelly/translations/pt.json +++ b/homeassistant/components/shelly/translations/pt.json @@ -4,7 +4,6 @@ "already_configured": "O dispositivo j\u00e1 est\u00e1 configurado" }, "error": { - "auth_not_supported": "Dispositivos Shelly que requerem autentica\u00e7\u00e3o n\u00e3o s\u00e3o atualmente suportados.", "cannot_connect": "Falha na liga\u00e7\u00e3o", "unknown": "Erro inesperado" }, @@ -19,6 +18,5 @@ } } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/ru.json b/homeassistant/components/shelly/translations/ru.json index 47b4ad27c70..508a189b849 100644 --- a/homeassistant/components/shelly/translations/ru.json +++ b/homeassistant/components/shelly/translations/ru.json @@ -5,7 +5,6 @@ "unsupported_firmware": "\u0412 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043f\u0440\u043e\u0448\u0438\u0432\u043a\u0438." }, "error": { - "auth_not_supported": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Shelly, \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." @@ -28,6 +27,5 @@ "description": "\u041f\u0435\u0440\u0435\u0434 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u043e\u0439 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0435 \u043e\u0442 \u0431\u0430\u0442\u0430\u0440\u0435\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0438\u0437 \u0441\u043f\u044f\u0449\u0435\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430, \u043d\u0430\u0436\u0430\u0432 \u043a\u043d\u043e\u043f\u043a\u0443 \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435." } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/translations/zh-Hant.json b/homeassistant/components/shelly/translations/zh-Hant.json index ebd7df5f919..59ac0f5cccb 100644 --- a/homeassistant/components/shelly/translations/zh-Hant.json +++ b/homeassistant/components/shelly/translations/zh-Hant.json @@ -5,12 +5,11 @@ "unsupported_firmware": "\u8a2d\u5099\u4f7f\u7528\u7684\u97cc\u9ad4\u4e0d\u652f\u63f4\u3002" }, "error": { - "auth_not_supported": "\u76ee\u524d\u4e0d\u652f\u63f4 Shelly \u8a2d\u5099\u6240\u9700\u8a8d\u8b49\u3002", "cannot_connect": "\u9023\u7dda\u5931\u6557", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, - "flow_title": "Shelly\uff1a{name}", + "flow_title": "{name}", "step": { "confirm_discovery": { "description": "\u662f\u5426\u8981\u8a2d\u5b9a\u4f4d\u65bc {host} \u7684 {model}\uff1f\n\n\u958b\u59cb\u8a2d\u5b9a\u524d\uff0c\u5fc5\u9808\u6309\u4e0b\u8a2d\u5099\u4e0a\u7684\u6309\u9215\u4ee5\u559a\u9192\u96fb\u6c60\u4f9b\u96fb\u8a2d\u5099\u3002" @@ -28,6 +27,5 @@ "description": "\u958b\u59cb\u8a2d\u5b9a\u524d\uff0c\u5fc5\u9808\u6309\u4e0b\u8a2d\u5099\u4e0a\u7684\u6309\u9215\u4ee5\u559a\u9192\u96fb\u6c60\u4f9b\u96fb\u8a2d\u5099\u3002" } } - }, - "title": "Shelly" + } } \ No newline at end of file diff --git a/homeassistant/components/shelly/utils.py b/homeassistant/components/shelly/utils.py new file mode 100644 index 00000000000..36ce48b5421 --- /dev/null +++ b/homeassistant/components/shelly/utils.py @@ -0,0 +1,75 @@ +"""Shelly helpers functions.""" +import logging +from typing import Optional + +import aioshelly + +from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT +from homeassistant.helpers import entity_registry + +from . import ShellyDeviceWrapper + +_LOGGER = logging.getLogger(__name__) + + +async def async_remove_entity_by_domain(hass, domain, unique_id, config_entry_id): + """Remove entity by domain.""" + + entity_reg = await hass.helpers.entity_registry.async_get_registry() + for entry in entity_registry.async_entries_for_config_entry( + entity_reg, config_entry_id + ): + if entry.domain == domain and entry.unique_id == unique_id: + entity_reg.async_remove(entry.entity_id) + _LOGGER.debug("Removed %s domain for %s", domain, entry.original_name) + break + + +def temperature_unit(block_info: dict) -> str: + """Detect temperature unit.""" + if block_info[aioshelly.BLOCK_VALUE_UNIT] == "F": + return TEMP_FAHRENHEIT + return TEMP_CELSIUS + + +def get_entity_name( + wrapper: ShellyDeviceWrapper, + block: aioshelly.Block, + description: Optional[str] = None, +): + """Naming for switch and sensors.""" + entity_name = wrapper.name + + channels = None + if block.type == "input": + channels = wrapper.device.shelly.get("num_inputs") + elif block.type == "emeter": + channels = wrapper.device.shelly.get("num_emeters") + elif block.type in ["relay", "light"]: + channels = wrapper.device.shelly.get("num_outputs") + elif block.type in ["roller", "device"]: + channels = 1 + + channels = channels or 1 + + if channels > 1 and block.type != "device": + entity_name = None + mode = block.type + "s" + if mode in wrapper.device.settings: + entity_name = wrapper.device.settings[mode][int(block.channel)].get("name") + + if not entity_name: + if wrapper.model == "SHEM-3": + base = ord("A") + else: + base = ord("1") + entity_name = f"{wrapper.name} channel {chr(int(block.channel)+base)}" + + # Shelly Dimmer has two input channels and missing "num_inputs" + if wrapper.model in ["SHDM-1", "SHDM-2"] and block.type == "input": + entity_name = f"{entity_name} channel {int(block.channel)+1}" + + if description: + entity_name = f"{entity_name} {description}" + + return entity_name diff --git a/homeassistant/components/shodan/manifest.json b/homeassistant/components/shodan/manifest.json index 264ae3655f6..32d05e2f90b 100644 --- a/homeassistant/components/shodan/manifest.json +++ b/homeassistant/components/shodan/manifest.json @@ -2,6 +2,6 @@ "domain": "shodan", "name": "Shodan", "documentation": "https://www.home-assistant.io/integrations/shodan", - "requirements": ["shodan==1.23.0"], + "requirements": ["shodan==1.24.0"], "codeowners": ["@fabaff"] } diff --git a/homeassistant/components/shopping_list/translations/et.json b/homeassistant/components/shopping_list/translations/et.json index 2b3fb480ff1..27ea7ee978a 100644 --- a/homeassistant/components/shopping_list/translations/et.json +++ b/homeassistant/components/shopping_list/translations/et.json @@ -5,8 +5,10 @@ }, "step": { "user": { - "description": "Kas soovid seadistada ostunimekirja?" + "description": "Kas soovid seadistada ostunimekirja?", + "title": "Ostunimekiri" } } - } + }, + "title": "Ostunimekiri" } \ No newline at end of file diff --git a/homeassistant/components/shopping_list/translations/lb.json b/homeassistant/components/shopping_list/translations/lb.json index 129d1b0e8e7..753d7bcce2e 100644 --- a/homeassistant/components/shopping_list/translations/lb.json +++ b/homeassistant/components/shopping_list/translations/lb.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Akafsl\u00ebscht ass scho konfigur\u00e9iert." + "already_configured": "Service ass scho konfigur\u00e9iert" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/__init__.py b/homeassistant/components/simplisafe/__init__.py index f71e69d9aab..2430aad43cf 100644 --- a/homeassistant/components/simplisafe/__init__.py +++ b/homeassistant/components/simplisafe/__init__.py @@ -178,6 +178,8 @@ async def async_setup(hass, config): async def async_setup_entry(hass, config_entry): """Set up SimpliSafe as config entry.""" + hass.data[DOMAIN][DATA_LISTENER][config_entry.entry_id] = [] + entry_updates = {} if not config_entry.unique_id: # If the config entry doesn't already have a unique ID, set one: @@ -313,7 +315,9 @@ async def async_setup_entry(hass, config_entry): ]: async_register_admin_service(hass, DOMAIN, service, method, schema=schema) - config_entry.add_update_listener(async_reload_entry) + hass.data[DOMAIN][DATA_LISTENER][config_entry.entry_id].append( + config_entry.add_update_listener(async_reload_entry) + ) return True @@ -330,8 +334,8 @@ async def async_unload_entry(hass, entry): ) if unload_ok: hass.data[DOMAIN][DATA_CLIENT].pop(entry.entry_id) - remove_listener = hass.data[DOMAIN][DATA_LISTENER].pop(entry.entry_id) - remove_listener() + for remove_listener in hass.data[DOMAIN][DATA_LISTENER].pop(entry.entry_id): + remove_listener() return unload_ok @@ -461,10 +465,10 @@ class SimpliSafe: """Define an event handler to disconnect from the websocket.""" await self.websocket.async_disconnect() - self._hass.data[DOMAIN][DATA_LISTENER][ - self.config_entry.entry_id - ] = self._hass.bus.async_listen_once( - EVENT_HOMEASSISTANT_STOP, async_websocket_disconnect + self._hass.data[DOMAIN][DATA_LISTENER][self.config_entry.entry_id].append( + self._hass.bus.async_listen_once( + EVENT_HOMEASSISTANT_STOP, async_websocket_disconnect + ) ) self.systems = await self._api.get_systems() @@ -530,8 +534,7 @@ class SimpliSafe: ) ) - LOGGER.error("Update failed with stored refresh token") - raise UpdateFailed from result + raise UpdateFailed("Update failed with stored refresh token") LOGGER.warning("SimpliSafe cloud error; trying stored refresh token") self._emergency_refresh_token_used = True @@ -542,23 +545,18 @@ class SimpliSafe: ) return except SimplipyError as err: - LOGGER.error("Error while using stored refresh token: %s", err) - raise UpdateFailed from err + raise UpdateFailed( # pylint: disable=raise-missing-from + f"Error while using stored refresh token: {err}" + ) if isinstance(result, EndpointUnavailable): - # In case the user attempt an action not allowed in their current plan, + # In case the user attempts an action not allowed in their current plan, # we merely log that message at INFO level (so the user is aware, # but not spammed with ERROR messages that they cannot change): LOGGER.info(result) - raise UpdateFailed from result if isinstance(result, SimplipyError): - LOGGER.error("SimpliSafe error while updating: %s", result) - raise UpdateFailed from result - - if isinstance(result, Exception): - LOGGER.error("Unknown error while updating: %s", result) - raise UpdateFailed from result + raise UpdateFailed(f"SimpliSafe error while updating: {result}") if self._api.refresh_token != self.config_entry.data[CONF_TOKEN]: _async_save_refresh_token( diff --git a/homeassistant/components/simplisafe/binary_sensor.py b/homeassistant/components/simplisafe/binary_sensor.py index 2a4f430e9cc..a92309c1123 100644 --- a/homeassistant/components/simplisafe/binary_sensor.py +++ b/homeassistant/components/simplisafe/binary_sensor.py @@ -19,8 +19,11 @@ from .const import DATA_CLIENT, DOMAIN, LOGGER SUPPORTED_BATTERY_SENSOR_TYPES = [ EntityTypes.carbon_monoxide, EntityTypes.entry, + EntityTypes.glass_break, EntityTypes.leak, EntityTypes.lock_keypad, + EntityTypes.motion, + EntityTypes.siren, EntityTypes.smoke, EntityTypes.temperature, ] @@ -31,6 +34,7 @@ TRIGGERED_SENSOR_TYPES = { EntityTypes.glass_break: DEVICE_CLASS_SAFETY, EntityTypes.leak: DEVICE_CLASS_MOISTURE, EntityTypes.motion: DEVICE_CLASS_MOTION, + EntityTypes.siren: DEVICE_CLASS_SAFETY, EntityTypes.smoke: DEVICE_CLASS_SMOKE, } diff --git a/homeassistant/components/simplisafe/translations/bg.json b/homeassistant/components/simplisafe/translations/bg.json index 9d9f60d309c..bdac125ee72 100644 --- a/homeassistant/components/simplisafe/translations/bg.json +++ b/homeassistant/components/simplisafe/translations/bg.json @@ -1,8 +1,7 @@ { "config": { "error": { - "identifier_exists": "\u041f\u0440\u043e\u0444\u0438\u043b\u044a\u0442 \u0435 \u0432\u0435\u0447\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d", - "invalid_credentials": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0438 \u0434\u0430\u043d\u043d\u0438" + "identifier_exists": "\u041f\u0440\u043e\u0444\u0438\u043b\u044a\u0442 \u0435 \u0432\u0435\u0447\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/ca.json b/homeassistant/components/simplisafe/translations/ca.json index b5b88f753af..5b5d0cf1798 100644 --- a/homeassistant/components/simplisafe/translations/ca.json +++ b/homeassistant/components/simplisafe/translations/ca.json @@ -7,7 +7,6 @@ "error": { "identifier_exists": "Aquest compte ja est\u00e0 registrat", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Credencials inv\u00e0lides", "still_awaiting_mfa": "Esperant clic de l'enlla\u00e7 del correu MFA", "unknown": "Error inesperat" }, diff --git a/homeassistant/components/simplisafe/translations/cs.json b/homeassistant/components/simplisafe/translations/cs.json index c422a20c14c..7fd81a94391 100644 --- a/homeassistant/components/simplisafe/translations/cs.json +++ b/homeassistant/components/simplisafe/translations/cs.json @@ -7,17 +7,18 @@ "error": { "identifier_exists": "\u00da\u010det je ji\u017e zaregistrov\u00e1n", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { "mfa": { + "description": "Zkontrolujte, zda v\u00e1m do e-mail p\u0159i\u0161el odkaz od SimpliSafe. Po ov\u011b\u0159en\u00ed odkazu se vra\u0165te sem a dokon\u010dete instalaci integrace.", "title": "V\u00edcefaktorov\u00e9 ov\u011b\u0159ov\u00e1n\u00ed SimpliSafe" }, "reauth_confirm": { "data": { "password": "Heslo" }, + "description": "Platnost va\u0161eho p\u0159\u00edstupov\u00e9ho tokenu vypr\u0161ela nebo byla zru\u0161ena. Chcete-li sv\u016fj \u00fa\u010det znovu propojit, zadejte sv\u00e9 heslo.", "title": "Znovu ov\u011b\u0159it integraci" }, "user": { diff --git a/homeassistant/components/simplisafe/translations/da.json b/homeassistant/components/simplisafe/translations/da.json index eca91f39a40..a5119762f90 100644 --- a/homeassistant/components/simplisafe/translations/da.json +++ b/homeassistant/components/simplisafe/translations/da.json @@ -4,8 +4,7 @@ "already_configured": "Denne SimpliSafe-konto er allerede i brug." }, "error": { - "identifier_exists": "Konto er allerede registreret", - "invalid_credentials": "Ugyldige legitimationsoplysninger" + "identifier_exists": "Konto er allerede registreret" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/de.json b/homeassistant/components/simplisafe/translations/de.json index 6b71d78673c..67f059c1cd3 100644 --- a/homeassistant/components/simplisafe/translations/de.json +++ b/homeassistant/components/simplisafe/translations/de.json @@ -4,8 +4,7 @@ "already_configured": "Dieses SimpliSafe-Konto wird bereits verwendet." }, "error": { - "identifier_exists": "Konto bereits registriert", - "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen" + "identifier_exists": "Konto bereits registriert" }, "step": { "reauth_confirm": { diff --git a/homeassistant/components/simplisafe/translations/en.json b/homeassistant/components/simplisafe/translations/en.json index 57a669444e5..b9e274666bb 100644 --- a/homeassistant/components/simplisafe/translations/en.json +++ b/homeassistant/components/simplisafe/translations/en.json @@ -7,7 +7,6 @@ "error": { "identifier_exists": "Account already registered", "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid credentials", "still_awaiting_mfa": "Still awaiting MFA email click", "unknown": "Unexpected error" }, diff --git a/homeassistant/components/simplisafe/translations/es-419.json b/homeassistant/components/simplisafe/translations/es-419.json index 6273cfa671b..7cdd07029eb 100644 --- a/homeassistant/components/simplisafe/translations/es-419.json +++ b/homeassistant/components/simplisafe/translations/es-419.json @@ -4,8 +4,7 @@ "already_configured": "Esta cuenta SimpliSafe ya est\u00e1 en uso." }, "error": { - "identifier_exists": "Cuenta ya registrada", - "invalid_credentials": "Credenciales no v\u00e1lidas" + "identifier_exists": "Cuenta ya registrada" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/es.json b/homeassistant/components/simplisafe/translations/es.json index 4437abd9819..747c1dbeac4 100644 --- a/homeassistant/components/simplisafe/translations/es.json +++ b/homeassistant/components/simplisafe/translations/es.json @@ -6,7 +6,7 @@ }, "error": { "identifier_exists": "Cuenta ya registrada", - "invalid_credentials": "Credenciales no v\u00e1lidas", + "invalid_auth": "Autenticaci\u00f3n inv\u00e1lida", "still_awaiting_mfa": "Esperando todav\u00eda el clic en el correo electr\u00f3nico de MFA", "unknown": "Error inesperado" }, diff --git a/homeassistant/components/simplisafe/translations/et.json b/homeassistant/components/simplisafe/translations/et.json index 95a24352db9..f386228f404 100644 --- a/homeassistant/components/simplisafe/translations/et.json +++ b/homeassistant/components/simplisafe/translations/et.json @@ -5,11 +5,16 @@ "reauth_successful": "Taasautentimine \u00f5nnestus" }, "error": { + "identifier_exists": "Konto on juba registreeritud", "invalid_auth": "Tuvastamise viga", - "invalid_credentials": "Sobimatu mandaat", + "still_awaiting_mfa": "Ootan endiselt MFA e-posti klikki", "unknown": "Tundmatu viga" }, "step": { + "mfa": { + "description": "Kontrollige oma e-posti: link SimpliSafe-lt. P\u00e4rast lingi kontrollimist naase siia, et viia l\u00f5pule sidumise installimine.", + "title": "SimpliSafe mitmeastmeline autentimine" + }, "reauth_confirm": { "data": { "password": "Salas\u00f5na" @@ -19,9 +24,21 @@ }, "user": { "data": { + "code": "Kood (kasutatakse Home Assistant'i kasutajaliideses)", "password": "Salas\u00f5na", "username": "E-post" - } + }, + "title": "Sisesta oma teave." + } + } + }, + "options": { + "step": { + "init": { + "data": { + "code": "Kood (kasutatakse Home Assistant'i kasutajaliideses)" + }, + "title": "Seadista SimpliSafe" } } } diff --git a/homeassistant/components/simplisafe/translations/fi.json b/homeassistant/components/simplisafe/translations/fi.json index 765616cd839..d3d18987b44 100644 --- a/homeassistant/components/simplisafe/translations/fi.json +++ b/homeassistant/components/simplisafe/translations/fi.json @@ -1,8 +1,7 @@ { "config": { "error": { - "identifier_exists": "Tili on jo rekister\u00f6ity", - "invalid_credentials": "Virheelliset tunnistetiedot" + "identifier_exists": "Tili on jo rekister\u00f6ity" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/fr.json b/homeassistant/components/simplisafe/translations/fr.json index 54f89eb3ab4..1627f41c212 100644 --- a/homeassistant/components/simplisafe/translations/fr.json +++ b/homeassistant/components/simplisafe/translations/fr.json @@ -6,7 +6,7 @@ }, "error": { "identifier_exists": "Compte d\u00e9j\u00e0 enregistr\u00e9", - "invalid_credentials": "Informations d'identification invalides", + "invalid_auth": "Authentification invalide", "still_awaiting_mfa": "En attente de clic sur le message \u00e9lectronique d'authentification multi facteur", "unknown": "Erreur inattendue" }, diff --git a/homeassistant/components/simplisafe/translations/hu.json b/homeassistant/components/simplisafe/translations/hu.json index 38c48c3a86d..7b989246de1 100644 --- a/homeassistant/components/simplisafe/translations/hu.json +++ b/homeassistant/components/simplisafe/translations/hu.json @@ -1,8 +1,7 @@ { "config": { "error": { - "identifier_exists": "Fi\u00f3k m\u00e1r regisztr\u00e1lva van", - "invalid_credentials": "\u00c9rv\u00e9nytelen hiteles\u00edt\u0151 adatok" + "identifier_exists": "Fi\u00f3k m\u00e1r regisztr\u00e1lva van" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/it.json b/homeassistant/components/simplisafe/translations/it.json index 69c720109a6..fdd69b39efc 100644 --- a/homeassistant/components/simplisafe/translations/it.json +++ b/homeassistant/components/simplisafe/translations/it.json @@ -6,7 +6,7 @@ }, "error": { "identifier_exists": "Account gi\u00e0 registrato", - "invalid_credentials": "Credenziali non valide", + "invalid_auth": "Autenticazione non valida", "still_awaiting_mfa": "Ancora in attesa del clic sull'email MFA", "unknown": "Errore imprevisto" }, @@ -20,7 +20,7 @@ "password": "Password" }, "description": "Il token di accesso \u00e8 scaduto o \u00e8 stato revocato. Inserisci la tua password per ricollegare il tuo account.", - "title": "Ricollegare l'account SimpliSafe" + "title": "Reautenticare l'integrazione" }, "user": { "data": { diff --git a/homeassistant/components/simplisafe/translations/ko.json b/homeassistant/components/simplisafe/translations/ko.json index 44d3f453d41..57ba4a88fc1 100644 --- a/homeassistant/components/simplisafe/translations/ko.json +++ b/homeassistant/components/simplisafe/translations/ko.json @@ -4,8 +4,7 @@ "already_configured": "\uc774 SimpliSafe \uacc4\uc815\uc740 \uc774\ubbf8 \uc0ac\uc6a9 \uc911\uc785\ub2c8\ub2e4." }, "error": { - "identifier_exists": "\uacc4\uc815\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "invalid_credentials": "\ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" + "identifier_exists": "\uacc4\uc815\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/lb.json b/homeassistant/components/simplisafe/translations/lb.json index 3d6865402aa..225c4457a10 100644 --- a/homeassistant/components/simplisafe/translations/lb.json +++ b/homeassistant/components/simplisafe/translations/lb.json @@ -6,7 +6,7 @@ }, "error": { "identifier_exists": "Konto ass scho registr\u00e9iert", - "invalid_credentials": "Ong\u00eblteg Login Informatioune", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", "still_awaiting_mfa": "Waart nach den MFA E-Mail Klick.", "unknown": "Onerwaarte Feeler" }, @@ -20,7 +20,7 @@ "password": "Passwuert" }, "description": "D\u00e4in Acc\u00e8s Jeton as ofgelaf oder gouf revok\u00e9iert. G\u00ebff d\u00e4i Passwuert an fir d\u00e4i Kont fr\u00ebsch ze verbannen.", - "title": "SimpliSafe Kont fr\u00ebsch verbannen" + "title": "Integratioun re-authentifiz\u00e9ieren" }, "user": { "data": { diff --git a/homeassistant/components/simplisafe/translations/nl.json b/homeassistant/components/simplisafe/translations/nl.json index ce3fcf2902f..b285b288525 100644 --- a/homeassistant/components/simplisafe/translations/nl.json +++ b/homeassistant/components/simplisafe/translations/nl.json @@ -5,9 +5,16 @@ }, "error": { "identifier_exists": "Account bestaat al", - "invalid_credentials": "Ongeldige gebruikersgegevens" + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" }, "step": { + "reauth_confirm": { + "data": { + "password": "Wachtwoord" + }, + "description": "Uw toegangstoken is verlopen of ingetrokken. Voer uw wachtwoord in om uw account opnieuw te koppelen." + }, "user": { "data": { "code": "Code (gebruikt in Home Assistant)", diff --git a/homeassistant/components/simplisafe/translations/no.json b/homeassistant/components/simplisafe/translations/no.json index dd47ea5e8e2..401c5a540d6 100644 --- a/homeassistant/components/simplisafe/translations/no.json +++ b/homeassistant/components/simplisafe/translations/no.json @@ -7,7 +7,6 @@ "error": { "identifier_exists": "Konto er allerede registrert", "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig legitimasjon", "still_awaiting_mfa": "Forventer fortsatt MFA-e-postklikk", "unknown": "Uventet feil" }, diff --git a/homeassistant/components/simplisafe/translations/pl.json b/homeassistant/components/simplisafe/translations/pl.json index 47741d56178..7793d51817a 100644 --- a/homeassistant/components/simplisafe/translations/pl.json +++ b/homeassistant/components/simplisafe/translations/pl.json @@ -7,7 +7,6 @@ "error": { "identifier_exists": "Konto jest ju\u017c zarejestrowane", "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce", "still_awaiting_mfa": "Wci\u0105\u017c nie potwierdzono linka w e-mailu od SimpliSafe", "unknown": "Nieoczekiwany b\u0142\u0105d" }, @@ -29,7 +28,7 @@ "password": "Has\u0142o", "username": "Adres e-mail" }, - "title": "Wprowad\u017a dane." + "title": "Wprowad\u017a dane" } } }, diff --git a/homeassistant/components/simplisafe/translations/pt-BR.json b/homeassistant/components/simplisafe/translations/pt-BR.json index 800ac719ca9..832af325d4b 100644 --- a/homeassistant/components/simplisafe/translations/pt-BR.json +++ b/homeassistant/components/simplisafe/translations/pt-BR.json @@ -1,8 +1,7 @@ { "config": { "error": { - "identifier_exists": "Conta j\u00e1 cadastrada", - "invalid_credentials": "C\u00f3digo inv\u00e1lido" + "identifier_exists": "Conta j\u00e1 cadastrada" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/pt.json b/homeassistant/components/simplisafe/translations/pt.json index 9c98515448b..a208b49150a 100644 --- a/homeassistant/components/simplisafe/translations/pt.json +++ b/homeassistant/components/simplisafe/translations/pt.json @@ -2,7 +2,6 @@ "config": { "error": { "identifier_exists": "Conta j\u00e1 registada", - "invalid_credentials": "Credenciais inv\u00e1lidas", "unknown": "Erro inesperado" }, "step": { diff --git a/homeassistant/components/simplisafe/translations/ro.json b/homeassistant/components/simplisafe/translations/ro.json index 7046b0992b1..7531bef0a8e 100644 --- a/homeassistant/components/simplisafe/translations/ro.json +++ b/homeassistant/components/simplisafe/translations/ro.json @@ -1,8 +1,7 @@ { "config": { "error": { - "identifier_exists": "Contul este deja \u00eenregistrat", - "invalid_credentials": "Credentiale invalide" + "identifier_exists": "Contul este deja \u00eenregistrat" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/ru.json b/homeassistant/components/simplisafe/translations/ru.json index 6f63e07a9f1..94b0e6a0975 100644 --- a/homeassistant/components/simplisafe/translations/ru.json +++ b/homeassistant/components/simplisafe/translations/ru.json @@ -7,7 +7,6 @@ "error": { "identifier_exists": "\u0423\u0447\u0435\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0430.", "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.", "still_awaiting_mfa": "\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u0435.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, diff --git a/homeassistant/components/simplisafe/translations/sl.json b/homeassistant/components/simplisafe/translations/sl.json index 92e7a83f5b4..dffa3c4ccef 100644 --- a/homeassistant/components/simplisafe/translations/sl.json +++ b/homeassistant/components/simplisafe/translations/sl.json @@ -4,8 +4,7 @@ "already_configured": "Ta ra\u010dun SimpliSafe je \u017ee v uporabi." }, "error": { - "identifier_exists": "Ra\u010dun je \u017ee registriran", - "invalid_credentials": "Neveljavne poverilnice" + "identifier_exists": "Ra\u010dun je \u017ee registriran" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/sv.json b/homeassistant/components/simplisafe/translations/sv.json index 48744428b1d..a1bfb4400be 100644 --- a/homeassistant/components/simplisafe/translations/sv.json +++ b/homeassistant/components/simplisafe/translations/sv.json @@ -1,8 +1,7 @@ { "config": { "error": { - "identifier_exists": "Kontot \u00e4r redan registrerat", - "invalid_credentials": "Ogiltiga autentiseringsuppgifter" + "identifier_exists": "Kontot \u00e4r redan registrerat" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/zh-Hans.json b/homeassistant/components/simplisafe/translations/zh-Hans.json index e4bb147aea2..9b0e1467d02 100644 --- a/homeassistant/components/simplisafe/translations/zh-Hans.json +++ b/homeassistant/components/simplisafe/translations/zh-Hans.json @@ -2,8 +2,7 @@ "config": { "error": { "identifier_exists": "\u8d26\u6237\u5df2\u6ce8\u518c", - "invalid_auth": "\u65e0\u6548\u7684\u8eab\u4efd\u9a8c\u8bc1", - "invalid_credentials": "\u65e0\u6548\u7684\u8eab\u4efd\u8ba4\u8bc1" + "invalid_auth": "\u65e0\u6548\u7684\u8eab\u4efd\u9a8c\u8bc1" }, "step": { "user": { diff --git a/homeassistant/components/simplisafe/translations/zh-Hant.json b/homeassistant/components/simplisafe/translations/zh-Hant.json index e7302d8c7a1..ad5323d3957 100644 --- a/homeassistant/components/simplisafe/translations/zh-Hant.json +++ b/homeassistant/components/simplisafe/translations/zh-Hant.json @@ -7,7 +7,6 @@ "error": { "identifier_exists": "\u5e33\u865f\u5df2\u8a3b\u518a", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u6191\u8b49\u7121\u6548", "still_awaiting_mfa": "\u4ecd\u5728\u7b49\u5019\u9ede\u64ca\u591a\u6b65\u9a5f\u8a8d\u8b49\u90f5\u4ef6", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, diff --git a/homeassistant/components/sisyphus/light.py b/homeassistant/components/sisyphus/light.py index 6d5fa2fc835..5ed3f046f59 100644 --- a/homeassistant/components/sisyphus/light.py +++ b/homeassistant/components/sisyphus/light.py @@ -38,6 +38,10 @@ class SisyphusLight(LightEntity): """Add listeners after this object has been initialized.""" self._table.add_listener(self.async_write_ha_state) + async def async_update(self): + """Force update the table state.""" + await self._table.refresh() + @property def available(self): """Return true if the table is responding to heartbeats.""" diff --git a/homeassistant/components/sisyphus/manifest.json b/homeassistant/components/sisyphus/manifest.json index fdd5961d33a..24dd3345f80 100644 --- a/homeassistant/components/sisyphus/manifest.json +++ b/homeassistant/components/sisyphus/manifest.json @@ -2,6 +2,10 @@ "domain": "sisyphus", "name": "Sisyphus", "documentation": "https://www.home-assistant.io/integrations/sisyphus", - "requirements": ["sisyphus-control==2.2.1"], - "codeowners": ["@jkeljo"] -} + "requirements": [ + "sisyphus-control==3.0" + ], + "codeowners": [ + "@jkeljo" + ] +} \ No newline at end of file diff --git a/homeassistant/components/sisyphus/media_player.py b/homeassistant/components/sisyphus/media_player.py index 8f55fce1178..21e50b19a1b 100644 --- a/homeassistant/components/sisyphus/media_player.py +++ b/homeassistant/components/sisyphus/media_player.py @@ -65,6 +65,10 @@ class SisyphusPlayer(MediaPlayerEntity): """Add listeners after this object has been initialized.""" self._table.add_listener(self.async_write_ha_state) + async def async_update(self): + """Force update table state.""" + await self._table.refresh() + @property def unique_id(self): """Return the UUID of the table.""" @@ -129,6 +133,24 @@ class SisyphusPlayer(MediaPlayerEntity): """Return the track ID of the current track.""" return self._table.active_track.id if self._table.active_track else None + @property + def media_duration(self): + """Return the total time it will take to run this track at the current speed.""" + return self._table.active_track_total_time.total_seconds() + + @property + def media_position(self): + """Return the current position within the track.""" + return ( + self._table.active_track_total_time + - self._table.active_track_remaining_time + ).total_seconds() + + @property + def media_position_updated_at(self): + """Return the last time we got a position update.""" + return self._table.active_track_remaining_time_as_of + @property def supported_features(self): """Return the features supported by this table.""" diff --git a/homeassistant/components/skybell/switch.py b/homeassistant/components/skybell/switch.py index 3d1d890b295..1ad13af9249 100644 --- a/homeassistant/components/skybell/switch.py +++ b/homeassistant/components/skybell/switch.py @@ -58,7 +58,7 @@ class SkybellSwitch(SkybellDevice, SwitchEntity): setattr(self._device, self._switch_type, True) def turn_off(self, **kwargs): - """Turn on the switch.""" + """Turn off the switch.""" setattr(self._device, self._switch_type, False) @property diff --git a/homeassistant/components/sma/sensor.py b/homeassistant/components/sma/sensor.py index ce61d4ff17b..119d9a366d6 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/smappee/translations/ca.json b/homeassistant/components/smappee/translations/ca.json index d2633ace026..92203b9b37e 100644 --- a/homeassistant/components/smappee/translations/ca.json +++ b/homeassistant/components/smappee/translations/ca.json @@ -5,7 +5,6 @@ "already_configured_local_device": "Dispositiu(s) local ja configurat. Elimina'ls primer abans de configurar un dispositiu al n\u00favol.", "authorize_url_timeout": "Temps d'espera esgotat durant la generaci\u00f3 de l'URL d'autoritzaci\u00f3.", "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar amb el Smappee.", "invalid_mdns": "Dispositiu no compatible amb la integraci\u00f3 de Smappee.", "missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3.", "no_url_available": "No hi ha cap URL disponible. Per a m\u00e9s informaci\u00f3 sobre aquest error, [consulta la secci\u00f3 d'ajuda]({docs_url})" diff --git a/homeassistant/components/smappee/translations/cs.json b/homeassistant/components/smappee/translations/cs.json index 723df988a1f..174da41205a 100644 --- a/homeassistant/components/smappee/translations/cs.json +++ b/homeassistant/components/smappee/translations/cs.json @@ -2,9 +2,10 @@ "config": { "abort": { "already_configured_device": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", + "already_configured_local_device": "M\u00edstn\u00ed za\u0159\u00edzen\u00ed ji\u017e jsou nastavena. P\u0159ed nastaven\u00ed cloudov\u00e9ho za\u0159\u00edzen\u00ed je nejprve odstra\u0148te.", "authorize_url_timeout": "\u010casov\u00fd limit autoriza\u010dn\u00edho URL vypr\u0161el", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed Smappee se nezda\u0159ilo.", + "invalid_mdns": "Nepodporovan\u00e9 za\u0159\u00edzen\u00ed pro integraci Smappee.", "missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace.", "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})" }, @@ -26,7 +27,7 @@ "title": "Vyberte metodu ov\u011b\u0159en\u00ed" }, "zeroconf_confirm": { - "description": "Chcete p\u0159idat za\u0159\u00edzen\u00ed Smappee se s\u00e9riov\u00fdm \u010d\u00edslem \"{serialnumber}\" do Home Assistant?", + "description": "Chcete p\u0159idat za\u0159\u00edzen\u00ed Smappee se s\u00e9riov\u00fdm \u010d\u00edslem `{serialnumber}` do Home Assistant?", "title": "Objeven\u00e9 za\u0159\u00edzen\u00ed Smappee" } } diff --git a/homeassistant/components/smappee/translations/en.json b/homeassistant/components/smappee/translations/en.json index 9d7c7f2c507..9220b1c3ec4 100644 --- a/homeassistant/components/smappee/translations/en.json +++ b/homeassistant/components/smappee/translations/en.json @@ -5,7 +5,6 @@ "already_configured_local_device": "Local device(s) is already configured. Please remove those first before configuring a cloud device.", "authorize_url_timeout": "Timeout generating authorize URL.", "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect to Smappee device.", "invalid_mdns": "Unsupported device for the Smappee integration.", "missing_configuration": "The component is not configured. Please follow the documentation.", "no_url_available": "No URL available. For information about this error, [check the help section]({docs_url})" diff --git a/homeassistant/components/smappee/translations/es.json b/homeassistant/components/smappee/translations/es.json index f4dc1c69a41..a1124557876 100644 --- a/homeassistant/components/smappee/translations/es.json +++ b/homeassistant/components/smappee/translations/es.json @@ -5,7 +5,6 @@ "already_configured_local_device": "Los dispositivos locales ya est\u00e1n configurados. Elim\u00ednelos primero antes de configurar un dispositivo en la nube.", "authorize_url_timeout": "Tiempo de espera agotado generando la url de autorizaci\u00f3n.", "cannot_connect": "No se pudo conectar", - "connection_error": "No se pudo conectar al dispositivo Smappee.", "invalid_mdns": "Dispositivo no compatible para la integraci\u00f3n de Smappee.", "missing_configuration": "El componente no est\u00e1 configurado. Consulta la documentaci\u00f3n.", "no_url_available": "No hay URL disponible. Para obtener informaci\u00f3n sobre este error, [consulta la secci\u00f3n de ayuda]({docs_url})" diff --git a/homeassistant/components/smappee/translations/et.json b/homeassistant/components/smappee/translations/et.json index b57bd9b81ff..4996f9dea9c 100644 --- a/homeassistant/components/smappee/translations/et.json +++ b/homeassistant/components/smappee/translations/et.json @@ -3,13 +3,20 @@ "abort": { "already_configured_device": "Seade on juba h\u00e4\u00e4lestatud", "already_configured_local_device": "Kohalikud seadmed on juba seadistatud. Enne pilveseadme seadistamist eemaldage need.", + "authorize_url_timeout": "Autentimise URL-i loomise ajal\u00f5pp.", "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "Smappee seadmega \u00fchenduse loomine nurjus.", "invalid_mdns": "Seade ei toeta Smappee'ga sidumist.", "missing_configuration": "Osis pole seadistatud. Palun vaata dokumentatsiooni.", "no_url_available": "URL pole saadaval. Rohkem teavet [check the help section]({docs_url})" }, + "flow_title": "", "step": { + "environment": { + "data": { + "environment": "Keskkond" + }, + "description": "Seadista oma Smappee Home Assistant-iga sidumiseks." + }, "local": { "data": { "host": "" @@ -20,7 +27,8 @@ "title": "Vali tuvastusmeetod" }, "zeroconf_confirm": { - "description": "Kas soovid lisada Home Assistanti Smappee seadme seerianumbriga \" {serial_number} \"?" + "description": "Kas soovid lisada Home Assistanti Smappee seadme seerianumbriga \" {serial_number} \"?", + "title": "Avastatud Smappee seade" } } } diff --git a/homeassistant/components/smappee/translations/fr.json b/homeassistant/components/smappee/translations/fr.json index 4bbed6615ca..f1d8cdb9615 100644 --- a/homeassistant/components/smappee/translations/fr.json +++ b/homeassistant/components/smappee/translations/fr.json @@ -4,7 +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.", - "connection_error": "\u00c9chec de la connexion \u00e0 l'appareil Smappee.", + "cannot_connect": "\u00c9chec de connexion", "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.", "no_url_available": "Aucune URL disponible. Pour plus d'informations sur cette erreur, [consultez la section d'aide] ( {docs_url} )" diff --git a/homeassistant/components/smappee/translations/it.json b/homeassistant/components/smappee/translations/it.json index e189cb2f3f2..5fd6bbf49c1 100644 --- a/homeassistant/components/smappee/translations/it.json +++ b/homeassistant/components/smappee/translations/it.json @@ -5,7 +5,6 @@ "already_configured_local_device": "L'apparecchio o gli apparecchi locali sono gi\u00e0 configurati. Si prega di rimuoverli prima di configurare un dispositivo cloud.", "authorize_url_timeout": "Tempo scaduto nel generare l'URL di autorizzazione.", "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi al dispositivo Smappee.", "invalid_mdns": "Dispositivo non supportato per l'integrazione Smappee.", "missing_configuration": "Il componente non \u00e8 configurato. Si prega di seguire la documentazione.", "no_url_available": "Nessun URL disponibile. Per informazioni su questo errore, [controlla la sezione della guida]({docs_url})" diff --git a/homeassistant/components/smappee/translations/lb.json b/homeassistant/components/smappee/translations/lb.json index 67496878870..da5f26b31ff 100644 --- a/homeassistant/components/smappee/translations/lb.json +++ b/homeassistant/components/smappee/translations/lb.json @@ -5,7 +5,6 @@ "already_configured_local_device": "Lokalen Apparat ass scho konfigur\u00e9iert. L\u00e4sch d\u00e9i iers de ee Cloud Apparat dob\u00e4isetz.", "authorize_url_timeout": "Z\u00e4it Iwwerschreidung beim gener\u00e9ieren vun der Autorisatiouns URL.", "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen mam Smappee Apparat.", "invalid_mdns": "Net \u00ebnnerst\u00ebtzten Apparat fir Smappee Integratioun.", "missing_configuration": "Komponent ass nach net konfigur\u00e9iert. Follegt w.e.g der Dokumentatioun.", "no_url_available": "Keng URL disponibel. Fir Informatiounen iwwert d\u00ebse Feeler, [kuck H\u00ebllef Sektioun]({docs_url})" diff --git a/homeassistant/components/smappee/translations/nl.json b/homeassistant/components/smappee/translations/nl.json index 7cb0141826a..86f4a40c6f9 100644 --- a/homeassistant/components/smappee/translations/nl.json +++ b/homeassistant/components/smappee/translations/nl.json @@ -1,7 +1,17 @@ { "config": { "abort": { + "already_configured_device": "Apparaat is al geconfigureerd", + "already_configured_local_device": "Lokale apparaten zijn al geconfigureerd. Verwijder deze eerst voordat u een cloudapparaat configureert.", "cannot_connect": "Kan geen verbinding maken" + }, + "step": { + "local": { + "data": { + "host": "Host" + }, + "description": "Voer de host in om de lokale Smappee-integratie te starten" + } } } } \ No newline at end of file diff --git a/homeassistant/components/smappee/translations/no.json b/homeassistant/components/smappee/translations/no.json index 5cefda545ba..5e378369465 100644 --- a/homeassistant/components/smappee/translations/no.json +++ b/homeassistant/components/smappee/translations/no.json @@ -2,10 +2,9 @@ "config": { "abort": { "already_configured_device": "Enheten er allerede konfigurert", - "already_configured_local_device": "Lokale enheter er allerede konfigurert. Fjern de f\u00f8rst f\u00f8r du konfigurerer en skyenhet.", + "already_configured_local_device": "Lokal(e) enhet(er) er allerede konfigurert. Fjern de f\u00f8rst f\u00f8r du konfigurerer en skyenhet.", "authorize_url_timeout": "Tidsavbrudd som genererer autorer URL-adresse.", "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kunne ikke koble til Smappee-enheten.", "invalid_mdns": "Ikke-st\u00f8ttet enhet for Smappee-integrasjonen.", "missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen.", "no_url_available": "Ingen URL tilgjengelig. For informasjon om denne feilen, [sjekk hjelpseksjonen]({docs_url})" diff --git a/homeassistant/components/smappee/translations/pl.json b/homeassistant/components/smappee/translations/pl.json index e23211713d8..56f20551195 100644 --- a/homeassistant/components/smappee/translations/pl.json +++ b/homeassistant/components/smappee/translations/pl.json @@ -5,7 +5,6 @@ "already_configured_local_device": "Urz\u0105dzenie(-a) lokalne jest ju\u017c skonfigurowane. Usu\u0144 je najpierw przed skonfigurowaniem urz\u0105dzenia w chmurze.", "authorize_url_timeout": "Przekroczono limit czasu generowania URL autoryzacji", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z urz\u0105dzeniem Smappee", "invalid_mdns": "Nieobs\u0142ugiwane urz\u0105dzenie dla integracji Smappee", "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105.", "no_url_available": "Brak dost\u0119pnego adresu URL. Aby uzyska\u0107 informacje na temat tego b\u0142\u0119du, [sprawd\u017a sekcj\u0119 pomocy] ({docs_url})" diff --git a/homeassistant/components/smappee/translations/ru.json b/homeassistant/components/smappee/translations/ru.json index 7f4c737a71b..568abf4814e 100644 --- a/homeassistant/components/smappee/translations/ru.json +++ b/homeassistant/components/smappee/translations/ru.json @@ -5,7 +5,6 @@ "already_configured_local_device": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0445 \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u043e\u0439 \u043e\u0431\u043b\u0430\u0447\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.", "authorize_url_timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443.", "invalid_mdns": "\u041d\u0435\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e.", "missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438.", "no_url_available": "URL-\u0430\u0434\u0440\u0435\u0441 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d. \u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439]({docs_url}) \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u044d\u0442\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0435." diff --git a/homeassistant/components/smappee/translations/zh-Hans.json b/homeassistant/components/smappee/translations/zh-Hans.json new file mode 100644 index 00000000000..6e842e66fab --- /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/smappee/translations/zh-Hant.json b/homeassistant/components/smappee/translations/zh-Hant.json index 928a45352ac..77f726a0dcd 100644 --- a/homeassistant/components/smappee/translations/zh-Hant.json +++ b/homeassistant/components/smappee/translations/zh-Hant.json @@ -5,7 +5,6 @@ "already_configured_local_device": "\u672c\u5730\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\uff0c\u8acb\u5148\u9032\u884c\u79fb\u9664\u5f8c\u518d\u8a2d\u5b9a\u96f2\u7aef\u8a2d\u5099\u3002", "authorize_url_timeout": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u903e\u6642\u3002", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "Smappee \u8a2d\u5099\u9023\u7dda\u5931\u6557\u3002", "invalid_mdns": "Smappee \u6574\u5408\u4e0d\u652f\u63f4\u7684\u8a2d\u5099\u3002", "missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002", "no_url_available": "\u6c92\u6709\u53ef\u7528\u7684\u7db2\u5740\u3002\u95dc\u65bc\u6b64\u932f\u8aa4\u66f4\u8a73\u7d30\u8a0a\u606f\uff0c[\u9ede\u9078\u5354\u52a9\u7ae0\u7bc0]({docs_url})" diff --git a/homeassistant/components/smart_meter_texas/strings.json b/homeassistant/components/smart_meter_texas/strings.json index 0e7916a269a..96dc8b371d1 100644 --- a/homeassistant/components/smart_meter_texas/strings.json +++ b/homeassistant/components/smart_meter_texas/strings.json @@ -1,9 +1,7 @@ { - "title": "Smart Meter Texas", "config": { "step": { "user": { - "description": "Provide your username and password for Smart Meter Texas.", "data": { "username": "[%key:common::config_flow::data::username%]", "password": "[%key:common::config_flow::data::password%]" diff --git a/homeassistant/components/smart_meter_texas/translations/ca.json b/homeassistant/components/smart_meter_texas/translations/ca.json index b2c1f34e1e4..9677f944330 100644 --- a/homeassistant/components/smart_meter_texas/translations/ca.json +++ b/homeassistant/components/smart_meter_texas/translations/ca.json @@ -13,10 +13,8 @@ "data": { "password": "Contrasenya", "username": "Nom d'usuari" - }, - "description": "Proporciona el nom d'usuari i contrasenya per a Smart Meter Texas." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/cs.json b/homeassistant/components/smart_meter_texas/translations/cs.json index f662c3765cf..dc27752e935 100644 --- a/homeassistant/components/smart_meter_texas/translations/cs.json +++ b/homeassistant/components/smart_meter_texas/translations/cs.json @@ -13,10 +13,8 @@ "data": { "password": "Heslo", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" - }, - "description": "Zadejte sv\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no a heslo pro Smart Meter Texas." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/de.json b/homeassistant/components/smart_meter_texas/translations/de.json index 936e9817d92..6f398062876 100644 --- a/homeassistant/components/smart_meter_texas/translations/de.json +++ b/homeassistant/components/smart_meter_texas/translations/de.json @@ -8,6 +8,5 @@ } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/en.json b/homeassistant/components/smart_meter_texas/translations/en.json index dec29957514..cb0e7bed7ea 100644 --- a/homeassistant/components/smart_meter_texas/translations/en.json +++ b/homeassistant/components/smart_meter_texas/translations/en.json @@ -13,10 +13,8 @@ "data": { "password": "Password", "username": "Username" - }, - "description": "Provide your username and password for Smart Meter Texas." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/es.json b/homeassistant/components/smart_meter_texas/translations/es.json index 0423fee406b..d537185eb68 100644 --- a/homeassistant/components/smart_meter_texas/translations/es.json +++ b/homeassistant/components/smart_meter_texas/translations/es.json @@ -13,10 +13,8 @@ "data": { "password": "Contrase\u00f1a", "username": "Usuario" - }, - "description": "Proporciona tu nombre de usuario y contrase\u00f1a para Smart Meter Texas." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/et.json b/homeassistant/components/smart_meter_texas/translations/et.json index 42bf8ce1ead..04c0ea2a1cf 100644 --- a/homeassistant/components/smart_meter_texas/translations/et.json +++ b/homeassistant/components/smart_meter_texas/translations/et.json @@ -13,8 +13,7 @@ "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - }, - "description": "Sisesta oma Smart Meter Texas'e konto kasutajanimi ja salas\u00f5na." + } } } } diff --git a/homeassistant/components/smart_meter_texas/translations/fr.json b/homeassistant/components/smart_meter_texas/translations/fr.json index 08e5bb657ee..aa84ec33d8c 100644 --- a/homeassistant/components/smart_meter_texas/translations/fr.json +++ b/homeassistant/components/smart_meter_texas/translations/fr.json @@ -13,10 +13,8 @@ "data": { "password": "Mot de passe", "username": "Nom d'utilisateur" - }, - "description": "Fournissez votre nom d\u2019utilisateur et votre mot de passe pour Smart Meter Texas." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/it.json b/homeassistant/components/smart_meter_texas/translations/it.json index 787dfd6b8c2..843262aa318 100644 --- a/homeassistant/components/smart_meter_texas/translations/it.json +++ b/homeassistant/components/smart_meter_texas/translations/it.json @@ -13,10 +13,8 @@ "data": { "password": "Password", "username": "Nome utente" - }, - "description": "Fornisci il tuo nome utente e la password per Smart Meter Texas." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/ko.json b/homeassistant/components/smart_meter_texas/translations/ko.json index 444e3cf4463..94261de9637 100644 --- a/homeassistant/components/smart_meter_texas/translations/ko.json +++ b/homeassistant/components/smart_meter_texas/translations/ko.json @@ -13,10 +13,8 @@ "data": { "password": "\ube44\ubc00\ubc88\ud638", "username": "\uc0ac\uc6a9\uc790 \uc774\ub984" - }, - "description": "Smart Meter Texas \uc758 \uc0ac\uc6a9\uc790 \uc774\ub984\uacfc \ube44\ubc00\ubc88\ud638\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/lb.json b/homeassistant/components/smart_meter_texas/translations/lb.json index 8b60dd41c8c..60b1bb6f305 100644 --- a/homeassistant/components/smart_meter_texas/translations/lb.json +++ b/homeassistant/components/smart_meter_texas/translations/lb.json @@ -13,10 +13,8 @@ "data": { "password": "Passwuert", "username": "Benotzernumm" - }, - "description": "G\u00ebff den Benotzernumm an d'Passwuert fir den Smart Meter Texas un." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/nl.json b/homeassistant/components/smart_meter_texas/translations/nl.json index 4b4275a8478..d25cf575b44 100644 --- a/homeassistant/components/smart_meter_texas/translations/nl.json +++ b/homeassistant/components/smart_meter_texas/translations/nl.json @@ -3,9 +3,15 @@ "abort": { "already_configured": "Apparaat is al geconfigureerd" }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "password": "Wachtwoord", "username": "Benutzername" } } diff --git a/homeassistant/components/smart_meter_texas/translations/no.json b/homeassistant/components/smart_meter_texas/translations/no.json index 1a2153c493c..4ea7b2401c3 100644 --- a/homeassistant/components/smart_meter_texas/translations/no.json +++ b/homeassistant/components/smart_meter_texas/translations/no.json @@ -13,10 +13,8 @@ "data": { "password": "Passord", "username": "Brukernavn" - }, - "description": "Oppgi brukernavn og passord for Smart Meter Texas." + } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/pl.json b/homeassistant/components/smart_meter_texas/translations/pl.json index 19257e3cf5c..8a08a06c699 100644 --- a/homeassistant/components/smart_meter_texas/translations/pl.json +++ b/homeassistant/components/smart_meter_texas/translations/pl.json @@ -13,10 +13,8 @@ "data": { "password": "Has\u0142o", "username": "Nazwa u\u017cytkownika" - }, - "description": "Podaj swoj\u0105 nazw\u0119 u\u017cytkownika i has\u0142o do Smart Meter Texas." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/ru.json b/homeassistant/components/smart_meter_texas/translations/ru.json index 2015377048d..9fe75df9c3f 100644 --- a/homeassistant/components/smart_meter_texas/translations/ru.json +++ b/homeassistant/components/smart_meter_texas/translations/ru.json @@ -13,10 +13,8 @@ "data": { "password": "\u041f\u0430\u0440\u043e\u043b\u044c", "username": "\u041b\u043e\u0433\u0438\u043d" - }, - "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 Home Assistant \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 Smart Meter Texas." + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smart_meter_texas/translations/zh-Hant.json b/homeassistant/components/smart_meter_texas/translations/zh-Hant.json index a268bee7cc3..df467dd38b9 100644 --- a/homeassistant/components/smart_meter_texas/translations/zh-Hant.json +++ b/homeassistant/components/smart_meter_texas/translations/zh-Hant.json @@ -13,10 +13,8 @@ "data": { "password": "\u5bc6\u78bc", "username": "\u4f7f\u7528\u8005\u540d\u7a31" - }, - "description": "\u8acb\u8f38\u5165 Smart Meter Texas \u5e33\u865f\u4f7f\u7528\u8005\u540d\u7a31\u8207\u5bc6\u78bc\u3002" + } } } - }, - "title": "Smart Meter Texas" + } } \ No newline at end of file diff --git a/homeassistant/components/smarthab/translations/ca.json b/homeassistant/components/smarthab/translations/ca.json index f6551d62078..cac81a0acea 100644 --- a/homeassistant/components/smarthab/translations/ca.json +++ b/homeassistant/components/smarthab/translations/ca.json @@ -3,9 +3,7 @@ "error": { "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", "service": "Error en l'intent de connexi\u00f3 a SmartHab. Pot ser que el servei no estigui disponible. Comprova la connexi\u00f3.", - "unknown": "Error inesperat", - "unknown_error": "Error inesperat", - "wrong_login": "Autenticaci\u00f3 inv\u00e0lida" + "unknown": "Error inesperat" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/cs.json b/homeassistant/components/smarthab/translations/cs.json index 3e8b1abfabf..1e862ff0069 100644 --- a/homeassistant/components/smarthab/translations/cs.json +++ b/homeassistant/components/smarthab/translations/cs.json @@ -2,16 +2,15 @@ "config": { "error": { "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "unknown": "Neo\u010dek\u00e1van\u00e1 chyba", - "unknown_error": "Neo\u010dek\u00e1van\u00e1 chyba", - "wrong_login": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" + "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { "user": { "data": { "email": "E-mail", "password": "Heslo" - } + }, + "title": "Nastaven\u00ed SmartHab" } } } diff --git a/homeassistant/components/smarthab/translations/de.json b/homeassistant/components/smarthab/translations/de.json index 04298404b55..2c76c4d56db 100644 --- a/homeassistant/components/smarthab/translations/de.json +++ b/homeassistant/components/smarthab/translations/de.json @@ -1,8 +1,7 @@ { "config": { "error": { - "unknown": "Unerwarteter Fehler", - "unknown_error": "Unerwarteter Fehler" + "unknown": "Unerwarteter Fehler" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/en.json b/homeassistant/components/smarthab/translations/en.json index 33f280a763d..854f7a7ddb5 100644 --- a/homeassistant/components/smarthab/translations/en.json +++ b/homeassistant/components/smarthab/translations/en.json @@ -3,9 +3,7 @@ "error": { "invalid_auth": "Invalid authentication", "service": "Error while trying to reach SmartHab. Service might be down. Check your connection.", - "unknown": "Unexpected error", - "unknown_error": "Unexpected error", - "wrong_login": "Invalid authentication" + "unknown": "Unexpected error" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/es.json b/homeassistant/components/smarthab/translations/es.json index 90ea53cd65a..b111ddbccd1 100644 --- a/homeassistant/components/smarthab/translations/es.json +++ b/homeassistant/components/smarthab/translations/es.json @@ -3,9 +3,7 @@ "error": { "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", "service": "Error al intentar contactar con SmartHab. El servicio podr\u00eda estar ca\u00eddo. Verifica tu conexi\u00f3n.", - "unknown": "Error inesperado", - "unknown_error": "Error inesperado", - "wrong_login": "Autenticaci\u00f3n no v\u00e1lida" + "unknown": "Error inesperado" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/et.json b/homeassistant/components/smarthab/translations/et.json index b0ef8d6bb48..f7c91f8dce6 100644 --- a/homeassistant/components/smarthab/translations/et.json +++ b/homeassistant/components/smarthab/translations/et.json @@ -2,15 +2,17 @@ "config": { "error": { "invalid_auth": "Tuvastamise viga", - "unknown": "Tundmatu viga", - "unknown_error": "Tundmatu viga", - "wrong_login": "Tuvastamine nurjus" + "service": "Viga SmartHabiga \u00fchendumisel. Teenus v\u00f5ib olla h\u00e4iritud. Kontrolli oma \u00fchendust.", + "unknown": "Tundmatu viga" }, "step": { "user": { "data": { + "email": "E-post", "password": "Salas\u00f5na" - } + }, + "description": "Tehnilistel p\u00f5hjustel kasuta kindlasti oma Home Assistanti seadistustele vastavat sekundaarset kontot. Selle saad luua rakendusest SmartHab.", + "title": "Seadista SmartHab" } } } diff --git a/homeassistant/components/smarthab/translations/fr.json b/homeassistant/components/smarthab/translations/fr.json index 798f252ac5d..7bc0bdc9531 100644 --- a/homeassistant/components/smarthab/translations/fr.json +++ b/homeassistant/components/smarthab/translations/fr.json @@ -1,9 +1,9 @@ { "config": { "error": { + "invalid_auth": "Authentification invalide", "service": "Erreur de connexion \u00e0 SmartHab. V\u00e9rifiez votre connexion. Le service peut \u00eatre indisponible.", - "unknown_error": "Erreur inattendue", - "wrong_login": "Authentification invalide" + "unknown": "Erreur inattendue" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/it.json b/homeassistant/components/smarthab/translations/it.json index 07da9a0abe1..298520459f0 100644 --- a/homeassistant/components/smarthab/translations/it.json +++ b/homeassistant/components/smarthab/translations/it.json @@ -3,9 +3,7 @@ "error": { "invalid_auth": "Autenticazione non valida", "service": "Errore durante il tentativo di raggiungere SmartHab. Il servizio potrebbe non essere attivo. Controllare la connessione.", - "unknown": "Errore imprevisto", - "unknown_error": "Errore imprevisto", - "wrong_login": "Autenticazione non valida" + "unknown": "Errore imprevisto" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/ko.json b/homeassistant/components/smarthab/translations/ko.json index 295dc839df2..4b15acd2f38 100644 --- a/homeassistant/components/smarthab/translations/ko.json +++ b/homeassistant/components/smarthab/translations/ko.json @@ -1,9 +1,7 @@ { "config": { "error": { - "service": "SmartHab \uc5d0 \uc811\uc18d\ud558\ub294 \uc911 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \uc11c\ube44\uc2a4\uac00 \ub2e4\uc6b4\ub418\uc5c8\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc5f0\uacb0\uc744 \ud655\uc778\ud574\uc8fc\uc138\uc694.", - "unknown_error": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4", - "wrong_login": "\uc778\uc99d\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" + "service": "SmartHab \uc5d0 \uc811\uc18d\ud558\ub294 \uc911 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \uc11c\ube44\uc2a4\uac00 \ub2e4\uc6b4\ub418\uc5c8\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc5f0\uacb0\uc744 \ud655\uc778\ud574\uc8fc\uc138\uc694." }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/lb.json b/homeassistant/components/smarthab/translations/lb.json index d2892805fac..e651190a1e2 100644 --- a/homeassistant/components/smarthab/translations/lb.json +++ b/homeassistant/components/smarthab/translations/lb.json @@ -1,9 +1,9 @@ { "config": { "error": { + "invalid_auth": "Ong\u00eblteg Authentifikatioun", "service": "Feeler beim verbanne mat SmartHab. De Service ass viellaicht net ereechbar. Iwwerpr\u00e9if deng Verbindung.", - "unknown_error": "Onerwaarte Feeler", - "wrong_login": "Ong\u00eblteg Authentifikatioun" + "unknown": "Onerwaarte Feeler" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/nl.json b/homeassistant/components/smarthab/translations/nl.json index 7e198e836d7..9dabac8aa55 100644 --- a/homeassistant/components/smarthab/translations/nl.json +++ b/homeassistant/components/smarthab/translations/nl.json @@ -1,7 +1,15 @@ { "config": { "error": { + "service": "Fout bij het bereiken van SmartHab. De service is mogelijk uitgevallen. Controleer uw verbinding.", "unknown": "Onverwachte fout" + }, + "step": { + "user": { + "data": { + "password": "Wachtwoord" + } + } } } } \ No newline at end of file diff --git a/homeassistant/components/smarthab/translations/no.json b/homeassistant/components/smarthab/translations/no.json index 50936181c59..ed2beaf7836 100644 --- a/homeassistant/components/smarthab/translations/no.json +++ b/homeassistant/components/smarthab/translations/no.json @@ -3,9 +3,7 @@ "error": { "invalid_auth": "Ugyldig godkjenning", "service": "Feil under fors\u00f8k p\u00e5 \u00e5 n\u00e5 SmartHab. Tjenesten kan v\u00e6re nede. Sjekk tilkoblingen din.", - "unknown": "Uventet feil", - "unknown_error": "Uventet feil", - "wrong_login": "Ugyldig godkjenning" + "unknown": "Uventet feil" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/pl.json b/homeassistant/components/smarthab/translations/pl.json index 563019593bb..7b2d65b85ab 100644 --- a/homeassistant/components/smarthab/translations/pl.json +++ b/homeassistant/components/smarthab/translations/pl.json @@ -3,9 +3,7 @@ "error": { "invalid_auth": "Niepoprawne uwierzytelnienie", "service": "B\u0142\u0105d podczas pr\u00f3by osi\u0105gni\u0119cia SmartHab. Us\u0142uga mo\u017ce by\u0107 wy\u0142\u0105czna. Sprawd\u017a po\u0142\u0105czenie.", - "unknown": "Nieoczekiwany b\u0142\u0105d", - "unknown_error": "Nieoczekiwany b\u0142\u0105d", - "wrong_login": "Niepoprawne uwierzytelnienie" + "unknown": "Nieoczekiwany b\u0142\u0105d" }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/pt.json b/homeassistant/components/smarthab/translations/pt.json index 843c1c7b592..2933743c867 100644 --- a/homeassistant/components/smarthab/translations/pt.json +++ b/homeassistant/components/smarthab/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "error": { - "unknown_error": "Erro inesperado", - "wrong_login": "Autentica\u00e7\u00e3o inv\u00e1lida" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/smarthab/translations/ru.json b/homeassistant/components/smarthab/translations/ru.json index 8f7c38aecc0..cea090f51d2 100644 --- a/homeassistant/components/smarthab/translations/ru.json +++ b/homeassistant/components/smarthab/translations/ru.json @@ -3,9 +3,7 @@ "error": { "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "service": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a SmartHab. \u0421\u0435\u0440\u0432\u0438\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435.", - "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", - "unknown_error": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", - "wrong_login": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." + "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "step": { "user": { diff --git a/homeassistant/components/smarthab/translations/zh-Hans.json b/homeassistant/components/smarthab/translations/zh-Hans.json new file mode 100644 index 00000000000..f339adebd86 --- /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/smarthab/translations/zh-Hant.json b/homeassistant/components/smarthab/translations/zh-Hant.json index 629f97762b9..9f1d903a9b1 100644 --- a/homeassistant/components/smarthab/translations/zh-Hant.json +++ b/homeassistant/components/smarthab/translations/zh-Hant.json @@ -3,9 +3,7 @@ "error": { "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", "service": "\u5617\u8a66\u8a2a\u554f Smarthab \u6642\u767c\u751f\u932f\u8aa4\uff0c\u670d\u52d9\u53ef\u4ee5\u5df2\u7d93\u5931\u6548\uff0c\u8acb\u6aa2\u67e5\u9023\u7dda\u3002", - "unknown": "\u672a\u9810\u671f\u932f\u8aa4", - "unknown_error": "\u672a\u9810\u671f\u932f\u8aa4", - "wrong_login": "\u9a57\u8b49\u78bc\u7121\u6548" + "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "step": { "user": { diff --git a/homeassistant/components/smartthings/strings.json b/homeassistant/components/smartthings/strings.json index 3b8e3b208a6..dbc78dd54e2 100644 --- a/homeassistant/components/smartthings/strings.json +++ b/homeassistant/components/smartthings/strings.json @@ -15,7 +15,7 @@ "select_location": { "title": "Select Location", "description": "Please select the SmartThings Location you wish to add to Home Assistant. We will then open a new window and ask you to login and authorize installation of the Home Assistant integration into the selected location.", - "data": { "location_id": "Location" } + "data": { "location_id": "[%key:common::config_flow::data::location%]" } }, "authorize": { "title": "Authorize Home Assistant" } }, diff --git a/homeassistant/components/smartthings/translations/cs.json b/homeassistant/components/smartthings/translations/cs.json index a634bcceb0e..a9279722712 100644 --- a/homeassistant/components/smartthings/translations/cs.json +++ b/homeassistant/components/smartthings/translations/cs.json @@ -19,12 +19,14 @@ "data": { "access_token": "P\u0159\u00edstupov\u00fd token" }, + "description": "Zadejte [osobn\u00ed p\u0159\u00edstupov\u00fd token]({token_url}) SmartThings, kter\u00fd byl vytvo\u0159en podle [pokyn\u016f]({component_url}). Ten se pou\u017eije k vytvo\u0159en\u00ed integrace Home Assistant ve va\u0161em \u00fa\u010dtu SmartThings.", "title": "Zadejte osobn\u00ed p\u0159\u00edstupov\u00fd token" }, "select_location": { "data": { "location_id": "Um\u00edst\u011bn\u00ed" }, + "description": "Vyberte um\u00edst\u011bn\u00ed SmartThings, kter\u00e9 chcete p\u0159idat do Home Assistant. Pot\u00e9 otev\u0159eme nov\u00e9 okno a po\u017e\u00e1d\u00e1me v\u00e1s o p\u0159ihl\u00e1\u0161en\u00ed a autorizaci instalace integrace Home Assistant do vybran\u00e9ho um\u00edst\u011bn\u00ed.", "title": "Vyberte um\u00edst\u011bn\u00ed" }, "user": { diff --git a/homeassistant/components/smartthings/translations/et.json b/homeassistant/components/smartthings/translations/et.json index 3cfbdb25c10..04cd0d70218 100644 --- a/homeassistant/components/smartthings/translations/et.json +++ b/homeassistant/components/smartthings/translations/et.json @@ -1,15 +1,37 @@ { "config": { + "abort": { + "invalid_webhook_url": "Home Assistant pole SmartThingsilt v\u00e4rskenduste saamiseks \u00f5igesti seadistatud. Veebikonksu URL on vale:\n > {webhook_url} \n\n V\u00e4rskenda oma seadeid vastavalt [juhistele] ( {component_url} ), taask\u00e4ivita Home Assistant ja proovi uuesti.", + "no_available_locations": "Home Assistanti seadistamiseks pole saadaval \u00fchtegi SmartThingsi asukohta." + }, + "error": { + "app_setup_error": "SmartAppi pole v\u00f5imalik seadistada. Palun proovi uuesti.", + "token_forbidden": "Fraasil puuduvad n\u00f5utavad OAuthi v\u00e4\u00e4rtused.", + "token_invalid_format": "Fraas peab olema UID / GUID-vormingus", + "token_unauthorized": "Luba ei sobi v\u00f5i on kehtetu.", + "webhook_error": "SmartThings ei saanud veebihaagi URL-i kinnitada. Veendu, et veebihaagi URL oleks Internetis k\u00e4ttesaadav, ja proovi uuesti." + }, "step": { + "authorize": { + "title": "Volita Home Assistant" + }, "pat": { "data": { "access_token": "Juurdep\u00e4\u00e4sut\u00f5end" - } + }, + "description": "Sisesta SmartThingsi [isiklik juurdep\u00e4\u00e4suluba] ( {token_url} ), mis on loodud vastavalt [juhistele] ( {component_url} ). Seda kasutatakse Home Assistanti sidumise loomiseks teie SmartThingsi kontol.", + "title": "Sisesta isiklik juurdep\u00e4\u00e4suluba (PAT)" }, "select_location": { "data": { "location_id": "Asukoht" - } + }, + "description": "Vali SmartThingsi asukoht, mille soovid lisada Home Assistanti. Seej\u00e4rel avame uue akna ja palume sisse logida ning anda volitus paigaldada Home Assistanti sidumine valitud asukoha jaoks.", + "title": "Vali asukoht" + }, + "user": { + "description": "SmartThings seadistatakse saatma v\u00e4rskendusi Home Assistanti aadressil:\n > {webhook_url}\n\n Kui see pole \u00f5ige, v\u00e4rskenda oma seadeid, taask\u00e4ivita Home Assistant ja proovi uuesti.", + "title": "Kinnita tagasisideURL" } } } diff --git a/homeassistant/components/smartthings/translations/nl.json b/homeassistant/components/smartthings/translations/nl.json index d29b9b7fc35..a77ad40f0ca 100644 --- a/homeassistant/components/smartthings/translations/nl.json +++ b/homeassistant/components/smartthings/translations/nl.json @@ -16,6 +16,9 @@ "title": "Machtig Home Assistant" }, "pat": { + "data": { + "access_token": "Toegangstoken" + }, "description": "Voer een SmartThings [Personal Access Token] ( {token_url} ) in dat is gemaakt volgens de [instructies] ( {component_url} ). Dit wordt gebruikt om de Home Assistant-integratie te cre\u00ebren binnen uw SmartThings-account.", "title": "Persoonlijk toegangstoken invoeren" }, diff --git a/homeassistant/components/smartthings/translations/zh-Hant.json b/homeassistant/components/smartthings/translations/zh-Hant.json index 8a8735a8077..d9a17e46058 100644 --- a/homeassistant/components/smartthings/translations/zh-Hant.json +++ b/homeassistant/components/smartthings/translations/zh-Hant.json @@ -24,7 +24,7 @@ }, "select_location": { "data": { - "location_id": "\u4f4d\u7f6e" + "location_id": "\u5ea7\u6a19" }, "description": "\u8acb\u9078\u64c7\u6240\u8981\u52a0\u5165\u81f3 Home Assistant \u7684 SmartThings \u4f4d\u7f6e\u3002\u5c07\u6703\u958b\u555f\u65b0\u8996\u7a97\u4e26\u8a62\u554f\u767b\u5165\u8207\u8a8d\u8b49\u5b89\u88dd Home Assistant \u6574\u5408\u81f3\u6240\u9078\u4f4d\u7f6e\u3002", "title": "\u9078\u64c7\u4f4d\u7f6e" diff --git a/homeassistant/components/smhi/translations/et.json b/homeassistant/components/smhi/translations/et.json index 984b43015d7..a519c6b6918 100644 --- a/homeassistant/components/smhi/translations/et.json +++ b/homeassistant/components/smhi/translations/et.json @@ -1,6 +1,7 @@ { "config": { "error": { + "name_exists": "Nimi on juba olemas", "wrong_location": "Asukoht saab olla ainult Rootsis" }, "step": { diff --git a/homeassistant/components/sms/translations/et.json b/homeassistant/components/sms/translations/et.json index 65272c56bff..70a378d591e 100644 --- a/homeassistant/components/sms/translations/et.json +++ b/homeassistant/components/sms/translations/et.json @@ -7,6 +7,14 @@ "error": { "cannot_connect": "\u00dchendamine nurjus", "unknown": "Tundmatu viga" + }, + "step": { + "user": { + "data": { + "device": "Seade" + }, + "title": "Modemiga \u00fchenduse loomine" + } } } } \ No newline at end of file diff --git a/homeassistant/components/sms/translations/nl.json b/homeassistant/components/sms/translations/nl.json index 3d8eda89436..75dd593982a 100644 --- a/homeassistant/components/sms/translations/nl.json +++ b/homeassistant/components/sms/translations/nl.json @@ -1,10 +1,18 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { "device": "Apparaat" - } + }, + "title": "Maak verbinding met de modem" } } } diff --git a/homeassistant/components/solaredge/translations/et.json b/homeassistant/components/solaredge/translations/et.json new file mode 100644 index 00000000000..e3abcedc5c1 --- /dev/null +++ b/homeassistant/components/solaredge/translations/et.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "site_exists": "See site_id on juba konfigureeritud" + }, + "error": { + "site_exists": "See site_id on juba konfigureeritud" + }, + "step": { + "user": { + "data": { + "api_key": "API v\u00f5ti", + "name": "Selle sidumise nimi", + "site_id": "SolarEdge'i saidi ID" + }, + "title": "M\u00e4\u00e4rake selle sidumise API parameetrid" + } + } + } +} \ 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 00000000000..baf8c980cb7 --- /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/et.json b/homeassistant/components/solarlog/translations/et.json index d37ef041b4d..6e78b961c22 100644 --- a/homeassistant/components/solarlog/translations/et.json +++ b/homeassistant/components/solarlog/translations/et.json @@ -10,8 +10,10 @@ "step": { "user": { "data": { - "host": "" - } + "host": "", + "name": "Solar-Log andurite eesliide" + }, + "title": "Solar-Log'i \u00fchenduse m\u00e4\u00e4ratlemine" } } } diff --git a/homeassistant/components/solarlog/translations/lb.json b/homeassistant/components/solarlog/translations/lb.json index 153aa3dcf67..3bb0bd2c2ed 100644 --- a/homeassistant/components/solarlog/translations/lb.json +++ b/homeassistant/components/solarlog/translations/lb.json @@ -5,7 +5,7 @@ }, "error": { "already_configured": "Apparat ass scho konfigur\u00e9iert", - "cannot_connect": "Feeler beim verbannen, iwwerpr\u00e9ift w.e.g d'Adresse vum Apparat" + "cannot_connect": "Feeler beim verbannen" }, "step": { "user": { diff --git a/homeassistant/components/solarlog/translations/zh-Hans.json b/homeassistant/components/solarlog/translations/zh-Hans.json new file mode 100644 index 00000000000..2941dfd9383 --- /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/soma/translations/cs.json b/homeassistant/components/soma/translations/cs.json index eeee574cf20..5a27562df71 100644 --- a/homeassistant/components/soma/translations/cs.json +++ b/homeassistant/components/soma/translations/cs.json @@ -4,7 +4,8 @@ "already_setup": "M\u016f\u017eete nastavit pouze jeden \u00fa\u010det Soma.", "authorize_url_timeout": "\u010casov\u00fd limit autoriza\u010dn\u00edho URL vypr\u0161el", "connection_error": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed SOMA Connect se nezda\u0159ilo.", - "missing_configuration": "Integrace Soma nen\u00ed nastavena. Postupujte podle dokumentace." + "missing_configuration": "Integrace Soma nen\u00ed nastavena. Postupujte podle dokumentace.", + "result_error": "SOMA Connect odpov\u011bd\u011blo chybov\u00fdm stavem." }, "create_entry": { "default": "\u00dasp\u011b\u0161n\u011b ov\u011b\u0159eno pomoc\u00ed Soma." diff --git a/homeassistant/components/soma/translations/et.json b/homeassistant/components/soma/translations/et.json index 9da1ff9b848..728e7ec0879 100644 --- a/homeassistant/components/soma/translations/et.json +++ b/homeassistant/components/soma/translations/et.json @@ -2,7 +2,13 @@ "config": { "abort": { "already_setup": "Saad h\u00e4\u00e4lestada ainult \u00fche Soma konto.", - "connection_error": "SOMA Connect seadmega \u00fchenduse loomine nurjus." + "authorize_url_timeout": "Kinnitus-URLi loomise ajal\u00f5pp.", + "connection_error": "SOMA Connect seadmega \u00fchenduse loomine nurjus.", + "missing_configuration": "Soma komponent pole seadistatud. Palun loe dokumentatsiooni.", + "result_error": "SOMA Connect vastas t\u00f5rkeolekuga." + }, + "create_entry": { + "default": "Edukalt Soma'ga autenditud." }, "step": { "user": { @@ -10,6 +16,7 @@ "host": "", "port": "" }, + "description": "Sisesta oma SOMA Connect \u00fchenduse teave.", "title": "" } } diff --git a/homeassistant/components/soma/translations/pl.json b/homeassistant/components/soma/translations/pl.json index f23411fa288..955e1f1daf4 100644 --- a/homeassistant/components/soma/translations/pl.json +++ b/homeassistant/components/soma/translations/pl.json @@ -1,14 +1,14 @@ { "config": { "abort": { - "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno konto Soma", + "already_setup": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", "authorize_url_timeout": "Przekroczono limit czasu generowania URL autoryzacji", "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z SOMA Connect", "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105.", "result_error": "SOMA Connect odpowiedzia\u0142 statusem b\u0142\u0119du" }, "create_entry": { - "default": "Pomy\u015blnie uwierzytelniono z Soma" + "default": "Pomy\u015blnie uwierzytelniono" }, "step": { "user": { diff --git a/homeassistant/components/somfy/__init__.py b/homeassistant/components/somfy/__init__.py index df0739bba31..99b0a2ee564 100644 --- a/homeassistant/components/somfy/__init__.py +++ b/homeassistant/components/somfy/__init__.py @@ -1,15 +1,16 @@ """Support for Somfy hubs.""" +from abc import abstractmethod import asyncio from datetime import timedelta import logging from pymfy.api.devices.category import Category -from requests import HTTPError import voluptuous as vol from homeassistant.components.somfy import config_flow from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET +from homeassistant.core import callback from homeassistant.helpers import ( config_entry_oauth2_flow, config_validation as cv, @@ -17,21 +18,18 @@ from homeassistant.helpers import ( ) from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import HomeAssistantType -from homeassistant.util import Throttle +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) from . import api -from .const import DOMAIN - -API = "api" - -DEVICES = "devices" +from .const import API, CONF_OPTIMISTIC, COORDINATOR, DOMAIN _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(minutes=1) - - -CONF_OPTIMISTIC = "optimistic" +SCAN_INTERVAL_ALL_ASSUMED_STATE = timedelta(minutes=60) SOMFY_AUTH_CALLBACK_PATH = "/auth/somfy/callback" SOMFY_AUTH_START = "/auth/somfy" @@ -88,15 +86,39 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): ) ) - hass.data[DOMAIN][API] = api.ConfigEntrySomfyApi(hass, entry, implementation) - hass.data[DOMAIN][DEVICES] = [] + data = hass.data[DOMAIN] + data[API] = api.ConfigEntrySomfyApi(hass, entry, implementation) - await update_all_devices(hass) + async def _update_all_devices(): + """Update all the devices.""" + devices = await hass.async_add_executor_job(data[API].get_devices) + return {dev.id: dev for dev in devices} + + coordinator = DataUpdateCoordinator( + hass, + _LOGGER, + name="somfy device update", + update_method=_update_all_devices, + update_interval=SCAN_INTERVAL, + ) + data[COORDINATOR] = coordinator + + await coordinator.async_refresh() + + if all(not bool(device.states) for device in coordinator.data.values()): + _LOGGER.debug( + "All devices have assumed state. Update interval has been reduced to: %s", + SCAN_INTERVAL_ALL_ASSUMED_STATE, + ) + coordinator.update_interval = SCAN_INTERVAL_ALL_ASSUMED_STATE device_registry = await dr.async_get_registry(hass) - devices = hass.data[DOMAIN][DEVICES] - hubs = [device for device in devices if Category.HUB.value in device.categories] + hubs = [ + device + for device in coordinator.data.values() + if Category.HUB.value in device.categories + ] for hub in hubs: device_registry.async_get_or_create( @@ -127,18 +149,24 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry): return True -class SomfyEntity(Entity): +class SomfyEntity(CoordinatorEntity, Entity): """Representation of a generic Somfy device.""" - def __init__(self, device, somfy_api): + def __init__(self, coordinator, device_id, somfy_api): """Initialize the Somfy device.""" - self.device = device + super().__init__(coordinator) + self._id = device_id self.api = somfy_api + @property + def device(self): + """Return data for the device id.""" + return self.coordinator.data[self._id] + @property def unique_id(self): """Return the unique id base on the id returned by Somfy.""" - return self.device.id + return self._id @property def name(self): @@ -160,23 +188,22 @@ class SomfyEntity(Entity): "manufacturer": "Somfy", } - async def async_update(self): - """Update the device with the latest data.""" - await update_all_devices(self.hass) - devices = self.hass.data[DOMAIN][DEVICES] - self.device = next((d for d in devices if d.id == self.device.id), self.device) - def has_capability(self, capability): """Test if device has a capability.""" capabilities = self.device.capabilities return bool([c for c in capabilities if c.name == capability]) + @property + def assumed_state(self): + """Return if the device has an assumed state.""" + return not bool(self.device.states) -@Throttle(SCAN_INTERVAL) -async def update_all_devices(hass): - """Update all the devices.""" - try: - data = hass.data[DOMAIN] - data[DEVICES] = await hass.async_add_executor_job(data[API].get_devices) - except HTTPError as err: - _LOGGER.warning("Cannot update devices: %s", err.response.status_code) + @callback + def _handle_coordinator_update(self): + """Process an update from the coordinator.""" + self._create_device() + super()._handle_coordinator_update() + + @abstractmethod + def _create_device(self): + """Update the device with the latest data.""" diff --git a/homeassistant/components/somfy/const.py b/homeassistant/components/somfy/const.py index 8765e37e6d6..aca93be66cb 100644 --- a/homeassistant/components/somfy/const.py +++ b/homeassistant/components/somfy/const.py @@ -1,3 +1,6 @@ """Define constants for the Somfy component.""" DOMAIN = "somfy" +COORDINATOR = "coordinator" +API = "api" +CONF_OPTIMISTIC = "optimistic" diff --git a/homeassistant/components/somfy/cover.py b/homeassistant/components/somfy/cover.py index cddde87d8f6..605d58a941b 100644 --- a/homeassistant/components/somfy/cover.py +++ b/homeassistant/components/somfy/cover.py @@ -1,14 +1,28 @@ """Support for Somfy Covers.""" + from pymfy.api.devices.blind import Blind from pymfy.api.devices.category import Category from homeassistant.components.cover import ( ATTR_POSITION, ATTR_TILT_POSITION, + DEVICE_CLASS_BLIND, + DEVICE_CLASS_SHUTTER, CoverEntity, ) +from homeassistant.const import STATE_CLOSED, STATE_OPEN +from homeassistant.helpers.restore_state import RestoreEntity -from . import API, CONF_OPTIMISTIC, DEVICES, DOMAIN, SomfyEntity +from . import SomfyEntity +from .const import API, CONF_OPTIMISTIC, COORDINATOR, DOMAIN + +BLIND_DEVICE_CATEGORIES = {Category.INTERIOR_BLIND.value, Category.EXTERIOR_BLIND.value} +SHUTTER_DEVICE_CATEGORIES = {Category.EXTERIOR_BLIND.value} +SUPPORTED_CATEGORIES = { + Category.ROLLER_SHUTTER.value, + Category.INTERIOR_BLIND.value, + Category.EXTERIOR_BLIND.value, +} async def async_setup_entry(hass, config_entry, async_add_entities): @@ -16,51 +30,60 @@ async def async_setup_entry(hass, config_entry, async_add_entities): def get_covers(): """Retrieve covers.""" - categories = { - Category.ROLLER_SHUTTER.value, - Category.INTERIOR_BLIND.value, - Category.EXTERIOR_BLIND.value, - } - - devices = hass.data[DOMAIN][DEVICES] + domain_data = hass.data[DOMAIN] + coordinator = domain_data[COORDINATOR] + api = domain_data[API] return [ - SomfyCover( - cover, hass.data[DOMAIN][API], hass.data[DOMAIN][CONF_OPTIMISTIC] - ) - for cover in devices - if categories & set(cover.categories) + SomfyCover(coordinator, device_id, api, domain_data[CONF_OPTIMISTIC]) + for device_id, device in coordinator.data.items() + if SUPPORTED_CATEGORIES & set(device.categories) ] - async_add_entities(await hass.async_add_executor_job(get_covers), True) + async_add_entities(await hass.async_add_executor_job(get_covers)) -class SomfyCover(SomfyEntity, CoverEntity): +class SomfyCover(SomfyEntity, RestoreEntity, CoverEntity): """Representation of a Somfy cover device.""" - def __init__(self, device, api, optimistic): + def __init__(self, coordinator, device_id, api, optimistic): """Initialize the Somfy device.""" - super().__init__(device, api) - self.cover = Blind(self.device, self.api) + super().__init__(coordinator, device_id, api) + self.categories = set(self.device.categories) self.optimistic = optimistic self._closed = None + self._is_opening = None + self._is_closing = None + self.cover = None + self._create_device() - async def async_update(self): + def _create_device(self): """Update the device with the latest data.""" - await super().async_update() self.cover = Blind(self.device, self.api) - def close_cover(self, **kwargs): + async def async_close_cover(self, **kwargs): """Close the cover.""" - if self.optimistic: + self._is_closing = True + self.async_write_ha_state() + try: + # Blocks until the close command is sent + await self.hass.async_add_executor_job(self.cover.close) self._closed = True - self.cover.close() + finally: + self._is_closing = None + self.async_write_ha_state() - def open_cover(self, **kwargs): + async def async_open_cover(self, **kwargs): """Open the cover.""" - if self.optimistic: + self._is_opening = True + self.async_write_ha_state() + try: + # Blocks until the open command is sent + await self.hass.async_add_executor_job(self.cover.open) self._closed = False - self.cover.open() + finally: + self._is_opening = None + self.async_write_ha_state() def stop_cover(self, **kwargs): """Stop the cover.""" @@ -70,6 +93,15 @@ class SomfyCover(SomfyEntity, CoverEntity): """Move the cover shutter to a specific position.""" self.cover.set_position(100 - kwargs[ATTR_POSITION]) + @property + def device_class(self): + """Return the device class.""" + if self.categories & BLIND_DEVICE_CATEGORIES: + return DEVICE_CLASS_BLIND + if self.categories & SHUTTER_DEVICE_CATEGORIES: + return DEVICE_CLASS_SHUTTER + return None + @property def current_cover_position(self): """Return the current position of cover shutter.""" @@ -78,6 +110,20 @@ class SomfyCover(SomfyEntity, CoverEntity): position = 100 - self.cover.get_position() return position + @property + def is_opening(self): + """Return if the cover is opening.""" + if not self.optimistic: + return None + return self._is_opening + + @property + def is_closing(self): + """Return if the cover is closing.""" + if not self.optimistic: + return None + return self._is_closing + @property def is_closed(self): """Return if the cover is closed.""" @@ -114,3 +160,17 @@ class SomfyCover(SomfyEntity, CoverEntity): def stop_cover_tilt(self, **kwargs): """Stop the cover.""" self.cover.stop() + + async def async_added_to_hass(self): + """Complete the initialization.""" + await super().async_added_to_hass() + if not self.optimistic: + return + # Restore the last state if we use optimistic + last_state = await self.async_get_last_state() + + if last_state is not None and last_state.state in ( + STATE_OPEN, + STATE_CLOSED, + ): + self._closed = last_state.state == STATE_CLOSED diff --git a/homeassistant/components/somfy/manifest.json b/homeassistant/components/somfy/manifest.json index ab24d21b2e1..69450c4c4dc 100644 --- a/homeassistant/components/somfy/manifest.json +++ b/homeassistant/components/somfy/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/somfy", "dependencies": ["http"], "codeowners": ["@tetienne"], - "requirements": ["pymfy==0.9.0"] + "requirements": ["pymfy==0.9.1"] } diff --git a/homeassistant/components/somfy/switch.py b/homeassistant/components/somfy/switch.py index e96c91ecaea..d614776778e 100644 --- a/homeassistant/components/somfy/switch.py +++ b/homeassistant/components/somfy/switch.py @@ -4,7 +4,8 @@ from pymfy.api.devices.category import Category from homeassistant.components.switch import SwitchEntity -from . import API, DEVICES, DOMAIN, SomfyEntity +from . import SomfyEntity +from .const import API, COORDINATOR, DOMAIN async def async_setup_entry(hass, config_entry, async_add_entities): @@ -12,11 +13,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities): def get_shutters(): """Retrieve switches.""" - devices = hass.data[DOMAIN][DEVICES] + domain_data = hass.data[DOMAIN] + coordinator = domain_data[COORDINATOR] + api = domain_data[API] return [ - SomfyCameraShutter(device, hass.data[DOMAIN][API]) - for device in devices + SomfyCameraShutter(coordinator, device_id, api) + for device_id, device in coordinator.data.items() if Category.CAMERA.value in device.categories ] @@ -26,14 +29,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class SomfyCameraShutter(SomfyEntity, SwitchEntity): """Representation of a Somfy Camera Shutter device.""" - def __init__(self, device, api): + def __init__(self, coordinator, device_id, api): """Initialize the Somfy device.""" - super().__init__(device, api) - self.shutter = CameraProtect(self.device, self.api) + super().__init__(coordinator, device_id, api) + self._create_device() - async def async_update(self): + def _create_device(self): """Update the device with the latest data.""" - await super().async_update() self.shutter = CameraProtect(self.device, self.api) def turn_on(self, **kwargs) -> None: diff --git a/homeassistant/components/somfy/translations/bg.json b/homeassistant/components/somfy/translations/bg.json index f115865a2b8..4ac8389ad42 100644 --- a/homeassistant/components/somfy/translations/bg.json +++ b/homeassistant/components/somfy/translations/bg.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u041c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u0438\u043d Somfy \u0430\u043a\u0430\u0443\u043d\u0442.", "authorize_url_timeout": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u0437\u0430 \u043e\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0432 \u0441\u0440\u043e\u043a.", "missing_configuration": "\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044a\u0442 Somfy \u043d\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d. \u041c\u043e\u043b\u044f, \u0441\u043b\u0435\u0434\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430." }, diff --git a/homeassistant/components/somfy/translations/ca.json b/homeassistant/components/somfy/translations/ca.json index 142be053b45..bc34c57c939 100644 --- a/homeassistant/components/somfy/translations/ca.json +++ b/homeassistant/components/somfy/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Nom\u00e9s pots configurar un \u00fanic compte amb Somfy.", "authorize_url_timeout": "Temps d'espera esgotat durant la generaci\u00f3 de l'URL d'autoritzaci\u00f3.", "missing_configuration": "El component no est\u00e0 configurat. Mira'n la documentaci\u00f3.", "no_url_available": "No hi ha cap URL disponible. Per a m\u00e9s informaci\u00f3 sobre aquest error, [consulta la secci\u00f3 d'ajuda]({docs_url})", diff --git a/homeassistant/components/somfy/translations/cs.json b/homeassistant/components/somfy/translations/cs.json index 32cf8c8d08d..acc7d260cad 100644 --- a/homeassistant/components/somfy/translations/cs.json +++ b/homeassistant/components/somfy/translations/cs.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "M\u016f\u017eete nastavit pouze jeden \u00fa\u010det Somfy.", "authorize_url_timeout": "\u010casov\u00fd limit autoriza\u010dn\u00edho URL vypr\u0161el", "missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace.", "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})", diff --git a/homeassistant/components/somfy/translations/da.json b/homeassistant/components/somfy/translations/da.json index be7d8e94193..3b7a79ef008 100644 --- a/homeassistant/components/somfy/translations/da.json +++ b/homeassistant/components/somfy/translations/da.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan kun konfigurere en enkelt Somfy konto.", "authorize_url_timeout": "Timeout ved generering af autoriseret url.", "missing_configuration": "Komponenten Somfy er ikke konfigureret. F\u00f8lg venligst dokumentationen." }, diff --git a/homeassistant/components/somfy/translations/de.json b/homeassistant/components/somfy/translations/de.json index b2f27a8fcca..6b76e2f61be 100644 --- a/homeassistant/components/somfy/translations/de.json +++ b/homeassistant/components/somfy/translations/de.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Es kann nur ein Somfy-Account konfiguriert werden.", "authorize_url_timeout": "Zeit\u00fcberschreitung beim Erstellen der Authorisierungs-URL.", "missing_configuration": "Die Somfy-Komponente ist nicht konfiguriert. Folge bitte der Dokumentation." }, diff --git a/homeassistant/components/somfy/translations/en.json b/homeassistant/components/somfy/translations/en.json index 9dede6ab53f..e0072d1da4d 100644 --- a/homeassistant/components/somfy/translations/en.json +++ b/homeassistant/components/somfy/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "You can only configure one Somfy account.", "authorize_url_timeout": "Timeout generating authorize URL.", "missing_configuration": "The component is not configured. Please follow the documentation.", "no_url_available": "No URL available. For information about this error, [check the help section]({docs_url})", diff --git a/homeassistant/components/somfy/translations/es-419.json b/homeassistant/components/somfy/translations/es-419.json index 3667a72315b..6acd9bb6bb8 100644 --- a/homeassistant/components/somfy/translations/es-419.json +++ b/homeassistant/components/somfy/translations/es-419.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Solo puede configurar una cuenta Somfy.", "authorize_url_timeout": "Tiempo de espera agotado para generar la URL de autorizaci\u00f3n.", "missing_configuration": "El componente Somfy no est\u00e1 configurado. Por favor, siga la documentaci\u00f3n." }, diff --git a/homeassistant/components/somfy/translations/es.json b/homeassistant/components/somfy/translations/es.json index 259fe360dd6..1fd22ebda3f 100644 --- a/homeassistant/components/somfy/translations/es.json +++ b/homeassistant/components/somfy/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Solo puedes configurar una cuenta de Somfy.", "authorize_url_timeout": "Tiempo de espera agotado generando la url de autorizaci\u00f3n", "missing_configuration": "El componente Somfy no est\u00e1 configurado. Por favor, sigue la documentaci\u00f3n.", "no_url_available": "No hay URL disponible. Para obtener informaci\u00f3n sobre este error, [consulta la secci\u00f3n de ayuda]({docs_url})", diff --git a/homeassistant/components/somfy/translations/et.json b/homeassistant/components/somfy/translations/et.json index 184faad8f40..9239f7df0ef 100644 --- a/homeassistant/components/somfy/translations/et.json +++ b/homeassistant/components/somfy/translations/et.json @@ -1,10 +1,14 @@ { "config": { "abort": { - "already_setup": "Saad h\u00e4\u00e4lestada ainult \u00fche Somfy konto.", + "authorize_url_timeout": "Kinnitus-URLi loomise ajal\u00f5pp.", + "missing_configuration": "Komponent pole seadistatud. Palun loe dokumentatsiooni.", "no_url_available": "URL pole saadaval. Rohkem teavet [check the help section]({docs_url})", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, + "create_entry": { + "default": "Edukalt tuvastatud" + }, "step": { "pick_implementation": { "title": "Vali tuvastusmeetod" diff --git a/homeassistant/components/somfy/translations/fr.json b/homeassistant/components/somfy/translations/fr.json index 3214b3a36de..c8783effc28 100644 --- a/homeassistant/components/somfy/translations/fr.json +++ b/homeassistant/components/somfy/translations/fr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Vous ne pouvez configurer qu'un seul compte Somfy.", "authorize_url_timeout": "D\u00e9lai de g\u00e9n\u00e9ration d'url autoriser.", "missing_configuration": "Le composant Somfy n'est pas configur\u00e9. Veuillez suivre la documentation.", "no_url_available": "Aucune URL disponible. Pour plus d'informations sur cette erreur, [consultez la section d'aide] ( {docs_url} )", diff --git a/homeassistant/components/somfy/translations/it.json b/homeassistant/components/somfy/translations/it.json index 20b645159cc..1c6650232dc 100644 --- a/homeassistant/components/somfy/translations/it.json +++ b/homeassistant/components/somfy/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u00c8 possibile configurare un solo account Somfy.", "authorize_url_timeout": "Tempo scaduto nel generare l'URL di autorizzazione.", "missing_configuration": "Il componente non \u00e8 configurato. Si prega di seguire la documentazione.", "no_url_available": "Nessun URL disponibile. Per informazioni su questo errore, [controlla la sezione della guida]({docs_url})", diff --git a/homeassistant/components/somfy/translations/ko.json b/homeassistant/components/somfy/translations/ko.json index 43d4ba146b3..5119670f766 100644 --- a/homeassistant/components/somfy/translations/ko.json +++ b/homeassistant/components/somfy/translations/ko.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\ud558\ub098\uc758 Somfy \uacc4\uc815\ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.", "authorize_url_timeout": "\uc778\uc99d url \uc0dd\uc131 \uc2dc\uac04\uc774 \ucd08\uacfc\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "missing_configuration": "Somfy \uad6c\uc131\uc694\uc18c\uac00 \uad6c\uc131\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \uc124\uba85\uc11c\ub97c \ucc38\uace0\ud574\uc8fc\uc138\uc694.", "no_url_available": "\uac00\ub2a5\ud55c URL\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. \uc774 \uc5d0\ub7ec\uc5d0 \ub300\ud55c \uc815\ubcf4\ub294 \ub3c4\uc6c0\ub9d0 \uc139\uc158\uc744 \ud655\uc778\ud558\uc138\uc694({docs_url})", diff --git a/homeassistant/components/somfy/translations/lb.json b/homeassistant/components/somfy/translations/lb.json index 849e2fbadce..a463473c2e1 100644 --- a/homeassistant/components/somfy/translations/lb.json +++ b/homeassistant/components/somfy/translations/lb.json @@ -1,18 +1,17 @@ { "config": { "abort": { - "already_setup": "Dir k\u00ebnnt n\u00ebmmen een eenzegen Somfy Kont konfigur\u00e9ieren.", "authorize_url_timeout": "Z\u00e4it Iwwerschreidung beim gener\u00e9ieren vun der Autorisatiouns URL.", - "missing_configuration": "D'Somfy Komponent ass nach net konfigur\u00e9iert. Follegt w.e.g der Dokumentatioun.", + "missing_configuration": "Komponent ass nach net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun.", "no_url_available": "Keng URL disponibel. Fir Informatiounen iwwert d\u00ebse Feeler, [kuck H\u00ebllef Sektioun]({docs_url})", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { - "default": "Erfollegr\u00e4ich mat Somfy authentifiz\u00e9iert." + "default": "Erfollegr\u00e4ich authentifiz\u00e9iert." }, "step": { "pick_implementation": { - "title": "Wielt Authentifikatiouns Method aus" + "title": "Wiel Authentifikatiouns Method aus" } } } diff --git a/homeassistant/components/somfy/translations/nl.json b/homeassistant/components/somfy/translations/nl.json index 58143628d17..423dbb6a2bb 100644 --- a/homeassistant/components/somfy/translations/nl.json +++ b/homeassistant/components/somfy/translations/nl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "U kunt slechts \u00e9\u00e9n Somfy-account configureren.", "authorize_url_timeout": "Time-out tijdens genereren autorisatie url.", "missing_configuration": "Het Somfy-component is niet geconfigureerd. Gelieve de documentatie te volgen.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." diff --git a/homeassistant/components/somfy/translations/no.json b/homeassistant/components/somfy/translations/no.json index 124975762c3..2bb48d39f29 100644 --- a/homeassistant/components/somfy/translations/no.json +++ b/homeassistant/components/somfy/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan kun konfigurere \u00e9n Somfy-konto.", "authorize_url_timeout": "Tidsavbrudd som genererer autorer URL-adresse.", "missing_configuration": "Komponenten er ikke konfigurert. Vennligst f\u00f8lg dokumentasjonen.", "no_url_available": "Ingen URL tilgjengelig. For informasjon om denne feilen, [sjekk hjelpseksjonen]({docs_url})", diff --git a/homeassistant/components/somfy/translations/pl.json b/homeassistant/components/somfy/translations/pl.json index 7bd4bc4abf6..baeb38e755e 100644 --- a/homeassistant/components/somfy/translations/pl.json +++ b/homeassistant/components/somfy/translations/pl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno konto Somfy", "authorize_url_timeout": "Przekroczono limit czasu generowania URL autoryzacji", "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105.", "no_url_available": "Brak dost\u0119pnego adresu URL. Aby uzyska\u0107 informacje na temat tego b\u0142\u0119du, [sprawd\u017a sekcj\u0119 pomocy] ({docs_url})", diff --git a/homeassistant/components/somfy/translations/pt-BR.json b/homeassistant/components/somfy/translations/pt-BR.json index 81c0de81e70..2f337742870 100644 --- a/homeassistant/components/somfy/translations/pt-BR.json +++ b/homeassistant/components/somfy/translations/pt-BR.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Voc\u00ea s\u00f3 pode configurar uma conta Somfy.", "authorize_url_timeout": "Excedido tempo limite gerando a URL de autoriza\u00e7\u00e3o.", "missing_configuration": "O componente Somfy n\u00e3o est\u00e1 configurado. Por favor, siga a documenta\u00e7\u00e3o." }, diff --git a/homeassistant/components/somfy/translations/ru.json b/homeassistant/components/somfy/translations/ru.json index 16205dabc3f..0451cbbaa29 100644 --- a/homeassistant/components/somfy/translations/ru.json +++ b/homeassistant/components/somfy/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "authorize_url_timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.", "missing_configuration": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438.", "no_url_available": "URL-\u0430\u0434\u0440\u0435\u0441 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d. \u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439]({docs_url}) \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u044d\u0442\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0435.", diff --git a/homeassistant/components/somfy/translations/sl.json b/homeassistant/components/somfy/translations/sl.json index b86ea9b33cb..3b9bc038fe6 100644 --- a/homeassistant/components/somfy/translations/sl.json +++ b/homeassistant/components/somfy/translations/sl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Nastavite lahko samo en ra\u010dun Somfy.", "authorize_url_timeout": "\u010casovna omejitev za generiranje potrditvenega URL-ja je potekla.", "missing_configuration": "Komponenta Somfy ni konfigurirana. Upo\u0161tevajte dokumentacijo." }, diff --git a/homeassistant/components/somfy/translations/sv.json b/homeassistant/components/somfy/translations/sv.json index 6f3d15206eb..cf0a8ec75bf 100644 --- a/homeassistant/components/somfy/translations/sv.json +++ b/homeassistant/components/somfy/translations/sv.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan endast konfigurera ett Somfy-konto.", "authorize_url_timeout": "Timeout vid skapandet av en auktoriseringsadress.", "missing_configuration": "Somfy-komponenten \u00e4r inte konfigurerad. V\u00e4nligen f\u00f6lj dokumentationen." }, diff --git a/homeassistant/components/somfy/translations/zh-Hant.json b/homeassistant/components/somfy/translations/zh-Hant.json index 4d3d5dc85fb..4768da884da 100644 --- a/homeassistant/components/somfy/translations/zh-Hant.json +++ b/homeassistant/components/somfy/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44 Somfy \u5e33\u865f\u3002", "authorize_url_timeout": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u903e\u6642\u3002", "missing_configuration": "\u5143\u4ef6\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002", "no_url_available": "\u6c92\u6709\u53ef\u7528\u7684\u7db2\u5740\u3002\u95dc\u65bc\u6b64\u932f\u8aa4\u66f4\u8a73\u7d30\u8a0a\u606f\uff0c[\u9ede\u9078\u5354\u52a9\u7ae0\u7bc0]({docs_url})", diff --git a/homeassistant/components/sonarr/__init__.py b/homeassistant/components/sonarr/__init__.py index d3330eab64b..3e2a5498c55 100644 --- a/homeassistant/components/sonarr/__init__.py +++ b/homeassistant/components/sonarr/__init__.py @@ -18,7 +18,6 @@ from homeassistant.const import ( ) from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import HomeAssistantType @@ -125,9 +124,7 @@ def _async_start_reauth(hass: HomeAssistantType, entry: ConfigEntry): async def _async_update_listener(hass: HomeAssistantType, entry: ConfigEntry) -> None: """Handle options update.""" - async_dispatcher_send( - hass, f"sonarr.{entry.entry_id}.entry_options_update", entry.options - ) + await hass.config_entries.async_reload(entry.entry_id) class SonarrEntity(Entity): diff --git a/homeassistant/components/sonarr/sensor.py b/homeassistant/components/sonarr/sensor.py index 880019ecdd3..8a625846744 100644 --- a/homeassistant/components/sonarr/sensor.py +++ b/homeassistant/components/sonarr/sensor.py @@ -7,7 +7,6 @@ from sonarr import Sonarr, SonarrConnectionError, SonarrError from homeassistant.config_entries import ConfigEntry from homeassistant.const import DATA_GIGABYTES -from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import HomeAssistantType import homeassistant.util.dt as dt_util @@ -291,18 +290,6 @@ class SonarrUpcomingSensor(SonarrSensor): unit_of_measurement="Episodes", ) - async def async_added_to_hass(self): - """Listen for signals.""" - await super().async_added_to_hass() - - self.async_on_remove( - async_dispatcher_connect( - self.hass, - f"sonarr.{self._entry_id}.entry_options_update", - self.async_update_entry_options, - ) - ) - @sonarr_exception_handler async def async_update(self) -> None: """Update entity.""" @@ -313,10 +300,6 @@ class SonarrUpcomingSensor(SonarrSensor): start=start.isoformat(), end=end.isoformat() ) - async def async_update_entry_options(self, options: dict) -> None: - """Update sensor settings when config entry options are update.""" - self._days = options[CONF_UPCOMING_DAYS] - @property def device_state_attributes(self) -> Optional[Dict[str, Any]]: """Return the state attributes of the entity.""" @@ -352,28 +335,12 @@ class SonarrWantedSensor(SonarrSensor): enabled_default=False, ) - async def async_added_to_hass(self): - """Listen for signals.""" - await super().async_added_to_hass() - - self.async_on_remove( - async_dispatcher_connect( - self.hass, - f"sonarr.{self._entry_id}.entry_options_update", - self.async_update_entry_options, - ) - ) - @sonarr_exception_handler async def async_update(self) -> None: """Update entity.""" self._results = await self.sonarr.wanted(page_size=self._max_items) self._total = self._results.total - async def async_update_entry_options(self, options: dict) -> None: - """Update sensor settings when config entry options are update.""" - self._max_items = options[CONF_WANTED_MAX_ITEMS] - @property def device_state_attributes(self) -> Optional[Dict[str, Any]]: """Return the state attributes of the entity.""" diff --git a/homeassistant/components/sonarr/strings.json b/homeassistant/components/sonarr/strings.json index e4de5cb9193..2b9a795b8a7 100644 --- a/homeassistant/components/sonarr/strings.json +++ b/homeassistant/components/sonarr/strings.json @@ -1,10 +1,8 @@ { - "title": "Sonarr", "config": { "flow_title": "Sonarr: {name}", "step": { "user": { - "title": "Connect to Sonarr", "data": { "host": "[%key:common::config_flow::data::host%]", "api_key": "[%key:common::config_flow::data::api_key%]", diff --git a/homeassistant/components/sonarr/translations/ca.json b/homeassistant/components/sonarr/translations/ca.json index 00e6a487394..7f9d34d7ce0 100644 --- a/homeassistant/components/sonarr/translations/ca.json +++ b/homeassistant/components/sonarr/translations/ca.json @@ -23,8 +23,7 @@ "port": "Port", "ssl": "Utilitza un certificat SSL", "verify_ssl": "Verifica el certificat SSL" - }, - "title": "Connexi\u00f3 amb Sonarr" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/cs.json b/homeassistant/components/sonarr/translations/cs.json index ac75f614029..00ff1611319 100644 --- a/homeassistant/components/sonarr/translations/cs.json +++ b/homeassistant/components/sonarr/translations/cs.json @@ -12,6 +12,7 @@ "flow_title": "Sonarr: {name}", "step": { "reauth_confirm": { + "description": "Integraci Sonarr je t\u0159eba ru\u010dn\u011b znovu ov\u011b\u0159it pomoc\u00ed API Sonarr hostovan\u00e9ho na adrese: {host}", "title": "Znovu ov\u011b\u0159it integraci" }, "user": { @@ -21,10 +22,18 @@ "port": "Port", "ssl": "Pou\u017e\u00edv\u00e1 SSL certifik\u00e1t", "verify_ssl": "Ov\u011b\u0159it certifik\u00e1t SSL" - }, - "title": "P\u0159ipojen\u00ed k Sonarr" + } } } }, - "title": "Sonarr" + "options": { + "step": { + "init": { + "data": { + "upcoming_days": "Po\u010det nadch\u00e1zej\u00edc\u00edch dn\u016f k zobrazen\u00ed", + "wanted_max_items": "Maxim\u00e1ln\u00ed po\u017eadovan\u00fd po\u010det polo\u017eek k zobrazen\u00ed" + } + } + } + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/de.json b/homeassistant/components/sonarr/translations/de.json index 358da02bc20..3abc6b45ef3 100644 --- a/homeassistant/components/sonarr/translations/de.json +++ b/homeassistant/components/sonarr/translations/de.json @@ -14,10 +14,8 @@ "base_path": "Pfad zur API", "host": "Host", "port": "Port" - }, - "title": "Mit Sonarr verbinden" + } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/en.json b/homeassistant/components/sonarr/translations/en.json index 25b3b9f9495..638b9a1668a 100644 --- a/homeassistant/components/sonarr/translations/en.json +++ b/homeassistant/components/sonarr/translations/en.json @@ -23,8 +23,7 @@ "port": "Port", "ssl": "Uses an SSL certificate", "verify_ssl": "Verify SSL certificate" - }, - "title": "Connect to Sonarr" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/es.json b/homeassistant/components/sonarr/translations/es.json index 8eb1d02d805..cee9f6661c5 100644 --- a/homeassistant/components/sonarr/translations/es.json +++ b/homeassistant/components/sonarr/translations/es.json @@ -23,8 +23,7 @@ "port": "Puerto", "ssl": "Utiliza un certificado SSL", "verify_ssl": "Verificar certificado SSL" - }, - "title": "Conectar a Sonarr" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/et.json b/homeassistant/components/sonarr/translations/et.json index 895936e5ce6..957b3c74eae 100644 --- a/homeassistant/components/sonarr/translations/et.json +++ b/homeassistant/components/sonarr/translations/et.json @@ -9,6 +9,7 @@ "cannot_connect": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamine nurjus" }, + "flow_title": "", "step": { "reauth_confirm": { "description": "Sonarr-i sidumine tuleb k\u00e4sitsi taastuvastada Sonarr API abil: {host}", @@ -16,12 +17,24 @@ }, "user": { "data": { + "api_key": "API v\u00f5ti", + "base_path": "API asukoht", "host": "", "port": "", + "ssl": "Kasutab SSL serti", "verify_ssl": "Kontrolli SSL sertifikaati" } } } }, - "title": "" + "options": { + "step": { + "init": { + "data": { + "upcoming_days": "Kuvatavate eelseisvate p\u00e4evade arv", + "wanted_max_items": "Kuvatavate soovitud \u00fcksuste maksimaalne arv" + } + } + } + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/fr.json b/homeassistant/components/sonarr/translations/fr.json index 91d3b0db419..6fa91de98a4 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": { @@ -21,8 +23,7 @@ "port": "Port", "ssl": "Sonarr utilise un certificat SSL", "verify_ssl": "Sonarr utilise un certificat appropri\u00e9" - }, - "title": "Se connecter \u00e0 Sonarr" + } } } }, @@ -35,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/it.json b/homeassistant/components/sonarr/translations/it.json index cc57bb2ef27..1a383201ab1 100644 --- a/homeassistant/components/sonarr/translations/it.json +++ b/homeassistant/components/sonarr/translations/it.json @@ -13,7 +13,7 @@ "step": { "reauth_confirm": { "description": "L'integrazione di Sonarr deve essere nuovamente autenticata manualmente con l'API Sonarr ospitata su: {host}", - "title": "Eseguire nuovamente l'autenticazione con Sonarr" + "title": "Reautenticare l'integrazione" }, "user": { "data": { @@ -23,8 +23,7 @@ "port": "Porta", "ssl": "Utilizza un certificato SSL", "verify_ssl": "Verificare il certificato SSL" - }, - "title": "Connettiti a Sonarr" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/ko.json b/homeassistant/components/sonarr/translations/ko.json index d08f188303a..fe650991778 100644 --- a/homeassistant/components/sonarr/translations/ko.json +++ b/homeassistant/components/sonarr/translations/ko.json @@ -18,8 +18,7 @@ "port": "\ud3ec\ud2b8", "ssl": "Sonarr \ub294 SSL \uc778\uc99d\uc11c\ub97c \uc0ac\uc6a9\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4", "verify_ssl": "Sonarr \ub294 \uc62c\ubc14\ub978 \uc778\uc99d\uc11c\ub97c \uc0ac\uc6a9\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4" - }, - "title": "Sonarr \uc5d0 \uc5f0\uacb0\ud558\uae30" + } } } }, @@ -32,6 +31,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/lb.json b/homeassistant/components/sonarr/translations/lb.json index 554bb3eebd2..392b3f7d4e2 100644 --- a/homeassistant/components/sonarr/translations/lb.json +++ b/homeassistant/components/sonarr/translations/lb.json @@ -13,7 +13,7 @@ "step": { "reauth_confirm": { "description": "Sonarr Integratioun muss manuell mat der Sonarr API um {host} re-authentifiz\u00e9iert ginn.", - "title": "Mat Sonarr re-authentifiz\u00e9ieren" + "title": "Integratioun re-authentifiz\u00e9ieren" }, "user": { "data": { @@ -21,10 +21,9 @@ "base_path": "Pad zur API", "host": "Host", "port": "Port", - "ssl": "Sonarr benotzt een SSL Zertifikat", - "verify_ssl": "Sonarr benotzt ee g\u00ebltegen SSL Zertifikat" - }, - "title": "Mat Sonarr verbannen" + "ssl": "Benotzt ee SSL Zertifikat", + "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/nl.json b/homeassistant/components/sonarr/translations/nl.json index c1909b19508..58db7f57dd4 100644 --- a/homeassistant/components/sonarr/translations/nl.json +++ b/homeassistant/components/sonarr/translations/nl.json @@ -1,9 +1,21 @@ { "config": { + "abort": { + "already_configured": "Service is al geconfigureerd", + "unknown": "Onverwachte fout" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie" + }, "step": { "user": { "data": { - "port": "Poort" + "api_key": "API-sleutel", + "host": "Host", + "port": "Poort", + "ssl": "Maakt gebruik van een SSL-certificaat", + "verify_ssl": "SSL-certificaat verifi\u00ebren" } } } diff --git a/homeassistant/components/sonarr/translations/no.json b/homeassistant/components/sonarr/translations/no.json index 2f42563b4b3..39f14020aec 100644 --- a/homeassistant/components/sonarr/translations/no.json +++ b/homeassistant/components/sonarr/translations/no.json @@ -23,8 +23,7 @@ "port": "Port", "ssl": "Bruker et SSL-sertifikat", "verify_ssl": "Verifisere SSL-sertifikat" - }, - "title": "Koble til Sonarr" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/pl.json b/homeassistant/components/sonarr/translations/pl.json index c119d5fe781..217f0b06d27 100644 --- a/homeassistant/components/sonarr/translations/pl.json +++ b/homeassistant/components/sonarr/translations/pl.json @@ -23,8 +23,7 @@ "port": "Port", "ssl": "Certyfikat SSL", "verify_ssl": "Weryfikacja certyfikatu SSL" - }, - "title": "Po\u0142\u0105czenie z Sonarr" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/ru.json b/homeassistant/components/sonarr/translations/ru.json index 9bf7bc39437..1b6345d4563 100644 --- a/homeassistant/components/sonarr/translations/ru.json +++ b/homeassistant/components/sonarr/translations/ru.json @@ -23,8 +23,7 @@ "port": "\u041f\u043e\u0440\u0442", "ssl": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 SSL", "verify_ssl": "\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 SSL" - }, - "title": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a Sonarr" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/sonarr/translations/sv.json b/homeassistant/components/sonarr/translations/sv.json index 67ab4524465..7745fb77e1b 100644 --- a/homeassistant/components/sonarr/translations/sv.json +++ b/homeassistant/components/sonarr/translations/sv.json @@ -4,8 +4,7 @@ "user": { "data": { "api_key": "API nyckel" - }, - "title": "Anslut till Sonarr" + } } } } diff --git a/homeassistant/components/sonarr/translations/zh-Hant.json b/homeassistant/components/sonarr/translations/zh-Hant.json index 04792776046..ec79d26532d 100644 --- a/homeassistant/components/sonarr/translations/zh-Hant.json +++ b/homeassistant/components/sonarr/translations/zh-Hant.json @@ -23,8 +23,7 @@ "port": "\u901a\u8a0a\u57e0", "ssl": "\u4f7f\u7528 SSL \u8a8d\u8b49", "verify_ssl": "\u78ba\u8a8d SSL \u8a8d\u8b49" - }, - "title": "\u9023\u7dda\u81f3 Sonarr" + } } } }, @@ -37,6 +36,5 @@ } } } - }, - "title": "Sonarr" + } } \ No newline at end of file diff --git a/homeassistant/components/songpal/translations/et.json b/homeassistant/components/songpal/translations/et.json index f4f38673a28..337f32b5b59 100644 --- a/homeassistant/components/songpal/translations/et.json +++ b/homeassistant/components/songpal/translations/et.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud", + "not_songpal_device": "Pole Songpal seade" }, "error": { "cannot_connect": "\u00dchendamine nurjus" @@ -10,6 +11,11 @@ "step": { "init": { "description": "Kas soovite seadistada {name}({host})?" + }, + "user": { + "data": { + "endpoint": "L\u00f5pppunkt" + } } } } diff --git a/homeassistant/components/songpal/translations/nl.json b/homeassistant/components/songpal/translations/nl.json new file mode 100644 index 00000000000..9566bf999a8 --- /dev/null +++ b/homeassistant/components/songpal/translations/nl.json @@ -0,0 +1,22 @@ +{ + "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd", + "not_songpal_device": "Geen Songpal-apparaat" + }, + "error": { + "cannot_connect": "Kon niet verbinden" + }, + "flow_title": "Sony Songpal {name} ( {host} )", + "step": { + "init": { + "description": "Wilt u {name} ( {host} ) instellen?" + }, + "user": { + "data": { + "endpoint": "Eindpunt" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/sonos/manifest.json b/homeassistant/components/sonos/manifest.json index 659d9bd1b1d..49826ebc410 100644 --- a/homeassistant/components/sonos/manifest.json +++ b/homeassistant/components/sonos/manifest.json @@ -3,7 +3,7 @@ "name": "Sonos", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/sonos", - "requirements": ["pysonos==0.0.35"], + "requirements": ["pysonos==0.0.36"], "ssdp": [ { "st": "urn:schemas-upnp-org:device:ZonePlayer:1" diff --git a/homeassistant/components/sonos/translations/lb.json b/homeassistant/components/sonos/translations/lb.json index 902d7d8b3cc..a2f45a9a53d 100644 --- a/homeassistant/components/sonos/translations/lb.json +++ b/homeassistant/components/sonos/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "no_devices_found": "Keng Sonos Apparater am Netzwierk fonnt.", - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun Sonos ass n\u00e9ideg." + "no_devices_found": "Keng Apparater am Netzwierk fonnt.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "confirm": { diff --git a/homeassistant/components/sonos/translations/pl.json b/homeassistant/components/sonos/translations/pl.json index eb016e6cd47..a8ee3fa57ac 100644 --- a/homeassistant/components/sonos/translations/pl.json +++ b/homeassistant/components/sonos/translations/pl.json @@ -6,7 +6,7 @@ }, "step": { "confirm": { - "description": "Czy chcesz skonfigurowa\u0107 Sonos?" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } } diff --git a/homeassistant/components/speedtestdotnet/translations/ar.json b/homeassistant/components/speedtestdotnet/translations/ar.json index f3c2591d040..527ad2ecd96 100644 --- a/homeassistant/components/speedtestdotnet/translations/ar.json +++ b/homeassistant/components/speedtestdotnet/translations/ar.json @@ -5,8 +5,7 @@ }, "step": { "user": { - "description": "\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u0625\u0639\u062f\u0627\u062f SpeedTest\u061f", - "title": "\u0625\u0639\u062f\u0627\u062f \u0627\u062e\u062a\u0628\u0627\u0631 \u0627\u0644\u0633\u0631\u0639\u0629" + "description": "\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u0625\u0639\u062f\u0627\u062f SpeedTest\u061f" } } }, diff --git a/homeassistant/components/speedtestdotnet/translations/ca.json b/homeassistant/components/speedtestdotnet/translations/ca.json index 090a464c91a..57caf0ed69b 100644 --- a/homeassistant/components/speedtestdotnet/translations/ca.json +++ b/homeassistant/components/speedtestdotnet/translations/ca.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Nom\u00e9s cal una \u00fanica inst\u00e0ncia.", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", "wrong_server_id": "L'identificador del servidor no \u00e9s v\u00e0lid" }, "step": { "user": { - "description": "Vols comen\u00e7ar la configuraci\u00f3?", - "title": "Configura SpeedTest" + "description": "Vols comen\u00e7ar la configuraci\u00f3?" } } }, "options": { - "error": { - "retrive_error": "S'ha produ\u00eft un error en recuperar la llista de servidors" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/cs.json b/homeassistant/components/speedtestdotnet/translations/cs.json index 3961433f4e8..7564e3ab4f7 100644 --- a/homeassistant/components/speedtestdotnet/translations/cs.json +++ b/homeassistant/components/speedtestdotnet/translations/cs.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Povolena je pouze jedna instance.", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", "wrong_server_id": "ID serveru nen\u00ed platn\u00e9." }, "step": { "user": { - "description": "Chcete za\u010d\u00edt nastavovat?", - "title": "Nastavit SpeedTest" + "description": "Chcete za\u010d\u00edt nastavovat?" } } }, "options": { - "error": { - "retrive_error": "P\u0159i na\u010d\u00edt\u00e1n\u00ed seznamu server\u016f do\u0161lo k chyb\u011b" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/de.json b/homeassistant/components/speedtestdotnet/translations/de.json index 186cd5b080e..56b1a91a89e 100644 --- a/homeassistant/components/speedtestdotnet/translations/de.json +++ b/homeassistant/components/speedtestdotnet/translations/de.json @@ -2,12 +2,14 @@ "config": { "abort": { "wrong_server_id": "Server ID ist ung\u00fcltig" + }, + "step": { + "user": { + "description": "Einrichtung beginnen?" + } } }, "options": { - "error": { - "retrive_error": "Fehler beim Abrufen der Serverliste" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/en.json b/homeassistant/components/speedtestdotnet/translations/en.json index edae80c9f19..b56ff193e33 100644 --- a/homeassistant/components/speedtestdotnet/translations/en.json +++ b/homeassistant/components/speedtestdotnet/translations/en.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Only a single instance is necessary.", "single_instance_allowed": "Already configured. Only a single configuration possible.", "wrong_server_id": "Server ID is not valid" }, "step": { "user": { - "description": "Do you want to start set up?", - "title": "Set up SpeedTest" + "description": "Do you want to start set up?" } } }, "options": { - "error": { - "retrive_error": "Error retriving servers list" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/es.json b/homeassistant/components/speedtestdotnet/translations/es.json index 88474eebd5d..1ccca471c7e 100644 --- a/homeassistant/components/speedtestdotnet/translations/es.json +++ b/homeassistant/components/speedtestdotnet/translations/es.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Solo se necesita una instancia.", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", "wrong_server_id": "Id del servidor no v\u00e1lido" }, "step": { "user": { - "description": "\u00bfEst\u00e1s seguro de que quieres configurar SpeedTest?", - "title": "Configurar SpeedTest" + "description": "\u00bfEst\u00e1s seguro de que quieres configurar SpeedTest?" } } }, "options": { - "error": { - "retrive_error": "Error al recuperar la lista de servidores" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/et.json b/homeassistant/components/speedtestdotnet/translations/et.json index b514abe05b6..834581a9941 100644 --- a/homeassistant/components/speedtestdotnet/translations/et.json +++ b/homeassistant/components/speedtestdotnet/translations/et.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Vajalik on ainult \u00fcks sidumine.", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", "wrong_server_id": "Serveri ID ei sobi" }, "step": { "user": { - "description": "Kas soovid seadistada SpeedTesti?", - "title": "Seadista SpeedTest" + "description": "Kas soovid seadistada SpeedTesti?" } } }, "options": { - "error": { - "retrive_error": "Viga serverite loendi hankimisel" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/fr.json b/homeassistant/components/speedtestdotnet/translations/fr.json index 7b92a679f25..9407a674550 100644 --- a/homeassistant/components/speedtestdotnet/translations/fr.json +++ b/homeassistant/components/speedtestdotnet/translations/fr.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", "wrong_server_id": "L'ID du serveur n'est pas valide" }, "step": { "user": { - "description": "Voulez-vous vraiment configurer SpeedTest ?", - "title": "Configurer SpeedTest" + "description": "Voulez-vous vraiment configurer SpeedTest ?" } } }, "options": { - "error": { - "retrive_error": "Erreur lors de la r\u00e9cup\u00e9ration de la liste des serveurs" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/it.json b/homeassistant/components/speedtestdotnet/translations/it.json index 7b5459948f9..a538c34e96d 100644 --- a/homeassistant/components/speedtestdotnet/translations/it.json +++ b/homeassistant/components/speedtestdotnet/translations/it.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "\u00c8 necessaria solo una singola istanza.", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", "wrong_server_id": "L'ID Server non \u00e8 valido" }, "step": { "user": { - "description": "Vuoi iniziare la configurazione?", - "title": "Configurare SpeedTest" + "description": "Vuoi iniziare la configurazione?" } } }, "options": { - "error": { - "retrive_error": "Errore nel recuperare l'elenco dei server" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/ko.json b/homeassistant/components/speedtestdotnet/translations/ko.json index a3b1ed02ae6..ede64fa0531 100644 --- a/homeassistant/components/speedtestdotnet/translations/ko.json +++ b/homeassistant/components/speedtestdotnet/translations/ko.json @@ -1,20 +1,15 @@ { "config": { "abort": { - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4.", "wrong_server_id": "\uc11c\ubc84 ID \uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "step": { "user": { - "description": "SpeedTest \ub97c \uc124\uc815\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?", - "title": "SpeedTest \uc124\uc815\ud558\uae30" + "description": "SpeedTest \ub97c \uc124\uc815\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?" } } }, "options": { - "error": { - "retrive_error": "\uc11c\ubc84 \ubaa9\ub85d\uc744 \uac80\uc0c9\ud558\ub294 \uc911 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/lb.json b/homeassistant/components/speedtestdotnet/translations/lb.json index 7ceedc228e3..3081080d1fb 100644 --- a/homeassistant/components/speedtestdotnet/translations/lb.json +++ b/homeassistant/components/speedtestdotnet/translations/lb.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech.", "wrong_server_id": "Server ID ass ong\u00eblteg" }, "step": { "user": { - "description": "S\u00e9cher fir SpeedTest anzeriichten?", - "title": "SpeedTest ariichten" + "description": "Soll den Ariichtungs Prozess gestart ginn?" } } }, "options": { - "error": { - "retrive_error": "Feeler beim ofruffen vun der Server L\u00ebscht" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/no.json b/homeassistant/components/speedtestdotnet/translations/no.json index cb438f80d47..98a372f81dc 100644 --- a/homeassistant/components/speedtestdotnet/translations/no.json +++ b/homeassistant/components/speedtestdotnet/translations/no.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", "wrong_server_id": "Server-ID er ikke gyldig" }, "step": { "user": { - "description": "Vil du starte oppsettet?", - "title": "Konfigurere SpeedTest" + "description": "Vil du starte oppsettet?" } } }, "options": { - "error": { - "retrive_error": "Feil ved henting av serverlisten" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/pl.json b/homeassistant/components/speedtestdotnet/translations/pl.json index 1adbbca166f..d64a7920bea 100644 --- a/homeassistant/components/speedtestdotnet/translations/pl.json +++ b/homeassistant/components/speedtestdotnet/translations/pl.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", "wrong_server_id": "Identyfikator serwera jest nieprawid\u0142owy" }, "step": { "user": { - "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", - "title": "Konfiguracja SpeedTest" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } }, "options": { - "error": { - "retrive_error": "B\u0142\u0105d podczas pobierania listy serwer\u00f3w" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/ru.json b/homeassistant/components/speedtestdotnet/translations/ru.json index 836f2422908..c26c63d8511 100644 --- a/homeassistant/components/speedtestdotnet/translations/ru.json +++ b/homeassistant/components/speedtestdotnet/translations/ru.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", "wrong_server_id": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d." }, "step": { "user": { - "description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443?", - "title": "SpeedTest" + "description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443?" } } }, "options": { - "error": { - "retrive_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432." - }, "step": { "init": { "data": { diff --git a/homeassistant/components/speedtestdotnet/translations/zh-Hant.json b/homeassistant/components/speedtestdotnet/translations/zh-Hant.json index ab475fa3b7b..e9459bf08f5 100644 --- a/homeassistant/components/speedtestdotnet/translations/zh-Hant.json +++ b/homeassistant/components/speedtestdotnet/translations/zh-Hant.json @@ -1,21 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u5373\u53ef\u3002", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", "wrong_server_id": "\u4f3a\u670d\u5668 ID \u7121\u6548" }, "step": { "user": { - "description": "\u662f\u5426\u8981\u958b\u59cb\u8a2d\u5b9a\uff1f", - "title": "\u8a2d\u5b9a SpeedTest" + "description": "\u662f\u5426\u8981\u958b\u59cb\u8a2d\u5b9a\uff1f" } } }, "options": { - "error": { - "retrive_error": "\u63a5\u6536\u4f3a\u670d\u5668\u5217\u8868\u932f\u8aa4" - }, "step": { "init": { "data": { diff --git a/homeassistant/components/spider/__init__.py b/homeassistant/components/spider/__init__.py index f2e9a06fb94..b0c34ae5a08 100644 --- a/homeassistant/components/spider/__init__.py +++ b/homeassistant/components/spider/__init__.py @@ -2,11 +2,12 @@ import asyncio import logging -from spiderpy.spiderapi import SpiderApi, UnauthorizedException +from spiderpy.spiderapi import SpiderApi, SpiderApiException, UnauthorizedException import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_USERNAME +from homeassistant.exceptions import ConfigEntryNotReady import homeassistant.helpers.config_validation as cv from .const import DEFAULT_SCAN_INTERVAL, DOMAIN, PLATFORMS @@ -29,16 +30,6 @@ CONFIG_SCHEMA = vol.Schema( ) -def _spider_startup_wrapper(entry): - """Startup wrapper for spider.""" - api = SpiderApi( - entry.data[CONF_USERNAME], - entry.data[CONF_PASSWORD], - entry.data[CONF_SCAN_INTERVAL], - ) - return api - - async def async_setup(hass, config): """Set up a config entry.""" hass.data[DOMAIN] = {} @@ -60,12 +51,20 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): """Set up Spider via config entry.""" try: - hass.data[DOMAIN][entry.entry_id] = await hass.async_add_executor_job( - _spider_startup_wrapper, entry + api = await hass.async_add_executor_job( + SpiderApi, + entry.data[CONF_USERNAME], + entry.data[CONF_PASSWORD], + entry.data[CONF_SCAN_INTERVAL], ) except UnauthorizedException: - _LOGGER.error("Can't connect to the Spider API") + _LOGGER.error("Authorization failed") return False + except SpiderApiException as err: + _LOGGER.error("Can't connect to the Spider API: %s", err) + raise ConfigEntryNotReady from err + + hass.data[DOMAIN][entry.entry_id] = api for component in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/spider/climate.py b/homeassistant/components/spider/climate.py index d9477c2a4fb..7730d8b34c4 100644 --- a/homeassistant/components/spider/climate.py +++ b/homeassistant/components/spider/climate.py @@ -28,9 +28,12 @@ async def async_setup_entry(hass, config, async_add_entities): """Initialize a Spider thermostat.""" api = hass.data[DOMAIN][config.entry_id] - entities = [SpiderThermostat(api, entity) for entity in api.get_thermostats()] - - async_add_entities(entities) + async_add_entities( + [ + SpiderThermostat(api, entity) + for entity in await hass.async_add_executor_job(api.get_thermostats) + ] + ) class SpiderThermostat(ClimateEntity): @@ -44,12 +47,9 @@ class SpiderThermostat(ClimateEntity): @property def supported_features(self): """Return the list of supported features.""" - supports = SUPPORT_TARGET_TEMPERATURE - if self.thermostat.has_fan_mode: - supports |= SUPPORT_FAN_MODE - - return supports + return SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE + return SUPPORT_TARGET_TEMPERATURE @property def unique_id(self): diff --git a/homeassistant/components/spider/switch.py b/homeassistant/components/spider/switch.py index 62f220bf805..1b0c86468ea 100644 --- a/homeassistant/components/spider/switch.py +++ b/homeassistant/components/spider/switch.py @@ -7,10 +7,12 @@ from .const import DOMAIN async def async_setup_entry(hass, config, async_add_entities): """Initialize a Spider thermostat.""" api = hass.data[DOMAIN][config.entry_id] - - entities = [SpiderPowerPlug(api, entity) for entity in api.get_power_plugs()] - - async_add_entities(entities) + async_add_entities( + [ + SpiderPowerPlug(api, entity) + for entity in await hass.async_add_executor_job(api.get_power_plugs) + ] + ) class SpiderPowerPlug(SwitchEntity): diff --git a/homeassistant/components/spider/translations/et.json b/homeassistant/components/spider/translations/et.json index a7e16adbe4a..489e6a8981a 100644 --- a/homeassistant/components/spider/translations/et.json +++ b/homeassistant/components/spider/translations/et.json @@ -12,7 +12,8 @@ "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "Logi sisse mijn.ithodaalderop.nl kontoga" } } } diff --git a/homeassistant/components/spider/translations/nl.json b/homeassistant/components/spider/translations/nl.json index 4d00f0bfc74..f0b4ddf59a9 100644 --- a/homeassistant/components/spider/translations/nl.json +++ b/homeassistant/components/spider/translations/nl.json @@ -1,8 +1,13 @@ { "config": { + "error": { + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "password": "Wachtwoord", "username": "Gebruikersnaam" } } diff --git a/homeassistant/components/spider/translations/pl.json b/homeassistant/components/spider/translations/pl.json index f288bcbd78b..7a40eec5ed6 100644 --- a/homeassistant/components/spider/translations/pl.json +++ b/homeassistant/components/spider/translations/pl.json @@ -13,7 +13,7 @@ "password": "Has\u0142o", "username": "Nazwa u\u017cytkownika" }, - "title": "Zaloguj si\u0119 na konto mijn.ithodaalderop.nl" + "title": "Logowanie na konto mijn.ithodaalderop.nl" } } } diff --git a/homeassistant/components/spotify/media_player.py b/homeassistant/components/spotify/media_player.py index 0782cb2f390..5f376493c65 100644 --- a/homeassistant/components/spotify/media_player.py +++ b/homeassistant/components/spotify/media_player.py @@ -5,7 +5,7 @@ from datetime import timedelta import logging from typing import Any, Callable, Dict, List, Optional -from aiohttp import ClientError +import requests from spotipy import Spotify, SpotifyException from yarl import URL @@ -195,7 +195,7 @@ def spotify_exception_handler(func): result = func(self, *args, **kwargs) self.player_available = True return result - except (SpotifyException, ClientError): + except (SpotifyException, requests.RequestException): self.player_available = False return wrapper @@ -218,7 +218,9 @@ class SpotifyMediaPlayer(MediaPlayerEntity): self._name = f"Spotify {name}" self._session = session self._spotify = spotify - self._scope_ok = set(session.token["scope"].split(" ")) == set(SPOTIFY_SCOPES) + self._scope_ok = set(session.token["scope"].split(" ")).issuperset( + SPOTIFY_SCOPES + ) self._currently_playing: Optional[dict] = {} self._devices: Optional[List[dict]] = [] @@ -474,6 +476,9 @@ class SpotifyMediaPlayer(MediaPlayerEntity): """Implement the websocket media browsing helper.""" if not self._scope_ok: + _LOGGER.debug( + "Spotify scopes are not set correctly, this can impact features such as media browsing" + ) raise NotImplementedError if media_content_type in [None, "library"]: diff --git a/homeassistant/components/spotify/translations/ca.json b/homeassistant/components/spotify/translations/ca.json index e0e65c0ebc2..0210147a489 100644 --- a/homeassistant/components/spotify/translations/ca.json +++ b/homeassistant/components/spotify/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Nom\u00e9s pots configurar un \u00fanic compte amb Spotify.", "authorize_url_timeout": "S'ha acabat el temps d'espera durant la generaci\u00f3 de l'URL d'autoritzaci\u00f3.", "missing_configuration": "La integraci\u00f3 Spotify no est\u00e0 configurada. Mira'n la documentaci\u00f3.", "no_url_available": "No hi ha cap URL disponible. Per a m\u00e9s informaci\u00f3 sobre aquest error, [consulta la secci\u00f3 d'ajuda]({docs_url})", diff --git a/homeassistant/components/spotify/translations/cs.json b/homeassistant/components/spotify/translations/cs.json index b8f7c90e317..f8f122e63e2 100644 --- a/homeassistant/components/spotify/translations/cs.json +++ b/homeassistant/components/spotify/translations/cs.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "M\u016f\u017eete nakonfigurovat pouze jeden \u00fa\u010det Spotify.", "authorize_url_timeout": "\u010casov\u00fd limit autoriza\u010dn\u00edho URL vypr\u0161el", "missing_configuration": "Integrace Spotify nen\u00ed nastavena. Postupujte podle dokumentace.", "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})" diff --git a/homeassistant/components/spotify/translations/da.json b/homeassistant/components/spotify/translations/da.json index 1b6611c4cb6..a3ac5db0f9b 100644 --- a/homeassistant/components/spotify/translations/da.json +++ b/homeassistant/components/spotify/translations/da.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan kun konfigurere en enkelt Spotify-konto.", "authorize_url_timeout": "Timeout ved generering af godkendelses-url.", "missing_configuration": "Spotify-integrationen er ikke konfigureret. F\u00f8lg venligst dokumentationen." }, diff --git a/homeassistant/components/spotify/translations/de.json b/homeassistant/components/spotify/translations/de.json index ff17a3ada82..b6a10d7cde5 100644 --- a/homeassistant/components/spotify/translations/de.json +++ b/homeassistant/components/spotify/translations/de.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Sie k\u00f6nnen nur ein Spotify-Konto konfigurieren.", "authorize_url_timeout": "Zeit\u00fcberschreitung beim Erstellen der Authorisierungs-URL.", "missing_configuration": "Die Spotify-Integration ist nicht konfiguriert. Bitte folgen Sie der Dokumentation." }, diff --git a/homeassistant/components/spotify/translations/en.json b/homeassistant/components/spotify/translations/en.json index 146c42f4411..1c04a5868bc 100644 --- a/homeassistant/components/spotify/translations/en.json +++ b/homeassistant/components/spotify/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "You can only configure one Spotify account.", "authorize_url_timeout": "Timeout generating authorize url.", "missing_configuration": "The Spotify integration is not configured. Please follow the documentation.", "no_url_available": "No URL available. For information about this error, [check the help section]({docs_url})", diff --git a/homeassistant/components/spotify/translations/es-419.json b/homeassistant/components/spotify/translations/es-419.json index f9b956e47bc..74e92a52b1b 100644 --- a/homeassistant/components/spotify/translations/es-419.json +++ b/homeassistant/components/spotify/translations/es-419.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Solo puede configurar una cuenta de Spotify.", "authorize_url_timeout": "Tiempo de espera agotado para generar la URL de autorizaci\u00f3n.", "missing_configuration": "La integraci\u00f3n de Spotify no est\u00e1 configurada. Por favor, siga la documentaci\u00f3n." }, diff --git a/homeassistant/components/spotify/translations/es.json b/homeassistant/components/spotify/translations/es.json index 56f2e3ba95b..68783fd3caf 100644 --- a/homeassistant/components/spotify/translations/es.json +++ b/homeassistant/components/spotify/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "S\u00f3lo puedes configurar una cuenta de Spotify.", "authorize_url_timeout": "Tiempo de espera agotado generando la url de autorizaci\u00f3n.", "missing_configuration": "La integraci\u00f3n de Spotify no est\u00e1 configurada. Por favor, siga la documentaci\u00f3n.", "no_url_available": "No hay URL disponible. Para obtener informaci\u00f3n sobre este error, [consulta la secci\u00f3n de ayuda]({docs_url})", diff --git a/homeassistant/components/spotify/translations/et.json b/homeassistant/components/spotify/translations/et.json index 3403292db03..f3ceec4fa5c 100644 --- a/homeassistant/components/spotify/translations/et.json +++ b/homeassistant/components/spotify/translations/et.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Saate konfigureerida ainult \u00fche Spotify konto.", "authorize_url_timeout": "Kinnituse URLi ajal\u00f5pp", "missing_configuration": "Spotify sidumine pole h\u00e4\u00e4lestatud. Palun j\u00e4rgige dokumentatsiooni.", "no_url_available": "URL pole saadaval. Rohkem teavet [check the help section]({docs_url})", diff --git a/homeassistant/components/spotify/translations/fr.json b/homeassistant/components/spotify/translations/fr.json index 251c85920aa..f4f6566e88d 100644 --- a/homeassistant/components/spotify/translations/fr.json +++ b/homeassistant/components/spotify/translations/fr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Vous ne pouvez configurer qu'un seul compte Spotify.", "authorize_url_timeout": "D\u00e9lai d'expiration g\u00e9n\u00e9rant une URL d'autorisation.", "missing_configuration": "L'int\u00e9gration Spotify n'est pas configur\u00e9e. Veuillez suivre la documentation.", "no_url_available": "Aucune URL disponible. Pour plus d'informations sur cette erreur, [consultez la section d'aide] ( {docs_url} )", diff --git a/homeassistant/components/spotify/translations/hu.json b/homeassistant/components/spotify/translations/hu.json index 48ebf35a97f..fb0dc0f8a1f 100644 --- a/homeassistant/components/spotify/translations/hu.json +++ b/homeassistant/components/spotify/translations/hu.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Csak egy Spotify-fi\u00f3kot konfigur\u00e1lhat.", "authorize_url_timeout": "Id\u0151t\u00fall\u00e9p\u00e9s az \u00e9rv\u00e9nyes\u00edt\u00e9si url gener\u00e1l\u00e1sa sor\u00e1n.", "missing_configuration": "A Spotify integr\u00e1ci\u00f3 nincs konfigur\u00e1lva. K\u00e9rj\u00fck, k\u00f6vesse a dokument\u00e1ci\u00f3t." }, diff --git a/homeassistant/components/spotify/translations/it.json b/homeassistant/components/spotify/translations/it.json index 648f071b8fe..c201c70cd1c 100644 --- a/homeassistant/components/spotify/translations/it.json +++ b/homeassistant/components/spotify/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u00c8 possibile configurare un solo account di Spotify.", "authorize_url_timeout": "Tempo scaduto nel generare l'URL di autorizzazione", "missing_configuration": "L'integrazione di Spotify non \u00e8 configurata. Si prega di seguire la documentazione.", "no_url_available": "Nessun URL disponibile. Per informazioni su questo errore, [controlla la sezione della guida]({docs_url})", @@ -16,7 +15,7 @@ }, "reauth_confirm": { "description": "L'integrazione di Spotify deve essere nuovamente autenticata con Spotify per l'account: {account}", - "title": "Eseguire nuovamente l'autenticazione con Spotify" + "title": "Reautenticare l'integrazione" } } } diff --git a/homeassistant/components/spotify/translations/ko.json b/homeassistant/components/spotify/translations/ko.json index 37dccd8c1a6..a12162bb4fb 100644 --- a/homeassistant/components/spotify/translations/ko.json +++ b/homeassistant/components/spotify/translations/ko.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\ud558\ub098\uc758 Spotify \uacc4\uc815\ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.", "authorize_url_timeout": "\uc778\uc99d url \uc0dd\uc131 \uc2dc\uac04\uc774 \ucd08\uacfc\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "missing_configuration": "Spotify \uad6c\uc131\uc694\uc18c\uac00 \uad6c\uc131\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \uc124\uba85\uc11c\ub97c \ucc38\uace0\ud574\uc8fc\uc138\uc694.", "no_url_available": "\uac00\ub2a5\ud55c URL\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. \uc774 \uc5d0\ub7ec\uc5d0 \ub300\ud55c \uc815\ubcf4\ub294 \ub3c4\uc6c0\ub9d0 \uc139\uc158\uc744 \ud655\uc778\ud558\uc138\uc694({docs_url})", diff --git a/homeassistant/components/spotify/translations/lb.json b/homeassistant/components/spotify/translations/lb.json index 59aaf936dc1..d7b5dcec0be 100644 --- a/homeassistant/components/spotify/translations/lb.json +++ b/homeassistant/components/spotify/translations/lb.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Dir k\u00ebnnt n\u00ebmmen een eenzegen Spotify Kont konfigur\u00e9ieren.", "authorize_url_timeout": "Z\u00e4it Iwwerschreidung beim gener\u00e9ieren vun der Autorisatiouns URL.", "missing_configuration": "Spotifiy Integratioun ass nach net konfigur\u00e9iert. Follegt w.e.g der Dokumentatioun.", "no_url_available": "Keng URL disponibel. Fir Informatiounen iwwert d\u00ebse Feeler, [kuck H\u00ebllef Sektioun]({docs_url})" @@ -11,7 +10,11 @@ }, "step": { "pick_implementation": { - "title": "Wielt Authentifikatiouns Method aus" + "title": "Wiel Authentifikatiouns Method aus" + }, + "reauth_confirm": { + "description": "Spotify Integratioun muss sec hbei Spotify fr\u00ebsch umellen fir de Kont: {acount}", + "title": "Integratioun re-authentifiz\u00e9ieren" } } } diff --git a/homeassistant/components/spotify/translations/nl.json b/homeassistant/components/spotify/translations/nl.json index b300066ca95..bdc86919f74 100644 --- a/homeassistant/components/spotify/translations/nl.json +++ b/homeassistant/components/spotify/translations/nl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "U kunt slechts \u00e9\u00e9n Spotify-account configureren.", "authorize_url_timeout": "Time-out tijdens genereren autorisatie url.", "missing_configuration": "De Spotify integratie is niet geconfigureerd. Gelieve de documentatie te volgen.", "no_url_available": "Geen URL beschikbaar. Voor informatie over deze fout [check the help section] ({docs_url})", diff --git a/homeassistant/components/spotify/translations/no.json b/homeassistant/components/spotify/translations/no.json index ebd6bc3816b..f400a2c11ad 100644 --- a/homeassistant/components/spotify/translations/no.json +++ b/homeassistant/components/spotify/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan bare konfigurere en Spotify-konto.", "authorize_url_timeout": "Tidsavbrudd ved oppretting av godkjenningsadresse.", "missing_configuration": "Spotify-integrasjonen er ikke konfigurert. F\u00f8lg dokumentasjonen.", "no_url_available": "Ingen URL tilgjengelig. For informasjon om denne feilen, [sjekk hjelpseksjonen]({docs_url})", diff --git a/homeassistant/components/spotify/translations/pl.json b/homeassistant/components/spotify/translations/pl.json index 8af9c3945f7..c503dfccda5 100644 --- a/homeassistant/components/spotify/translations/pl.json +++ b/homeassistant/components/spotify/translations/pl.json @@ -1,14 +1,13 @@ { "config": { "abort": { - "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno konto Spotify", "authorize_url_timeout": "Przekroczono limit czasu generowania URL autoryzacji", "missing_configuration": "Komponent nie jest skonfigurowany. Post\u0119puj zgodnie z dokumentacj\u0105.", "no_url_available": "Brak dost\u0119pnego adresu URL. Aby uzyska\u0107 informacje na temat tego b\u0142\u0119du, [sprawd\u017a sekcj\u0119 pomocy] ({docs_url})", "reauth_account_mismatch": "Uwierzytelnione konto Spotify nie pasuje do konta, kt\u00f3re wymaga ponownego uwierzytelnienia" }, "create_entry": { - "default": "Pomy\u015blnie uwierzytelniono z Spotify" + "default": "Pomy\u015blnie uwierzytelniono" }, "step": { "pick_implementation": { diff --git a/homeassistant/components/spotify/translations/ru.json b/homeassistant/components/spotify/translations/ru.json index 82190aa57bb..c9451ad76f3 100644 --- a/homeassistant/components/spotify/translations/ru.json +++ b/homeassistant/components/spotify/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "authorize_url_timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.", "missing_configuration": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f Spotify \u043d\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438.", "no_url_available": "URL-\u0430\u0434\u0440\u0435\u0441 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d. \u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439]({docs_url}) \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u044d\u0442\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0435.", diff --git a/homeassistant/components/spotify/translations/sl.json b/homeassistant/components/spotify/translations/sl.json index 5a996e47547..0b138211240 100644 --- a/homeassistant/components/spotify/translations/sl.json +++ b/homeassistant/components/spotify/translations/sl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Konfigurirate lahko samo en ra\u010dun Spotify.", "authorize_url_timeout": "\u010casovna omejitev za generiranje potrditvenega URL-ja je potekla.", "missing_configuration": "Integracija Spotify ni konfigurirana. Prosimo, upo\u0161tevajte dokumentacijo." }, diff --git a/homeassistant/components/spotify/translations/sv.json b/homeassistant/components/spotify/translations/sv.json index 25daba13b87..55f94e6b717 100644 --- a/homeassistant/components/spotify/translations/sv.json +++ b/homeassistant/components/spotify/translations/sv.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Du kan endast konfigurera ett Spotify-konto.", "authorize_url_timeout": "Skapandet av en auktoriseringsadress \u00f6verskred tidsgr\u00e4nsen.", "missing_configuration": "Spotify-integrationen \u00e4r inte konfigurerad. V\u00e4nligen f\u00f6lj dokumentationen." }, diff --git a/homeassistant/components/spotify/translations/tr.json b/homeassistant/components/spotify/translations/tr.json index 29641464f57..c7307d119a0 100644 --- a/homeassistant/components/spotify/translations/tr.json +++ b/homeassistant/components/spotify/translations/tr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "Yaln\u0131zca bir Spotify hesab\u0131 ayarlayabilirsin.", "authorize_url_timeout": "Kimlik do\u011frulama URL'sini olu\u015ftururken zaman a\u015f\u0131m\u0131 ger\u00e7ekle\u015fti.", "missing_configuration": "Spotify entegrasyonu ayarlanmam\u0131\u015f. L\u00fctfen dok\u00fcmentasyonu takip et." }, diff --git a/homeassistant/components/spotify/translations/zh-Hant.json b/homeassistant/components/spotify/translations/zh-Hant.json index cb091ed5dd9..9518c53732d 100644 --- a/homeassistant/components/spotify/translations/zh-Hant.json +++ b/homeassistant/components/spotify/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_setup": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44 Spotify \u5e33\u865f\u3002", "authorize_url_timeout": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u903e\u6642\u3002", "missing_configuration": "Spotify \u6574\u5408\u5c1a\u672a\u8a2d\u7f6e\uff0c\u8acb\u53c3\u95b1\u6587\u4ef6\u8aaa\u660e\u3002", "no_url_available": "\u6c92\u6709\u53ef\u7528\u7684\u7db2\u5740\u3002\u95dc\u65bc\u6b64\u932f\u8aa4\u66f4\u8a73\u7d30\u8a0a\u606f\uff0c[\u9ede\u9078\u5354\u52a9\u7ae0\u7bc0]({docs_url})", diff --git a/homeassistant/components/squeezebox/browse_media.py b/homeassistant/components/squeezebox/browse_media.py index bab24e39cbc..4c0ec186707 100644 --- a/homeassistant/components/squeezebox/browse_media.py +++ b/homeassistant/components/squeezebox/browse_media.py @@ -13,6 +13,7 @@ from homeassistant.components.media_player.const import ( MEDIA_TYPE_PLAYLIST, MEDIA_TYPE_TRACK, ) +from homeassistant.helpers.network import is_internal_request LIBRARY = ["Artists", "Albums", "Tracks", "Playlists", "Genres"] @@ -47,10 +48,7 @@ CONTENT_TYPE_MEDIA_CLASS = { MEDIA_TYPE_ARTIST: {"item": MEDIA_CLASS_ARTIST, "children": MEDIA_CLASS_ALBUM}, MEDIA_TYPE_TRACK: {"item": MEDIA_CLASS_TRACK, "children": None}, MEDIA_TYPE_GENRE: {"item": MEDIA_CLASS_GENRE, "children": MEDIA_CLASS_ARTIST}, - MEDIA_TYPE_PLAYLIST: { - "item": MEDIA_CLASS_PLAYLIST, - "children": MEDIA_CLASS_TRACK, - }, + MEDIA_TYPE_PLAYLIST: {"item": MEDIA_CLASS_PLAYLIST, "children": MEDIA_CLASS_TRACK}, } CONTENT_TYPE_TO_CHILD_TYPE = { @@ -68,8 +66,10 @@ CONTENT_TYPE_TO_CHILD_TYPE = { BROWSE_LIMIT = 1000 -async def build_item_response(player, payload): +async def build_item_response(entity, player, payload): """Create response payload for search described by payload.""" + internal_request = is_internal_request(entity.hass) + search_id = payload["search_id"] search_type = payload["search_type"] @@ -94,15 +94,29 @@ async def build_item_response(player, payload): children = [] for item in result["items"]: + item_id = str(item["id"]) + item_thumbnail = None + + artwork_track_id = item.get("artwork_track_id") + if artwork_track_id: + if internal_request: + item_thumbnail = player.generate_image_url_from_track_id( + artwork_track_id + ) + else: + item_thumbnail = entity.get_browse_image_url( + item_type, item_id, artwork_track_id + ) + children.append( BrowseMedia( title=item["title"], media_class=child_media_class["item"], - media_content_id=str(item["id"]), + media_content_id=item_id, media_content_type=item_type, can_play=True, can_expand=child_media_class["children"] is not None, - thumbnail=item.get("image_url"), + thumbnail=item_thumbnail, ) ) diff --git a/homeassistant/components/squeezebox/manifest.json b/homeassistant/components/squeezebox/manifest.json index a0d0d1ef50e..5c384e6ae1c 100644 --- a/homeassistant/components/squeezebox/manifest.json +++ b/homeassistant/components/squeezebox/manifest.json @@ -6,7 +6,7 @@ "@rajlaud" ], "requirements": [ - "pysqueezebox==0.5.4" + "pysqueezebox==0.5.5" ], "config_flow": true } diff --git a/homeassistant/components/squeezebox/media_player.py b/homeassistant/components/squeezebox/media_player.py index 9a7baffb3f8..b87695dd159 100644 --- a/homeassistant/components/squeezebox/media_player.py +++ b/homeassistant/components/squeezebox/media_player.py @@ -168,8 +168,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): known_players = hass.data[DOMAIN].setdefault(KNOWN_PLAYERS, []) + session = async_get_clientsession(hass) _LOGGER.debug("Creating LMS object for %s", host) - lms = Server(async_get_clientsession(hass), host, port, username, password) + lms = Server(session, host, port, username, password) async def _discovery(now=None): """Discover squeezebox players by polling server.""" @@ -587,4 +588,17 @@ class SqueezeBoxEntity(MediaPlayerEntity): "search_id": media_content_id, } - return await build_item_response(self._player, payload) + return await build_item_response(self, self._player, payload) + + async def async_get_browse_image( + self, media_content_type, media_content_id, media_image_id=None + ): + """Get album art from Squeezebox server.""" + if media_image_id: + image_url = self._player.generate_image_url_from_track_id(media_image_id) + result = await self._async_fetch_image(image_url) + if result == (None, None): + _LOGGER.debug("Error retrieving proxied album art from %s", image_url) + return result + + return (None, None) diff --git a/homeassistant/components/squeezebox/strings.json b/homeassistant/components/squeezebox/strings.json index d905335a6ae..afe68d01947 100644 --- a/homeassistant/components/squeezebox/strings.json +++ b/homeassistant/components/squeezebox/strings.json @@ -1,21 +1,19 @@ { - "title": "Logitech Squeezebox", "config": { "flow_title": "Logitech Squeezebox: {host}", "step": { "user": { - "title": "Configure Logitech Media Server", - "data": { - "host": "[%key:common::config_flow::data::host%]" - } + "data": { + "host": "[%key:common::config_flow::data::host%]" + } }, "edit": { "title": "Edit connection information", "data": { "host": "[%key:common::config_flow::data::host%]", - "port": "[%key:common::config_flow::data::port%]", - "username": "[%key:common::config_flow::data::username%]", - "password": "[%key:common::config_flow::data::password%]" + "port": "[%key:common::config_flow::data::port%]", + "username": "[%key:common::config_flow::data::username%]", + "password": "[%key:common::config_flow::data::password%]" } } }, diff --git a/homeassistant/components/squeezebox/translations/ca.json b/homeassistant/components/squeezebox/translations/ca.json index 3d3ce7f7c08..edd34c8454a 100644 --- a/homeassistant/components/squeezebox/translations/ca.json +++ b/homeassistant/components/squeezebox/translations/ca.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "Amfitri\u00f3" - }, - "title": "Configura el servidor Logitech Media" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/cs.json b/homeassistant/components/squeezebox/translations/cs.json index d90b902cc61..d94448efe56 100644 --- a/homeassistant/components/squeezebox/translations/cs.json +++ b/homeassistant/components/squeezebox/translations/cs.json @@ -17,7 +17,8 @@ "password": "Heslo", "port": "Port", "username": "U\u017eivatelsk\u00e9 jm\u00e9no" - } + }, + "title": "Upravte informace o p\u0159ipojen\u00ed" }, "user": { "data": { diff --git a/homeassistant/components/squeezebox/translations/de.json b/homeassistant/components/squeezebox/translations/de.json index 8671822cdf8..24087b50617 100644 --- a/homeassistant/components/squeezebox/translations/de.json +++ b/homeassistant/components/squeezebox/translations/de.json @@ -14,6 +14,5 @@ } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/en.json b/homeassistant/components/squeezebox/translations/en.json index 9cbfbcc3664..614cb07af77 100644 --- a/homeassistant/components/squeezebox/translations/en.json +++ b/homeassistant/components/squeezebox/translations/en.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "Host" - }, - "title": "Configure Logitech Media Server" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/es.json b/homeassistant/components/squeezebox/translations/es.json index 33b5f846fc8..4183a575ec4 100644 --- a/homeassistant/components/squeezebox/translations/es.json +++ b/homeassistant/components/squeezebox/translations/es.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "Host" - }, - "title": "Configurar Logitech Media Server" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/et.json b/homeassistant/components/squeezebox/translations/et.json index 34155663543..44e075c83ca 100644 --- a/homeassistant/components/squeezebox/translations/et.json +++ b/homeassistant/components/squeezebox/translations/et.json @@ -1,11 +1,13 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud", + "no_server_found": "LMS serverit ei leitud." }, "error": { "cannot_connect": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamine nurjus", + "no_server_found": "Serverit ei \u00f5nnestunud automaatselt tuvastada.", "unknown": "Tundmatu viga" }, "flow_title": "Logitech Squeezebox: {host}", @@ -16,7 +18,8 @@ "password": "Salas\u00f5na", "port": "", "username": "Kasutajanimi" - } + }, + "title": "\u00dchenduse teabe muutmine" }, "user": { "data": { @@ -24,6 +27,5 @@ } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/fr.json b/homeassistant/components/squeezebox/translations/fr.json index 6119bc34f8d..f79d25bc20a 100644 --- a/homeassistant/components/squeezebox/translations/fr.json +++ b/homeassistant/components/squeezebox/translations/fr.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "H\u00f4te" - }, - "title": "Configurer Logitech Media Server" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/it.json b/homeassistant/components/squeezebox/translations/it.json index 08918192b7a..13686f1eebc 100644 --- a/homeassistant/components/squeezebox/translations/it.json +++ b/homeassistant/components/squeezebox/translations/it.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "Host" - }, - "title": "Configurare Logitech Media Server" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/ko.json b/homeassistant/components/squeezebox/translations/ko.json index 6ff17d6465c..6bc1f9a95ec 100644 --- a/homeassistant/components/squeezebox/translations/ko.json +++ b/homeassistant/components/squeezebox/translations/ko.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "\ud638\uc2a4\ud2b8" - }, - "title": "Logitech Media Server \uad6c\uc131\ud558\uae30" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/lb.json b/homeassistant/components/squeezebox/translations/lb.json index 26b41e68e60..5b8c0cfdfbb 100644 --- a/homeassistant/components/squeezebox/translations/lb.json +++ b/homeassistant/components/squeezebox/translations/lb.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "Host" - }, - "title": "Logitech Media Server ariichten" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/nl.json b/homeassistant/components/squeezebox/translations/nl.json index 67fe1197e21..d023a3e96d1 100644 --- a/homeassistant/components/squeezebox/translations/nl.json +++ b/homeassistant/components/squeezebox/translations/nl.json @@ -1,18 +1,29 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "flow_title": "Logitech Squeezebox: {host}", "step": { "edit": { "data": { + "host": "Host", "password": "Wachtwoord", "port": "Poort", "username": "Gebruikersnaam" - } + }, + "title": "Verbindingsgegevens bewerken" }, "user": { - "title": "Configureer Logitech Media Server" + "data": { + "host": "Host" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/no.json b/homeassistant/components/squeezebox/translations/no.json index 777c782691d..d33ec911948 100644 --- a/homeassistant/components/squeezebox/translations/no.json +++ b/homeassistant/components/squeezebox/translations/no.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "Vert" - }, - "title": "Konfigurer Logitech Media Server" + } } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/pl.json b/homeassistant/components/squeezebox/translations/pl.json index 1f9aa5d24af..8a092a27062 100644 --- a/homeassistant/components/squeezebox/translations/pl.json +++ b/homeassistant/components/squeezebox/translations/pl.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "Nazwa hosta lub adres IP" - }, - "title": "Konfiguracja Serwera medi\u00f3w Logitech (LMS)" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/ru.json b/homeassistant/components/squeezebox/translations/ru.json index 8b6c6a71ff6..789fff313d8 100644 --- a/homeassistant/components/squeezebox/translations/ru.json +++ b/homeassistant/components/squeezebox/translations/ru.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "\u0425\u043e\u0441\u0442" - }, - "title": "Logitech Media Server" + } } } - }, - "title": "Logitech Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/squeezebox/translations/zh-Hant.json b/homeassistant/components/squeezebox/translations/zh-Hant.json index 54b54195bf4..85942f812b0 100644 --- a/homeassistant/components/squeezebox/translations/zh-Hant.json +++ b/homeassistant/components/squeezebox/translations/zh-Hant.json @@ -24,10 +24,8 @@ "user": { "data": { "host": "\u4e3b\u6a5f\u7aef" - }, - "title": "\u8a2d\u5b9a\u7f85\u6280 Media Server" + } } } - }, - "title": "\u7f85\u6280 Squeezebox" + } } \ No newline at end of file diff --git a/homeassistant/components/ssdp/__init__.py b/homeassistant/components/ssdp/__init__.py index 7108034cfb8..e962c141bef 100644 --- a/homeassistant/components/ssdp/__init__.py +++ b/homeassistant/components/ssdp/__init__.py @@ -79,7 +79,8 @@ class Scanner: async def _process_entries(self, entries): """Process SSDP entries.""" - tasks = [] + entries_to_process = [] + unseen_locations = set() for entry in entries: key = (entry.st, entry.location) @@ -89,21 +90,24 @@ class Scanner: self.seen.add(key) - tasks.append(self._process_entry(entry)) + entries_to_process.append(entry) - if not tasks: + if ( + entry.location is not None + and entry.location not in self._description_cache + ): + unseen_locations.add(entry.location) + + if not entries_to_process: return - to_load = [ - result for result in await asyncio.gather(*tasks) if result is not None - ] - - if not to_load: - return + if unseen_locations: + await self._fetch_descriptions(list(unseen_locations)) tasks = [] - for entry, info, domains in to_load: + for entry in entries_to_process: + info, domains = self._process_entry(entry) for domain in domains: _LOGGER.debug("Discovered %s at %s", domain, entry.location) tasks.append( @@ -112,9 +116,29 @@ class Scanner: ) ) - await asyncio.wait(tasks) + if tasks: + await asyncio.gather(*tasks) - async def _process_entry(self, entry): + async def _fetch_descriptions(self, locations): + """Fetch descriptions from locations.""" + + for idx, result in enumerate( + await asyncio.gather( + *[self._fetch_description(location) for location in locations], + return_exceptions=True, + ) + ): + location = locations[idx] + + if isinstance(result, Exception): + _LOGGER.exception( + "Failed to fetch ssdp data from: %s", location, exc_info=result + ) + continue + + self._description_cache[location] = result + + def _process_entry(self, entry): """Process a single entry.""" info = {"st": entry.st} @@ -123,17 +147,13 @@ class Scanner: info[key] = entry.values[key] if entry.location: - # Multiple entries usually share same location. Make sure # we fetch it only once. info_req = self._description_cache.get(entry.location) - if info_req is None: - info_req = self._description_cache[ - entry.location - ] = self.hass.async_create_task(self._fetch_description(entry.location)) + return (None, []) - info.update(await info_req) + info.update(info_req) domains = set() for domain, matchers in self._integration_matchers.items(): @@ -142,9 +162,9 @@ class Scanner: domains.add(domain) if domains: - return (entry, info_from_entry(entry, info), domains) + return (info_from_entry(entry, info), domains) - return None + return (None, []) async def _fetch_description(self, xml_location): """Fetch an XML description.""" diff --git a/homeassistant/components/starline/translations/cs.json b/homeassistant/components/starline/translations/cs.json index c7446a1cc80..4424c594c01 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/starline/translations/et.json b/homeassistant/components/starline/translations/et.json index 0b4d2f9f6d5..73614f5b1a7 100644 --- a/homeassistant/components/starline/translations/et.json +++ b/homeassistant/components/starline/translations/et.json @@ -1,20 +1,40 @@ { "config": { "error": { + "error_auth_app": "Vale rakenduse ID v\u00f5i salas\u00f5na", + "error_auth_mfa": "Vale kood", "error_auth_user": "Vale kasutajanimi v\u00f5i salas\u00f5na" }, "step": { + "auth_app": { + "data": { + "app_id": "Rakenduse ID", + "app_secret": "Salas\u00f5na" + }, + "description": "Rakenduse ID ja [StarLine'i arendajakonto] salakood (https://my.starline.ru/developer)", + "title": "Rakenduse mandaadid" + }, "auth_captcha": { + "data": { + "captcha_code": "Kood pildilt" + }, + "description": "", "title": "" }, "auth_mfa": { + "data": { + "mfa_code": "SMS-kood" + }, + "description": "Sisesta telefonile {phone_number} saadetud kood", "title": "Kaheastmeline autoriseerimine" }, "auth_user": { "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "description": "StarLine konto e-post ja salas\u00f5na", + "title": "Kasutaja mandaat" } } } diff --git a/homeassistant/components/stream/const.py b/homeassistant/components/stream/const.py index 9406c24eaf6..181808e549e 100644 --- a/homeassistant/components/stream/const.py +++ b/homeassistant/components/stream/const.py @@ -23,3 +23,6 @@ MAX_TIMESTAMP_GAP = 10000 # seconds - anything from 10 to 50000 is probably rea MAX_MISSING_DTS = 6 # Number of packets missing DTS to allow STREAM_TIMEOUT = 30 # Timeout for reading stream + +STREAM_RESTART_INCREMENT = 10 # Increase wait_timeout by this amount each retry +STREAM_RESTART_RESET_TIME = 300 # Reset wait_timeout after this many seconds diff --git a/homeassistant/components/stream/recorder.py b/homeassistant/components/stream/recorder.py index d0b8789f602..420e7c654c5 100644 --- a/homeassistant/components/stream/recorder.py +++ b/homeassistant/components/stream/recorder.py @@ -25,12 +25,23 @@ def recorder_save_worker(file_out: str, segments: List[Segment], container_forma output_v = None output_a = None - for segment in segments: - # Seek to beginning and open segment - segment.segment.seek(0) + # Get first_pts values from first segment + if len(segments) > 0: + segment = segments[0] source = av.open(segment.segment, "r", format=container_format) source_v = source.streams.video[0] + first_pts["video"] = source_v.start_time + if len(source.streams.audio) > 0: + source_a = source.streams.audio[0] + first_pts["audio"] = int( + source_v.start_time * source_v.time_base / source_a.time_base + ) + source.close() + for segment in segments: + # Open segment + source = av.open(segment.segment, "r", format=container_format) + source_v = source.streams.video[0] # Add output streams if not output_v: output_v = output.add_stream(template=source_v) @@ -42,13 +53,12 @@ def recorder_save_worker(file_out: str, segments: List[Segment], container_forma # Remux video for packet in source.demux(): - if packet is not None and packet.dts is not None: - if first_pts[packet.stream.type] is None: - first_pts[packet.stream.type] = packet.pts - packet.pts -= first_pts[packet.stream.type] - packet.dts -= first_pts[packet.stream.type] - packet.stream = output_v if packet.stream.type == "video" else output_a - output.mux(packet) + if packet.dts is None: + continue + packet.pts -= first_pts[packet.stream.type] + packet.dts -= first_pts[packet.stream.type] + packet.stream = output_v if packet.stream.type == "video" else output_a + output.mux(packet) source.close() diff --git a/homeassistant/components/stream/worker.py b/homeassistant/components/stream/worker.py index 4f972774fcc..68cbbc79726 100644 --- a/homeassistant/components/stream/worker.py +++ b/homeassistant/components/stream/worker.py @@ -11,6 +11,8 @@ from .const import ( MAX_TIMESTAMP_GAP, MIN_SEGMENT_DURATION, PACKETS_TO_WAIT_FOR_AUDIO, + STREAM_RESTART_INCREMENT, + STREAM_RESTART_RESET_TIME, STREAM_TIMEOUT, ) from .core import Segment, StreamBuffer @@ -56,8 +58,13 @@ def stream_worker(hass, stream, quit_event): _LOGGER.exception("Stream connection failed: %s", stream.source) if not stream.keepalive or quit_event.is_set(): break - # To avoid excessive restarts, don't restart faster than once every 40 seconds. - wait_timeout = max(40 - (time.time() - start_time), 0) + # To avoid excessive restarts, wait before restarting + # As the required recovery time may be different for different setups, start + # with trying a short wait_timeout and increase it on each reconnection attempt. + # Reset the wait_timeout after the worker has been up for several minutes + if time.time() - start_time > STREAM_RESTART_RESET_TIME: + wait_timeout = 0 + wait_timeout += STREAM_RESTART_INCREMENT _LOGGER.debug( "Restarting stream worker in %d seconds: %s", wait_timeout, @@ -68,7 +75,13 @@ def stream_worker(hass, stream, quit_event): def _stream_worker_internal(hass, stream, quit_event): """Handle consuming streams.""" - container = av.open(stream.source, options=stream.options, timeout=STREAM_TIMEOUT) + try: + container = av.open( + stream.source, options=stream.options, timeout=STREAM_TIMEOUT + ) + except av.AVError: + _LOGGER.error("Error opening stream %s", stream.source) + return try: video_stream = container.streams.video[0] except (KeyError, IndexError): @@ -89,11 +102,8 @@ def _stream_worker_internal(hass, stream, quit_event): # Iterator for demuxing container_packets = None - # The presentation timestamps of the first packet in each stream we receive - # Use to adjust before muxing or outputting, but we don't adjust internally - first_pts = {} # The decoder timestamps of the latest packet in each stream we processed - last_dts = None + last_dts = {video_stream: float("-inf"), audio_stream: float("-inf")} # Keep track of consecutive packets without a dts to detect end of stream. missing_dts = 0 # Holds the buffers for each stream provider @@ -110,21 +120,19 @@ def _stream_worker_internal(hass, stream, quit_event): # 2 - seeking can be problematic https://trac.ffmpeg.org/ticket/7815 def peek_first_pts(): - nonlocal first_pts, audio_stream, container_packets + """Initialize by peeking into the first few packets of the stream. + + Deal with problem #1 above (bad first packet pts/dts) by recalculating using pts/dts from second packet. + Also load the first video keyframe pts into segment_start_pts and check if the audio stream really exists. + """ + nonlocal segment_start_pts, audio_stream, container_packets missing_dts = 0 - - def empty_stream_dict(): - return { - video_stream: None, - **({audio_stream: None} if audio_stream else {}), - } - + found_audio = False try: container_packets = container.demux((video_stream, audio_stream)) - first_packet = empty_stream_dict() - first_pts = empty_stream_dict() + first_packet = None # Get to first video keyframe - while first_packet[video_stream] is None: + while first_packet is None: packet = next(container_packets) if ( packet.dts is None @@ -135,13 +143,17 @@ def _stream_worker_internal(hass, stream, quit_event): ) missing_dts += 1 continue - if packet.stream == video_stream and packet.is_keyframe: - first_packet[video_stream] = packet + if packet.stream == audio_stream: + found_audio = True + elif packet.is_keyframe: # video_keyframe + first_packet = packet initial_packets.append(packet) # Get first_pts from subsequent frame to first keyframe - while any( - [pts is None for pts in {**first_packet, **first_pts}.values()] - ) and (len(initial_packets) < PACKETS_TO_WAIT_FOR_AUDIO): + while segment_start_pts is None or ( + audio_stream + and not found_audio + and len(initial_packets) < PACKETS_TO_WAIT_FOR_AUDIO + ): packet = next(container_packets) if ( packet.dts is None @@ -152,24 +164,19 @@ def _stream_worker_internal(hass, stream, quit_event): ) missing_dts += 1 continue - if ( - first_packet[packet.stream] is None - ): # actually video already found above so only for audio - if packet.is_keyframe: - first_packet[packet.stream] = packet - else: # Discard leading non-keyframes - continue - else: # This is the second frame to calculate first_pts from - if first_pts[packet.stream] is None: - first_pts[packet.stream] = packet.dts - packet.duration - first_packet[packet.stream].pts = first_pts[packet.stream] - first_packet[packet.stream].dts = first_pts[packet.stream] + if packet.stream == audio_stream: + found_audio = True + elif ( + segment_start_pts is None + ): # This is the second video frame to calculate first_pts from + segment_start_pts = packet.dts - packet.duration + first_packet.pts = segment_start_pts + first_packet.dts = segment_start_pts initial_packets.append(packet) - if audio_stream and first_packet[audio_stream] is None: + if audio_stream and not found_audio: _LOGGER.warning( "Audio stream not found" ) # Some streams declare an audio stream and never send any packets - del first_pts[audio_stream] audio_stream = None except (av.AVError, StopIteration) as ex: @@ -199,9 +206,6 @@ def _stream_worker_internal(hass, stream, quit_event): ) def mux_video_packet(packet): - # adjust pts and dts before muxing - packet.pts -= first_pts[video_stream] - packet.dts -= first_pts[video_stream] # mux packets to each buffer for buffer, output_streams in outputs.values(): # Assign the packet to the new stream & mux @@ -210,9 +214,6 @@ def _stream_worker_internal(hass, stream, quit_event): def mux_audio_packet(packet): # almost the same as muxing video but add extra check - # adjust pts and dts before muxing - packet.pts -= first_pts[audio_stream] - packet.dts -= first_pts[audio_stream] for buffer, output_streams in outputs.values(): # Assign the packet to the new stream & mux if output_streams.get(audio_stream): @@ -222,14 +223,14 @@ def _stream_worker_internal(hass, stream, quit_event): def finalize_stream(): if not stream.keepalive: # End of stream, clear listeners and stop thread - for fmt in stream.outputs.keys(): + for fmt in stream.outputs: hass.loop.call_soon_threadsafe(stream.outputs[fmt].put, None) if not peek_first_pts(): container.close() return - last_dts = {k: v - 1 for k, v in first_pts.items()} - initialize_segment(first_pts[video_stream]) + + initialize_segment(segment_start_pts) while not quit_event.is_set(): try: diff --git a/homeassistant/components/syncthru/translations/cs.json b/homeassistant/components/syncthru/translations/cs.json index 7527e6d81c8..d34668146a3 100644 --- a/homeassistant/components/syncthru/translations/cs.json +++ b/homeassistant/components/syncthru/translations/cs.json @@ -3,6 +3,9 @@ "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" }, + "error": { + "invalid_url": "Neplatn\u00e1 URL adresa" + }, "flow_title": "Tisk\u00e1rna Samsung SyncThru: {name}", "step": { "confirm": { diff --git a/homeassistant/components/syncthru/translations/et.json b/homeassistant/components/syncthru/translations/et.json index 71fe5cfb03c..85fae03ef3e 100644 --- a/homeassistant/components/syncthru/translations/et.json +++ b/homeassistant/components/syncthru/translations/et.json @@ -5,7 +5,23 @@ }, "error": { "invalid_url": "Sobimatu URL", + "syncthru_not_supported": "Seade ei toeta SyncThru-d", "unknown_state": "Printeri olek teadmata, kontrolli URL-i ja v\u00f5rgu\u00fchendust" + }, + "flow_title": "", + "step": { + "confirm": { + "data": { + "name": "", + "url": "Veebiliidese URL" + } + }, + "user": { + "data": { + "name": "Nimi", + "url": "Veebiliidese URL" + } + } } } } \ No newline at end of file diff --git a/homeassistant/components/syncthru/translations/nl.json b/homeassistant/components/syncthru/translations/nl.json index 900bac61bc5..349b4b2818e 100644 --- a/homeassistant/components/syncthru/translations/nl.json +++ b/homeassistant/components/syncthru/translations/nl.json @@ -1,5 +1,12 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "unknown_state": "Printerstatus onbekend, controleer URL en netwerkconnectiviteit" + }, + "flow_title": "Samsung SyncThru Printer: {name}", "step": { "user": { "data": { diff --git a/homeassistant/components/syncthru/translations/pl.json b/homeassistant/components/syncthru/translations/pl.json index 6b554ef9e74..cacb7e92b1f 100644 --- a/homeassistant/components/syncthru/translations/pl.json +++ b/homeassistant/components/syncthru/translations/pl.json @@ -6,20 +6,20 @@ "error": { "invalid_url": "Nieprawid\u0142owy URL", "syncthru_not_supported": "Urz\u0105dzenie nie obs\u0142uguje SyncThru", - "unknown_state": "Nieznany stan drukarki, sprawd\u017a adres URL i \u0142\u0105czno\u015b\u0107 sieciow\u0105" + "unknown_state": "Nieznany stan drukarki, sprawd\u017a adres URL i pod\u0142\u0105czenie do sieci" }, "flow_title": "Drukarka Samsung SyncThru: {name}", "step": { "confirm": { "data": { "name": "Nazwa", - "url": "Adres URL interfejsu internetowego" + "url": "URL interfejsu internetowego" } }, "user": { "data": { "name": "Nazwa", - "url": "Adres URL interfejsu internetowego" + "url": "URL interfejsu internetowego" } } } diff --git a/homeassistant/components/synology_dsm/__init__.py b/homeassistant/components/synology_dsm/__init__.py index a9c2f47e6b9..d8acf29016c 100644 --- a/homeassistant/components/synology_dsm/__init__.py +++ b/homeassistant/components/synology_dsm/__init__.py @@ -6,12 +6,17 @@ from typing import Dict from synology_dsm import SynologyDSM from synology_dsm.api.core.security import SynoCoreSecurity +from synology_dsm.api.core.system import SynoCoreSystem +from synology_dsm.api.core.upgrade import SynoCoreUpgrade from synology_dsm.api.core.utilization import SynoCoreUtilization from synology_dsm.api.dsm.information import SynoDSMInformation from synology_dsm.api.dsm.network import SynoDSMNetwork from synology_dsm.api.storage.storage import SynoStorage from synology_dsm.api.surveillance_station import SynoSurveillanceStation -from synology_dsm.exceptions import SynologyDSMRequestException +from synology_dsm.exceptions import ( + SynologyDSMLoginFailedException, + SynologyDSMRequestException, +) import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry @@ -26,8 +31,9 @@ from homeassistant.const import ( CONF_SSL, CONF_TIMEOUT, CONF_USERNAME, + CONF_VERIFY_SSL, ) -from homeassistant.core import callback +from homeassistant.core import ServiceCall, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import entity_registry import homeassistant.helpers.config_validation as cv @@ -40,9 +46,11 @@ from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.typing import HomeAssistantType from .const import ( + CONF_SERIAL, CONF_VOLUMES, DEFAULT_SCAN_INTERVAL, - DEFAULT_SSL, + DEFAULT_USE_SSL, + DEFAULT_VERIFY_SSL, DOMAIN, ENTITY_CLASS, ENTITY_ENABLE, @@ -50,6 +58,9 @@ from .const import ( ENTITY_NAME, ENTITY_UNIT, PLATFORMS, + SERVICE_REBOOT, + SERVICE_SHUTDOWN, + SERVICES, STORAGE_DISK_BINARY_SENSORS, STORAGE_DISK_SENSORS, STORAGE_VOL_SENSORS, @@ -63,7 +74,8 @@ CONFIG_SCHEMA = vol.Schema( { vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_PORT): cv.port, - vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, + vol.Optional(CONF_SSL, default=DEFAULT_USE_SSL): cv.boolean, + vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean, vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_DISKS): cv.ensure_list, @@ -162,11 +174,18 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): await entity_registry.async_migrate_entries(hass, entry.entry_id, _async_migrator) + # Migrate existing entry configuration + if entry.data.get(CONF_VERIFY_SSL) is None: + hass.config_entries.async_update_entry( + entry, data={**entry.data, CONF_VERIFY_SSL: DEFAULT_VERIFY_SSL} + ) + # Continue setup api = SynoApi(hass, entry) try: await api.async_setup() - except SynologyDSMRequestException as err: + except (SynologyDSMLoginFailedException, SynologyDSMRequestException) as err: + _LOGGER.debug("async_setup_entry - Unable to connect to DSM: %s", str(err)) raise ConfigEntryNotReady from err undo_listener = entry.add_update_listener(_async_update_listener) @@ -177,6 +196,9 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): UNDO_UPDATE_LISTENER: undo_listener, } + # Services + await _async_setup_services(hass) + # For SSDP compat if not entry.data.get(CONF_MAC): network = await hass.async_add_executor_job(getattr, api.dsm, "network") @@ -217,6 +239,49 @@ async def _async_update_listener(hass: HomeAssistantType, entry: ConfigEntry): await hass.config_entries.async_reload(entry.entry_id) +async def _async_setup_services(hass: HomeAssistantType): + """Service handler setup.""" + + async def service_handler(call: ServiceCall): + """Handle service call.""" + _LOGGER.debug( + "service_handler - called as '%s' with data: %s", call.service, call.data + ) + serial = call.data.get(CONF_SERIAL) + dsm_devices = hass.data[DOMAIN] + + if serial: + dsm_device = dsm_devices.get(serial) + elif len(dsm_devices) == 1: + dsm_device = next(iter(dsm_devices.values())) + serial = next(iter(dsm_devices)) + else: + _LOGGER.error( + "service_handler - more than one DSM configured, must specify one of serials %s", + sorted(dsm_devices), + ) + return + + if not dsm_device: + _LOGGER.error( + "service_handler - DSM with specified serial %s not found", serial + ) + return + + _LOGGER.info("%s DSM with serial %s", call.service, serial) + dsm_api = dsm_device[SYNO_API] + if call.service == SERVICE_REBOOT: + await dsm_api.async_reboot() + elif call.service == SERVICE_SHUTDOWN: + await dsm_api.system.shutdown() + + for service in SERVICES: + _LOGGER.debug( + "_async_setup_services - register service %s on domain %s", service, DOMAIN + ) + hass.services.async_register(DOMAIN, service, service_handler) + + class SynoApi: """Class to interface with Synology DSM API.""" @@ -231,16 +296,20 @@ class SynoApi: self.network: SynoDSMNetwork = None self.security: SynoCoreSecurity = None self.storage: SynoStorage = None - self.utilisation: SynoCoreUtilization = None self.surveillance_station: SynoSurveillanceStation = None + self.system: SynoCoreSystem = None + self.upgrade: SynoCoreUpgrade = None + self.utilisation: SynoCoreUtilization = None # Should we fetch them self._fetching_entities = {} + self._with_information = True self._with_security = True self._with_storage = True - self._with_utilisation = True - self._with_information = True self._with_surveillance_station = True + self._with_system = True + self._with_upgrade = True + self._with_utilisation = True self._unsub_dispatcher = None @@ -257,6 +326,7 @@ class SynoApi: self._entry.data[CONF_USERNAME], self._entry.data[CONF_PASSWORD], self._entry.data[CONF_SSL], + self._entry.data[CONF_VERIFY_SSL], timeout=self._entry.options.get(CONF_TIMEOUT), device_token=self._entry.data.get("device_token"), ) @@ -307,6 +377,8 @@ class SynoApi: self._fetching_entities.get(SynoCoreSecurity.API_KEY) ) self._with_storage = bool(self._fetching_entities.get(SynoStorage.API_KEY)) + self._with_system = bool(self._fetching_entities.get(SynoCoreSystem.API_KEY)) + self._with_upgrade = bool(self._fetching_entities.get(SynoCoreUpgrade.API_KEY)) self._with_utilisation = bool( self._fetching_entities.get(SynoCoreUtilization.API_KEY) ) @@ -328,6 +400,14 @@ class SynoApi: self.dsm.reset(self.storage) self.storage = None + if not self._with_system: + self.dsm.reset(self.system) + self.system = None + + if not self._with_upgrade: + self.dsm.reset(self.upgrade) + self.upgrade = None + if not self._with_utilisation: self.dsm.reset(self.utilisation) self.utilisation = None @@ -348,12 +428,32 @@ class SynoApi: if self._with_storage: self.storage = self.dsm.storage + if self._with_upgrade: + self.upgrade = self.dsm.upgrade + + if self._with_system: + self.system = self.dsm.system + if self._with_utilisation: self.utilisation = self.dsm.utilisation if self._with_surveillance_station: self.surveillance_station = self.dsm.surveillance_station + async def async_reboot(self): + """Reboot NAS.""" + if not self.system: + _LOGGER.debug("async_reboot - System API not ready: %s", self) + return + self._hass.async_add_executor_job(self.system.reboot) + + async def async_shutdown(self): + """Shutdown NAS.""" + if not self.system: + _LOGGER.debug("async_shutdown - System API not ready: %s", self) + return + self._hass.async_add_executor_job(self.system.shutdown) + async def async_unload(self): """Stop interacting with the NAS and prepare for removal from hass.""" self._unsub_dispatcher() @@ -361,8 +461,17 @@ class SynoApi: async def async_update(self, now=None): """Update function for updating API information.""" self._async_setup_api_requests() - await self._hass.async_add_executor_job(self.dsm.update, self._with_information) - async_dispatcher_send(self._hass, self.signal_sensor_update) + try: + await self._hass.async_add_executor_job( + self.dsm.update, self._with_information + ) + async_dispatcher_send(self._hass, self.signal_sensor_update) + except (SynologyDSMLoginFailedException, SynologyDSMRequestException) as err: + _LOGGER.warning( + "async_update - connection error during update, fallback by reloading the entry" + ) + _LOGGER.debug("async_update - exception: %s", str(err)) + await self._hass.config_entries.async_reload(self._entry.entry_id) class SynologyDSMEntity(Entity): diff --git a/homeassistant/components/synology_dsm/binary_sensor.py b/homeassistant/components/synology_dsm/binary_sensor.py index 6c11d31b7f7..69f217a4b4e 100644 --- a/homeassistant/components/synology_dsm/binary_sensor.py +++ b/homeassistant/components/synology_dsm/binary_sensor.py @@ -12,6 +12,7 @@ from .const import ( SECURITY_BINARY_SENSORS, STORAGE_DISK_BINARY_SENSORS, SYNO_API, + UPGRADE_BINARY_SENSORS, ) @@ -29,6 +30,13 @@ async def async_setup_entry( for sensor_type in SECURITY_BINARY_SENSORS ] + entities += [ + SynoDSMUpgradeBinarySensor( + api, sensor_type, UPGRADE_BINARY_SENSORS[sensor_type] + ) + for sensor_type in UPGRADE_BINARY_SENSORS + ] + # Handle all disks if api.storage.disks_ids: for disk in entry.data.get(CONF_DISKS, api.storage.disks_ids): @@ -68,3 +76,17 @@ class SynoDSMStorageBinarySensor(SynologyDSMDeviceEntity, BinarySensorEntity): def is_on(self) -> bool: """Return the state.""" return getattr(self._api.storage, self.entity_type)(self._device_id) + + +class SynoDSMUpgradeBinarySensor(SynologyDSMEntity, BinarySensorEntity): + """Representation a Synology Upgrade binary sensor.""" + + @property + def is_on(self) -> bool: + """Return the state.""" + return getattr(self._api.upgrade, self.entity_type) + + @property + def available(self) -> bool: + """Return True if entity is available.""" + return bool(self._api.upgrade) diff --git a/homeassistant/components/synology_dsm/config_flow.py b/homeassistant/components/synology_dsm/config_flow.py index 314bab54806..5a1ab53b3f7 100644 --- a/homeassistant/components/synology_dsm/config_flow.py +++ b/homeassistant/components/synology_dsm/config_flow.py @@ -25,6 +25,7 @@ from homeassistant.const import ( CONF_SSL, CONF_TIMEOUT, CONF_USERNAME, + CONF_VERIFY_SSL, ) from homeassistant.core import callback import homeassistant.helpers.config_validation as cv @@ -34,8 +35,9 @@ from .const import ( DEFAULT_PORT, DEFAULT_PORT_SSL, DEFAULT_SCAN_INTERVAL, - DEFAULT_SSL, DEFAULT_TIMEOUT, + DEFAULT_USE_SSL, + DEFAULT_VERIFY_SSL, ) from .const import DOMAIN # pylint: disable=unused-import @@ -62,7 +64,13 @@ def _ordered_shared_schema(schema_input): vol.Required(CONF_USERNAME, default=schema_input.get(CONF_USERNAME, "")): str, vol.Required(CONF_PASSWORD, default=schema_input.get(CONF_PASSWORD, "")): str, vol.Optional(CONF_PORT, default=schema_input.get(CONF_PORT, "")): str, - vol.Optional(CONF_SSL, default=schema_input.get(CONF_SSL, DEFAULT_SSL)): bool, + vol.Optional( + CONF_SSL, default=schema_input.get(CONF_SSL, DEFAULT_USE_SSL) + ): bool, + vol.Optional( + CONF_VERIFY_SSL, + default=schema_input.get(CONF_VERIFY_SSL, DEFAULT_VERIFY_SSL), + ): bool, } @@ -117,7 +125,8 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): port = user_input.get(CONF_PORT) username = user_input[CONF_USERNAME] password = user_input[CONF_PASSWORD] - use_ssl = user_input.get(CONF_SSL, DEFAULT_SSL) + use_ssl = user_input.get(CONF_SSL, DEFAULT_USE_SSL) + verify_ssl = user_input.get(CONF_VERIFY_SSL, DEFAULT_VERIFY_SSL) otp_code = user_input.get(CONF_OTP_CODE) if not port: @@ -126,7 +135,9 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): else: port = DEFAULT_PORT - api = SynologyDSM(host, port, username, password, use_ssl, timeout=30) + api = SynologyDSM( + host, port, username, password, use_ssl, verify_ssl, timeout=30 + ) try: serial = await self.hass.async_add_executor_job( @@ -153,14 +164,17 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): if errors: return await self._show_setup_form(user_input, errors) - # Check if already configured + # unique_id should be serial for services purpose await self.async_set_unique_id(serial, raise_on_progress=False) + + # Check if already configured self._abort_if_unique_id_configured() config_data = { CONF_HOST: host, CONF_PORT: port, CONF_SSL: use_ssl, + CONF_VERIFY_SSL: verify_ssl, CONF_USERNAME: username, CONF_PASSWORD: password, CONF_MAC: api.network.macs, diff --git a/homeassistant/components/synology_dsm/const.py b/homeassistant/components/synology_dsm/const.py index 82bb232461e..ba1a8034223 100644 --- a/homeassistant/components/synology_dsm/const.py +++ b/homeassistant/components/synology_dsm/const.py @@ -1,6 +1,7 @@ """Constants for Synology DSM.""" from synology_dsm.api.core.security import SynoCoreSecurity +from synology_dsm.api.core.upgrade import SynoCoreUpgrade from synology_dsm.api.core.utilization import SynoCoreUtilization from synology_dsm.api.dsm.information import SynoDSMInformation from synology_dsm.api.storage.storage import SynoStorage @@ -24,9 +25,11 @@ SYNO_API = "syno_api" UNDO_UPDATE_LISTENER = "undo_update_listener" # Configuration +CONF_SERIAL = "serial" CONF_VOLUMES = "volumes" -DEFAULT_SSL = True +DEFAULT_USE_SSL = True +DEFAULT_VERIFY_SSL = False DEFAULT_PORT = 5000 DEFAULT_PORT_SSL = 5001 # Options @@ -40,9 +43,27 @@ ENTITY_ICON = "icon" ENTITY_CLASS = "device_class" ENTITY_ENABLE = "enable" +# Services +SERVICE_REBOOT = "reboot" +SERVICE_SHUTDOWN = "shutdown" +SERVICES = [ + SERVICE_REBOOT, + SERVICE_SHUTDOWN, +] + # Entity keys should start with the API_KEY to fetch # Binary sensors +UPGRADE_BINARY_SENSORS = { + f"{SynoCoreUpgrade.API_KEY}:update_available": { + ENTITY_NAME: "Update available", + ENTITY_UNIT: None, + ENTITY_ICON: "mdi:update", + ENTITY_CLASS: None, + ENTITY_ENABLE: True, + }, +} + SECURITY_BINARY_SENSORS = { f"{SynoCoreSecurity.API_KEY}:status": { ENTITY_NAME: "Security status", diff --git a/homeassistant/components/synology_dsm/manifest.json b/homeassistant/components/synology_dsm/manifest.json index 6aefaf7742b..1dc0f2a3242 100644 --- a/homeassistant/components/synology_dsm/manifest.json +++ b/homeassistant/components/synology_dsm/manifest.json @@ -3,7 +3,7 @@ "name": "Synology DSM", "documentation": "https://www.home-assistant.io/integrations/synology_dsm", "requirements": ["python-synology==1.0.0"], - "codeowners": ["@hacf-fr", "@Quentame"], + "codeowners": ["@hacf-fr", "@Quentame", "@mib1185"], "config_flow": true, "ssdp": [ { diff --git a/homeassistant/components/synology_dsm/services.yaml b/homeassistant/components/synology_dsm/services.yaml new file mode 100644 index 00000000000..f75b2f0ec8a --- /dev/null +++ b/homeassistant/components/synology_dsm/services.yaml @@ -0,0 +1,15 @@ +# synology-dsm service entries description. + +reboot: + description: Reboot the NAS. + fields: + serial: + description: serial of the NAS to reboot; required when multiple NAS are configured. + example: 1NDVC86409 + +shutdown: + description: Shutdown the NAS. + fields: + serial: + description: serial of the NAS to shutdown; required when multiple NAS are configured. + example: 1NDVC86409 diff --git a/homeassistant/components/synology_dsm/strings.json b/homeassistant/components/synology_dsm/strings.json index 9ff0b16f8fb..91933571028 100644 --- a/homeassistant/components/synology_dsm/strings.json +++ b/homeassistant/components/synology_dsm/strings.json @@ -8,6 +8,7 @@ "host": "[%key:common::config_flow::data::host%]", "port": "[%key:common::config_flow::data::port%]", "ssl": "[%key:common::config_flow::data::ssl%]", + "verify_ssl": "[%key:common::config_flow::data::verify_ssl%]", "username": "[%key:common::config_flow::data::username%]", "password": "[%key:common::config_flow::data::password%]" } @@ -23,6 +24,7 @@ "description": "Do you want to setup {name} ({host})?", "data": { "ssl": "[%key:common::config_flow::data::ssl%]", + "verify_ssl": "[%key:common::config_flow::data::verify_ssl%]", "username": "[%key:common::config_flow::data::username%]", "password": "[%key:common::config_flow::data::password%]", "port": "[%key:common::config_flow::data::port%]" diff --git a/homeassistant/components/synology_dsm/translations/ca.json b/homeassistant/components/synology_dsm/translations/ca.json index 71372908ff4..05ea3f78801 100644 --- a/homeassistant/components/synology_dsm/translations/ca.json +++ b/homeassistant/components/synology_dsm/translations/ca.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connection": "Error de connexi\u00f3: comprova l'amfitri\u00f3, la contrasenya i l'SSL", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "login": "Error d'inici de sessi\u00f3: comprova el nom d'usuari i la contrasenya", "missing_data": "Falten dades: torna-ho a provar m\u00e9s tard o prova una altra configuraci\u00f3 diferent", "otp_failed": "L'autenticaci\u00f3 en dos passos ha fallat, torna-ho a provar amb un nou codi", "unknown": "Error inesperat" @@ -25,7 +23,8 @@ "password": "Contrasenya", "port": "Port", "ssl": "Utilitza un certificat SSL", - "username": "Nom d'usuari" + "username": "Nom d'usuari", + "verify_ssl": "Verifica el certificat SSL" }, "description": "Vols configurar {name} ({host})?", "title": "Synology DSM" @@ -36,7 +35,8 @@ "password": "Contrasenya", "port": "Port", "ssl": "Utilitza un certificat SSL", - "username": "Nom d'usuari" + "username": "Nom d'usuari", + "verify_ssl": "Verifica el certificat SSL" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/cs.json b/homeassistant/components/synology_dsm/translations/cs.json index ce48a3c23b6..a9fdd199618 100644 --- a/homeassistant/components/synology_dsm/translations/cs.json +++ b/homeassistant/components/synology_dsm/translations/cs.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection": "Chyba p\u0159ipojen\u00ed: zkontrolujte pros\u00edm sv\u00e9ho hostitele, port a SSL", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "login": "Chyba p\u0159ihl\u00e1\u0161en\u00ed: zkontrolujte sv\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no a heslo", "missing_data": "Chyb\u011bj\u00edc\u00ed data: zkuste to pros\u00edm pozd\u011bji nebo s jin\u00fdm nastaven\u00edm", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, @@ -24,7 +22,8 @@ "password": "Heslo", "port": "Port", "ssl": "Pou\u017e\u00edv\u00e1 SSL certifik\u00e1t", - "username": "U\u017eivatelsk\u00e9 jm\u00e9no" + "username": "U\u017eivatelsk\u00e9 jm\u00e9no", + "verify_ssl": "Ov\u011b\u0159it certifik\u00e1t SSL" }, "description": "Chcete nastavit {name} ({host})?", "title": "Synology DSM" @@ -35,7 +34,8 @@ "password": "Heslo", "port": "Port", "ssl": "Pou\u017e\u00edv\u00e1 SSL certifik\u00e1t", - "username": "U\u017eivatelsk\u00e9 jm\u00e9no" + "username": "U\u017eivatelsk\u00e9 jm\u00e9no", + "verify_ssl": "Ov\u011b\u0159it certifik\u00e1t SSL" }, "title": "Synology DSM" } @@ -45,6 +45,7 @@ "step": { "init": { "data": { + "scan_interval": "Po\u010det minut mezi skenov\u00e1n\u00edm", "timeout": "\u010casov\u00fd limit (v sekund\u00e1ch)" } } diff --git a/homeassistant/components/synology_dsm/translations/de.json b/homeassistant/components/synology_dsm/translations/de.json index 205bf5197b0..47c01a0309f 100644 --- a/homeassistant/components/synology_dsm/translations/de.json +++ b/homeassistant/components/synology_dsm/translations/de.json @@ -4,8 +4,6 @@ "already_configured": "Host bereits konfiguriert" }, "error": { - "connection": "Verbindungsfehler: Bitte \u00fcberpr\u00fcfe Host, Port und SSL", - "login": "Login-Fehler: Bitte \u00fcberpr\u00fcfen Sie Ihren Benutzernamen & Passwort", "missing_data": "Fehlende Daten: Bitte versuchen Sie es sp\u00e4ter noch einmal oder eine andere Konfiguration", "otp_failed": "Die zweistufige Authentifizierung ist fehlgeschlagen. Versuchen Sie es erneut mit einem neuen Code", "unknown": "Unbekannter Fehler: Bitte \u00fcberpr\u00fcfen Sie die Protokolle, um weitere Details zu erhalten" @@ -23,7 +21,8 @@ "password": "Passwort", "port": "Port", "ssl": "Verwenden Sie SSL/TLS, um eine Verbindung zu Ihrem NAS herzustellen", - "username": "Benutzername" + "username": "Benutzername", + "verify_ssl": "SSL Zertifikat verifizieren" }, "description": "M\u00f6chten Sie {name} ({host}) einrichten?", "title": "Synology DSM" @@ -34,7 +33,8 @@ "password": "Passwort", "port": "Port", "ssl": "Verwenden Sie SSL/TLS, um eine Verbindung zu Ihrem NAS herzustellen", - "username": "Benutzername" + "username": "Benutzername", + "verify_ssl": "SSL Zertifikat verifizieren" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/en.json b/homeassistant/components/synology_dsm/translations/en.json index 54266f9e8fa..1501aa89485 100644 --- a/homeassistant/components/synology_dsm/translations/en.json +++ b/homeassistant/components/synology_dsm/translations/en.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "Failed to connect", - "connection": "Connection error: please check your host, port & ssl", "invalid_auth": "Invalid authentication", - "login": "Login error: please check your username & password", "missing_data": "Missing data: please retry later or an other configuration", "otp_failed": "Two-step authentication failed, retry with a new pass code", "unknown": "Unexpected error" @@ -25,7 +23,8 @@ "password": "Password", "port": "Port", "ssl": "Uses an SSL certificate", - "username": "Username" + "username": "Username", + "verify_ssl": "Verify SSL certificate" }, "description": "Do you want to setup {name} ({host})?", "title": "Synology DSM" @@ -36,7 +35,8 @@ "password": "Password", "port": "Port", "ssl": "Uses an SSL certificate", - "username": "Username" + "username": "Username", + "verify_ssl": "Verify SSL certificate" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/es-419.json b/homeassistant/components/synology_dsm/translations/es-419.json index a7c83782df5..2886a8ef624 100644 --- a/homeassistant/components/synology_dsm/translations/es-419.json +++ b/homeassistant/components/synology_dsm/translations/es-419.json @@ -4,8 +4,6 @@ "already_configured": "Host ya configurado" }, "error": { - "connection": "Error de conexi\u00f3n: compruebe su host, puerto y ssl", - "login": "Error de inicio de sesi\u00f3n: compruebe su nombre de usuario y contrase\u00f1a", "missing_data": "Datos faltantes: vuelva a intentarlo m\u00e1s tarde u otra configuraci\u00f3n", "otp_failed": "La autenticaci\u00f3n de dos pasos fall\u00f3, vuelva a intentar con un nuevo c\u00f3digo de acceso", "unknown": "Error desconocido: verifique los registros para obtener m\u00e1s detalles" diff --git a/homeassistant/components/synology_dsm/translations/es.json b/homeassistant/components/synology_dsm/translations/es.json index c428054f2de..f76ce7ab27a 100644 --- a/homeassistant/components/synology_dsm/translations/es.json +++ b/homeassistant/components/synology_dsm/translations/es.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "connection": "Error de conexi\u00f3n: comprueba tu host, puerto y ssl", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "login": "Error de inicio de sesi\u00f3n: comprueba tu nombre de usuario y contrase\u00f1a", "missing_data": "Faltan datos: por favor, vuelva a intentarlo m\u00e1s tarde o pruebe con otra configuraci\u00f3n", "otp_failed": "La autenticaci\u00f3n de dos pasos fall\u00f3, vuelva a intentar con un nuevo c\u00f3digo de acceso", "unknown": "Error desconocido: por favor, consulta logs para obtener m\u00e1s detalles" @@ -25,7 +23,8 @@ "password": "Contrase\u00f1a", "port": "Puerto", "ssl": "Usar SSL/TLS para conectar con tu NAS", - "username": "Usuario" + "username": "Usuario", + "verify_ssl": "Verificar certificado SSL" }, "description": "\u00bfQuieres configurar {name} ({host})?", "title": "Synology DSM" @@ -36,7 +35,8 @@ "password": "Contrase\u00f1a", "port": "Puerto", "ssl": "Usar SSL/TLS para conectar con tu NAS", - "username": "Usuario" + "username": "Usuario", + "verify_ssl": "Verificar certificado SSL" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/et.json b/homeassistant/components/synology_dsm/translations/et.json index 354fa0058d2..7b7b14c17ea 100644 --- a/homeassistant/components/synology_dsm/translations/et.json +++ b/homeassistant/components/synology_dsm/translations/et.json @@ -6,21 +6,37 @@ "error": { "cannot_connect": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamise viga", - "login": "Viga sisselogimisel: kontrolli palun oma kasutajanime ja salas\u00f5na", + "missing_data": "Andmed puuduvad: proovi hiljem uuesti v\u00f5i kasuta muid s\u00e4tteid", + "otp_failed": "Kaheastmeline autentimine nurjus, proovi uuesti uue p\u00e4\u00e4sukoodiga", "unknown": "Tundmatu viga" }, + "flow_title": "", "step": { + "2sa": { + "data": { + "otp_code": "Kood" + }, + "title": "Synology DSM: kaheastmeline autentimine (2FA)" + }, "link": { "data": { "password": "Salas\u00f5na", - "username": "Kasutajanimi" + "port": "", + "ssl": "Kasutab SSL sertifikaati", + "username": "Kasutajanimi", + "verify_ssl": "Kontrolli SSL sertifikaati" }, "description": "Kas soovid seadistada {name}({host})?", "title": "" }, "user": { "data": { - "password": "Salas\u00f5na" + "host": "", + "password": "Salas\u00f5na", + "port": "", + "ssl": "Kasutab SSL sertifikaati", + "username": "Kasutajanimi", + "verify_ssl": "Kontrolli SSL sertifikaati" }, "title": "" } @@ -30,6 +46,7 @@ "step": { "init": { "data": { + "scan_interval": "P\u00e4ringute vahe minutites", "timeout": "Ajal\u00f5pp (sekundites)" } } diff --git a/homeassistant/components/synology_dsm/translations/fr.json b/homeassistant/components/synology_dsm/translations/fr.json index 1c411591f1a..361bd8de76e 100644 --- a/homeassistant/components/synology_dsm/translations/fr.json +++ b/homeassistant/components/synology_dsm/translations/fr.json @@ -4,8 +4,8 @@ "already_configured": "H\u00f4te d\u00e9j\u00e0 configur\u00e9" }, "error": { - "connection": "Erreur de connexion: veuillez v\u00e9rifier votre h\u00f4te, port et SSL", - "login": "Erreur de connexion: veuillez v\u00e9rifier votre nom d'utilisateur et votre mot de passe", + "cannot_connect": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide", "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", "unknown": "Erreur inconnue: veuillez consulter les journaux pour obtenir plus de d\u00e9tails" @@ -23,7 +23,8 @@ "password": "Mot de passe", "port": "Port", "ssl": "Utilisez SSL/TLS pour vous connecter \u00e0 votre NAS", - "username": "Nom d'utilisateur" + "username": "Nom d'utilisateur", + "verify_ssl": "V\u00e9rifiez le certificat SSL" }, "description": "Voulez-vous configurer {name} ({host})?", "title": "Synology DSM" @@ -34,7 +35,8 @@ "password": "Mot de passe", "port": "Port", "ssl": "Utilisez SSL/TLS pour vous connecter \u00e0 votre NAS", - "username": "Nom d'utilisateur" + "username": "Nom d'utilisateur", + "verify_ssl": "V\u00e9rifiez le certificat SSL" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/hi.json b/homeassistant/components/synology_dsm/translations/hi.json index de48b719ea7..adb4398f8ad 100644 --- a/homeassistant/components/synology_dsm/translations/hi.json +++ b/homeassistant/components/synology_dsm/translations/hi.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connection": "\u0915\u0928\u0947\u0915\u094d\u0936\u0928 \u0924\u094d\u0930\u0941\u091f\u093f: \u0915\u0943\u092a\u092f\u093e \u0905\u092a\u0928\u0947 \u0939\u094b\u0938\u094d\u091f, \u092a\u094b\u0930\u094d\u091f \u0914\u0930 \u090f\u0938\u090f\u0938\u090f\u0932 \u0915\u0940 \u091c\u093e\u0902\u091a \u0915\u0930\u0947\u0902", "unknown": "\u0905\u091c\u094d\u091e\u093e\u0924 \u0924\u094d\u0930\u0941\u091f\u093f: \u0905\u0927\u093f\u0915 \u0935\u093f\u0935\u0930\u0923 \u092a\u094d\u0930\u093e\u092a\u094d\u0924 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0932\u0949\u0917 \u0915\u0940 \u091c\u093e\u0902\u091a \u0915\u0930\u0947\u0902" } } diff --git a/homeassistant/components/synology_dsm/translations/it.json b/homeassistant/components/synology_dsm/translations/it.json index 986e35119c7..f57cfedd12d 100644 --- a/homeassistant/components/synology_dsm/translations/it.json +++ b/homeassistant/components/synology_dsm/translations/it.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "connection": "Errore di connessione: controlla host, porta e SSL", "invalid_auth": "Autenticazione non valida", - "login": "Errore di accesso: si prega di controllare il nome utente e la password", "missing_data": "Dati mancanti: si prega di riprovare pi\u00f9 tardi o un'altra configurazione", "otp_failed": "Autenticazione in due fasi fallita, riprovare con un nuovo codice di accesso", "unknown": "Errore imprevisto" @@ -25,7 +23,8 @@ "password": "Password", "port": "Porta", "ssl": "Utilizza un certificato SSL", - "username": "Nome utente" + "username": "Nome utente", + "verify_ssl": "Verificare il certificato SSL" }, "description": "Vuoi impostare {name} ({host})?", "title": "Synology DSM" @@ -36,7 +35,8 @@ "password": "Password", "port": "Porta", "ssl": "Utilizza un certificato SSL", - "username": "Nome utente" + "username": "Nome utente", + "verify_ssl": "Verificare il certificato SSL" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/ko.json b/homeassistant/components/synology_dsm/translations/ko.json index 6c0dc98b4ae..6989f6515a1 100644 --- a/homeassistant/components/synology_dsm/translations/ko.json +++ b/homeassistant/components/synology_dsm/translations/ko.json @@ -4,8 +4,6 @@ "already_configured": "\ud638\uc2a4\ud2b8\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "error": { - "connection": "\ub85c\uadf8\uc778 \uc624\ub958: \ud638\uc2a4\ud2b8\ub098 \ud3ec\ud2b8 \ub610\ub294 \uc778\uc99d\uc11c\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694", - "login": "\ub85c\uadf8\uc778 \uc624\ub958: \uc0ac\uc6a9\uc790 \uc774\ub984 \ubc0f \ube44\ubc00\ubc88\ud638\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694", "missing_data": "\ub204\ub77d\ub41c \ub370\uc774\ud130: \ub098\uc911\uc5d0 \ub2e4\uc2dc \uc2dc\ub3c4\ud558\uac70\ub098 \ub2e4\ub978 \uad6c\uc131\uc744 \uc2dc\ub3c4\ud574\ubcf4\uc138\uc694", "otp_failed": "2\ub2e8\uacc4 \uc778\uc99d\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. \uc0c8\ub85c\uc6b4 \ud328\uc2a4 \ucf54\ub4dc\ub85c \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694", "unknown": "\uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uc785\ub2c8\ub2e4. \uc790\uc138\ud55c \uc815\ubcf4\ub294 \ub85c\uadf8\ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694" diff --git a/homeassistant/components/synology_dsm/translations/lb.json b/homeassistant/components/synology_dsm/translations/lb.json index 78f3f434064..4360b8685b3 100644 --- a/homeassistant/components/synology_dsm/translations/lb.json +++ b/homeassistant/components/synology_dsm/translations/lb.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "Feeler beim verbannen", - "connection": "Feeler beim verbannen Iwwerpr\u00e9if w.e.g. den Numm, Passwuert & SSL", "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "login": "Feeler beim Login: iwwerpr\u00e9if de Benotzernumm & Passwuert", "missing_data": "Donn\u00e9\u00ebe feelen, prob\u00e9ier sp\u00e9ider oder mat enger aner Konfiguratioun", "otp_failed": "Feeler mam 2-Faktor-Authentifikatiouns, prob\u00e9ier mat engem neie Code", "unknown": "Onerwaarte Feeler" @@ -24,8 +22,9 @@ "data": { "password": "Passwuert", "port": "Port", - "ssl": "Benotz SSL/TLS fir d'Verbindung mam NAS", - "username": "Benotzernumm" + "ssl": "Benotzt ee SSL Zertifikat", + "username": "Benotzernumm", + "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" }, "description": "Soll {name} ({host}) konfigur\u00e9iert ginn?", "title": "Synology DSM" @@ -35,8 +34,9 @@ "host": "Apparat", "password": "Passwuert", "port": "Port", - "ssl": "Benotzt SSL/TLS fir sech mam NAS ze verbannen", - "username": "Benotzernumm" + "ssl": "Benotzt ee SSL Zertifikat", + "username": "Benotzernumm", + "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/nl.json b/homeassistant/components/synology_dsm/translations/nl.json index d03c70d3711..d4932064a60 100644 --- a/homeassistant/components/synology_dsm/translations/nl.json +++ b/homeassistant/components/synology_dsm/translations/nl.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Kan geen verbinding maken", - "connection": "Verbindingsfout: controleer uw host, poort & ssl", - "login": "Aanmeldingsfout: controleer uw gebruikersnaam en wachtwoord", + "invalid_auth": "Ongeldige authenticatie", "missing_data": "Ontbrekende gegevens: probeer het later opnieuw of een andere configuratie", "otp_failed": "Tweestapsverificatie is mislukt, probeer het opnieuw met een nieuwe toegangscode", "unknown": "Onbekende fout: controleer de logs voor meer informatie" @@ -24,7 +23,8 @@ "password": "Wachtwoord", "port": "Poort (optioneel)", "ssl": "Gebruik SSL/TLS om verbinding te maken met uw NAS", - "username": "Gebruikersnaam" + "username": "Gebruikersnaam", + "verify_ssl": "Controleer het SSL-certificaat" }, "description": "Wil je {name} ({host}) instellen?", "title": "Synology DSM" @@ -35,7 +35,8 @@ "password": "Wachtwoord", "port": "Poort (optioneel)", "ssl": "Gebruik SSL/TLS om verbinding te maken met uw NAS", - "username": "Gebruikersnaam" + "username": "Gebruikersnaam", + "verify_ssl": "Controleer het SSL-certificaat" }, "title": "Synology DSM" } @@ -45,6 +46,7 @@ "step": { "init": { "data": { + "scan_interval": "Minuten tussen scans", "timeout": "Time-out (seconden)" } } diff --git a/homeassistant/components/synology_dsm/translations/no.json b/homeassistant/components/synology_dsm/translations/no.json index 9dffa382c38..c66ccdcbf45 100644 --- a/homeassistant/components/synology_dsm/translations/no.json +++ b/homeassistant/components/synology_dsm/translations/no.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "connection": "Tilkoblingsfeil: Vennligst sjekk verten, porten og SSL", "invalid_auth": "Ugyldig godkjenning", - "login": "P\u00e5loggingsfeil: Vennligst sjekk brukernavnet ditt og passordet ditt", "missing_data": "Manglende data: Vennligst pr\u00f8v p\u00e5 nytt senere eller en annen konfigurasjon", "otp_failed": "Totrinnsgodkjenning mislyktes, pr\u00f8v p\u00e5 nytt med en ny passord", "unknown": "Uventet feil" @@ -25,7 +23,8 @@ "password": "Passord", "port": "Port", "ssl": "Bruker et SSL-sertifikat", - "username": "Brukernavn" + "username": "Brukernavn", + "verify_ssl": "Verifisere SSL-sertifikat" }, "description": "Vil du konfigurere {name} ({host})?", "title": "" @@ -36,7 +35,8 @@ "password": "Passord", "port": "Port", "ssl": "Bruker et SSL-sertifikat", - "username": "Brukernavn" + "username": "Brukernavn", + "verify_ssl": "Verifisere SSL-sertifikat" }, "title": "" } diff --git a/homeassistant/components/synology_dsm/translations/pl.json b/homeassistant/components/synology_dsm/translations/pl.json index c827c09c369..b5929c307de 100644 --- a/homeassistant/components/synology_dsm/translations/pl.json +++ b/homeassistant/components/synology_dsm/translations/pl.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection": "B\u0142\u0105d po\u0142\u0105czenia: sprawd\u017a host, port i SSL", "invalid_auth": "Niepoprawne uwierzytelnienie", - "login": "B\u0142\u0105d logowania: sprawd\u017a nazw\u0119 u\u017cytkownika i has\u0142o", "missing_data": "Brakuj\u0105ce dane: spr\u00f3buj ponownie p\u00f3\u017aniej lub skorzystaj z innej konfiguracji", "otp_failed": "Uwierzytelnianie dwuetapowe nie powiod\u0142o si\u0119, spr\u00f3buj ponownie z nowym kodem dost\u0119pu", "unknown": "Nieoczekiwany b\u0142\u0105d" @@ -25,7 +23,8 @@ "password": "Has\u0142o", "port": "Port", "ssl": "Certyfikat SSL", - "username": "Nazwa u\u017cytkownika" + "username": "Nazwa u\u017cytkownika", + "verify_ssl": "Weryfikacja certyfikatu SSL" }, "description": "Czy chcesz skonfigurowa\u0107 {name} ({host})?", "title": "Synology DSM" @@ -36,7 +35,8 @@ "password": "Has\u0142o", "port": "Port", "ssl": "Certyfikat SSL", - "username": "Nazwa u\u017cytkownika" + "username": "Nazwa u\u017cytkownika", + "verify_ssl": "Weryfikacja certyfikatu SSL" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/pt.json b/homeassistant/components/synology_dsm/translations/pt.json index c164be4b61d..4264b1e4a08 100644 --- a/homeassistant/components/synology_dsm/translations/pt.json +++ b/homeassistant/components/synology_dsm/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "login": "Erro de autentica\u00e7\u00e3o: verifique seu nome de utilizador e palavra-passe" - }, "step": { "2sa": { "data": { diff --git a/homeassistant/components/synology_dsm/translations/ru.json b/homeassistant/components/synology_dsm/translations/ru.json index 61079c31af3..ed3c2eea0a8 100644 --- a/homeassistant/components/synology_dsm/translations/ru.json +++ b/homeassistant/components/synology_dsm/translations/ru.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0445\u043e\u0441\u0442, \u043f\u043e\u0440\u0442 \u0438 SSL.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", - "login": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u0445\u043e\u0434\u0430: \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c.", "missing_data": "\u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435: \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", "otp_failed": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0434\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u0441 \u043d\u043e\u0432\u044b\u043c \u043f\u0430\u0440\u043e\u043b\u0435\u043c.", "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." @@ -25,7 +23,8 @@ "password": "\u041f\u0430\u0440\u043e\u043b\u044c", "port": "\u041f\u043e\u0440\u0442", "ssl": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 SSL", - "username": "\u041b\u043e\u0433\u0438\u043d" + "username": "\u041b\u043e\u0433\u0438\u043d", + "verify_ssl": "\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 SSL" }, "description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c {name} ({host})?", "title": "Synology DSM" @@ -36,7 +35,8 @@ "password": "\u041f\u0430\u0440\u043e\u043b\u044c", "port": "\u041f\u043e\u0440\u0442", "ssl": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 SSL", - "username": "\u041b\u043e\u0433\u0438\u043d" + "username": "\u041b\u043e\u0433\u0438\u043d", + "verify_ssl": "\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 SSL" }, "title": "Synology DSM" } diff --git a/homeassistant/components/synology_dsm/translations/sl.json b/homeassistant/components/synology_dsm/translations/sl.json index 8f58af96960..164abf7e2cc 100644 --- a/homeassistant/components/synology_dsm/translations/sl.json +++ b/homeassistant/components/synology_dsm/translations/sl.json @@ -4,8 +4,6 @@ "already_configured": "Gostitelj je \u017ee konfiguriran" }, "error": { - "connection": "Napaka pri povezavi: preverite gostitelja, vrata in ssl", - "login": "Napaka pri prijavi: preverite svoje uporabni\u0161ko ime in geslo", "missing_data": "Manjkajo\u010di podatki: poskusite pozneje ali v drugi konfiguraciji", "otp_failed": "Dvostopenjska avtentikacija ni uspela. Poskusite z novim geslom", "unknown": "Neznana napaka: za ve\u010d podrobnosti preverite dnevnike" diff --git a/homeassistant/components/synology_dsm/translations/sv.json b/homeassistant/components/synology_dsm/translations/sv.json index 690e622ecd2..3a0f66f1245 100644 --- a/homeassistant/components/synology_dsm/translations/sv.json +++ b/homeassistant/components/synology_dsm/translations/sv.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "V\u00e4rden \u00e4r redan konfigurerad." }, - "error": { - "connection": "Anslutningsfel: v\u00e4nligen kontrollera v\u00e4rd, port & SSL" - }, "step": { "link": { "data": { diff --git a/homeassistant/components/synology_dsm/translations/tr.json b/homeassistant/components/synology_dsm/translations/tr.json new file mode 100644 index 00000000000..a7598bb3438 --- /dev/null +++ b/homeassistant/components/synology_dsm/translations/tr.json @@ -0,0 +1,16 @@ +{ + "config": { + "step": { + "link": { + "data": { + "verify_ssl": "SSL sertifikalar\u0131n\u0131 do\u011frula" + } + }, + "user": { + "data": { + "verify_ssl": "SSL sertifikalar\u0131n\u0131 do\u011frula" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/synology_dsm/translations/zh-Hans.json b/homeassistant/components/synology_dsm/translations/zh-Hans.json index 94a619f570d..b4edf8039a6 100644 --- a/homeassistant/components/synology_dsm/translations/zh-Hans.json +++ b/homeassistant/components/synology_dsm/translations/zh-Hans.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "\u8fde\u63a5\u5931\u8d25", - "connection": "\u8fde\u63a5\u9519\u8bef\uff1a\u8bf7\u68c0\u67e5\u4e3b\u673a\u3001\u7aef\u53e3\u548c SSL", "invalid_auth": "\u8eab\u4efd\u8ba4\u8bc1\u65e0\u6548", - "login": "\u767b\u5f55\u9519\u8bef\uff1a\u8bf7\u68c0\u67e5\u7528\u6237\u540d\u548c\u5bc6\u7801", "missing_data": "\u7f3a\u5c11\u6570\u636e\uff1a\u8bf7\u7a0d\u540e\u91cd\u8bd5\u6216\u5c1d\u8bd5\u5176\u4ed6\u914d\u7f6e", "otp_failed": "\u4e24\u6b65\u9a8c\u8bc1\u5931\u8d25\uff0c\u8bf7\u4f7f\u7528\u65b0\u7684\u9a8c\u8bc1\u7801\u91cd\u8bd5", "unknown": "\u975e\u9884\u671f\u7684\u9519\u8bef" diff --git a/homeassistant/components/synology_dsm/translations/zh-Hant.json b/homeassistant/components/synology_dsm/translations/zh-Hant.json index c0460d74cf6..4f50be27955 100644 --- a/homeassistant/components/synology_dsm/translations/zh-Hant.json +++ b/homeassistant/components/synology_dsm/translations/zh-Hant.json @@ -5,9 +5,7 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection": "\u9023\u7dda\u932f\u8aa4\uff1a\u8acb\u6aa2\u67e5\u4e3b\u6a5f\u7aef\u3001\u901a\u8a0a\u57e0\u8207 SSL", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "login": "\u767b\u5165\u932f\u8aa4\uff1a\u8acb\u78ba\u8a8d\u96fb\u5b50\u90f5\u4ef6\u8207\u5bc6\u78bc", "missing_data": "\u7f3a\u5c11\u8cc7\u6599\uff1a\u8acb\u7a0d\u5f8c\u91cd\u8a66\u6216\u4f7f\u7528\u5176\u4ed6\u8a2d\u5b9a", "otp_failed": "\u5169\u6b65\u9a5f\u9a57\u8b49\u5931\u6557\uff0c\u8acb\u91cd\u65b0\u53d6\u5f97\u4ee3\u78bc\u5f8c\u91cd\u8a66", "unknown": "\u672a\u9810\u671f\u932f\u8aa4" @@ -25,7 +23,8 @@ "password": "\u5bc6\u78bc", "port": "\u901a\u8a0a\u57e0", "ssl": "\u4f7f\u7528 SSL \u8a8d\u8b49", - "username": "\u4f7f\u7528\u8005\u540d\u7a31" + "username": "\u4f7f\u7528\u8005\u540d\u7a31", + "verify_ssl": "\u78ba\u8a8d SSL \u8a8d\u8b49" }, "description": "\u662f\u5426\u8981\u8a2d\u5b9a {name} ({host})\uff1f", "title": "\u7fa4\u6689 DSM" @@ -36,7 +35,8 @@ "password": "\u5bc6\u78bc", "port": "\u901a\u8a0a\u57e0", "ssl": "\u4f7f\u7528 SSL \u8a8d\u8b49", - "username": "\u4f7f\u7528\u8005\u540d\u7a31" + "username": "\u4f7f\u7528\u8005\u540d\u7a31", + "verify_ssl": "\u78ba\u8a8d SSL \u8a8d\u8b49" }, "title": "\u7fa4\u6689 DSM" } diff --git a/homeassistant/components/system_health/__init__.py b/homeassistant/components/system_health/__init__.py index 778ddf601dc..c53cd9da1a5 100644 --- a/homeassistant/components/system_health/__init__.py +++ b/homeassistant/components/system_health/__init__.py @@ -1,15 +1,18 @@ """Support for System health .""" import asyncio -from collections import OrderedDict +import dataclasses +from datetime import datetime import logging -from typing import Callable, Dict +from typing import Awaitable, Callable, Dict, Optional +import aiohttp import async_timeout import voluptuous as vol from homeassistant.components import websocket_api -from homeassistant.core import callback -from homeassistant.helpers.typing import ConfigType, HomeAssistantType +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import aiohttp_client, integration_platform +from homeassistant.helpers.typing import ConfigType from homeassistant.loader import bind_hass _LOGGER = logging.getLogger(__name__) @@ -22,53 +25,194 @@ INFO_CALLBACK_TIMEOUT = 5 @bind_hass @callback def async_register_info( - hass: HomeAssistantType, + hass: HomeAssistant, domain: str, - info_callback: Callable[[HomeAssistantType], Dict], + info_callback: Callable[[HomeAssistant], Dict], ): - """Register an info callback.""" - data = hass.data.setdefault(DOMAIN, OrderedDict()).setdefault("info", OrderedDict()) - data[domain] = info_callback + """Register an info callback. + + Deprecated. + """ + _LOGGER.warning( + "system_health.async_register_info is deprecated. Add a system_health platform instead." + ) + hass.data.setdefault(DOMAIN, {}) + SystemHealthRegistration(hass, domain).async_register_info(info_callback) -async def async_setup(hass: HomeAssistantType, config: ConfigType): +async def async_setup(hass: HomeAssistant, config: ConfigType): """Set up the System Health component.""" hass.components.websocket_api.async_register_command(handle_info) + hass.data.setdefault(DOMAIN, {}) + + await integration_platform.async_process_integration_platforms( + hass, DOMAIN, _register_system_health_platform + ) + return True -async def _info_wrapper(hass, info_callback): - """Wrap info callback.""" +async def _register_system_health_platform(hass, integration_domain, platform): + """Register a system health platform.""" + platform.async_register(hass, SystemHealthRegistration(hass, integration_domain)) + + +async def get_integration_info( + hass: HomeAssistant, registration: "SystemHealthRegistration" +): + """Get integration system health.""" try: with async_timeout.timeout(INFO_CALLBACK_TIMEOUT): - return await info_callback(hass) + data = await registration.info_callback(hass) except asyncio.TimeoutError: - return {"error": "Fetching info timed out"} - except Exception as err: # pylint: disable=broad-except + data = {"error": {"type": "failed", "error": "timeout"}} + except Exception: # pylint: disable=broad-except _LOGGER.exception("Error fetching info") - return {"error": str(err)} + data = {"error": {"type": "failed", "error": "unknown"}} + + result = {"info": data} + + if registration.manage_url: + result["manage_url"] = registration.manage_url + + return result + + +@callback +def _format_value(val): + """Format a system health value.""" + if isinstance(val, datetime): + return {"value": val.isoformat(), "type": "date"} + return val @websocket_api.async_response @websocket_api.websocket_command({vol.Required("type"): "system_health/info"}) async def handle_info( - hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg: Dict + hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: Dict ): - """Handle an info request.""" - info_callbacks = hass.data.get(DOMAIN, {}).get("info", {}) - data = OrderedDict() - data["homeassistant"] = await hass.helpers.system_info.async_get_system_info() + """Handle an info request via a subscription.""" + registrations: Dict[str, SystemHealthRegistration] = hass.data[DOMAIN] + data = {} + pending_info = {} - if info_callbacks: - for domain, domain_data in zip( - info_callbacks, - await asyncio.gather( - *( - _info_wrapper(hass, info_callback) - for info_callback in info_callbacks.values() + for domain, domain_data in zip( + registrations, + await asyncio.gather( + *( + get_integration_info(hass, registration) + for registration in registrations.values() + ) + ), + ): + for key, value in domain_data["info"].items(): + if asyncio.iscoroutine(value): + value = asyncio.create_task(value) + if isinstance(value, asyncio.Task): + pending_info[(domain, key)] = value + domain_data["info"][key] = {"type": "pending"} + else: + domain_data["info"][key] = _format_value(value) + + data[domain] = domain_data + + # Confirm subscription + connection.send_result(msg["id"]) + + stop_event = asyncio.Event() + connection.subscriptions[msg["id"]] = stop_event.set + + # Send initial data + connection.send_message( + websocket_api.messages.event_message( + msg["id"], {"type": "initial", "data": data} + ) + ) + + # If nothing pending, wrap it up. + if not pending_info: + connection.send_message( + websocket_api.messages.event_message(msg["id"], {"type": "finish"}) + ) + return + + tasks = [asyncio.create_task(stop_event.wait()), *pending_info.values()] + pending_lookup = {val: key for key, val in pending_info.items()} + + # One task is the stop_event.wait() and is always there + while len(tasks) > 1 and not stop_event.is_set(): + # Wait for first completed task + done, tasks = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + + if stop_event.is_set(): + for task in tasks: + task.cancel() + return + + # Update subscription of all finished tasks + for result in done: + domain, key = pending_lookup[result] + event_msg = { + "type": "update", + "domain": domain, + "key": key, + } + + if result.exception(): + exception = result.exception() + _LOGGER.error( + "Error fetching system info for %s - %s", + domain, + key, + exc_info=(type(exception), exception, exception.__traceback__), ) - ), - ): - data[domain] = domain_data + event_msg["success"] = False + event_msg["error"] = {"type": "failed", "error": "unknown"} + else: + event_msg["success"] = True + event_msg["data"] = _format_value(result.result()) - connection.send_message(websocket_api.result_message(msg["id"], data)) + connection.send_message( + websocket_api.messages.event_message(msg["id"], event_msg) + ) + + connection.send_message( + websocket_api.messages.event_message(msg["id"], {"type": "finish"}) + ) + + +@dataclasses.dataclass() +class SystemHealthRegistration: + """Helper class to track platform registration.""" + + hass: HomeAssistant + domain: str + info_callback: Optional[Callable[[HomeAssistant], Awaitable[Dict]]] = None + manage_url: Optional[str] = None + + @callback + def async_register_info( + self, + info_callback: Callable[[HomeAssistant], Awaitable[Dict]], + manage_url: Optional[str] = None, + ): + """Register an info callback.""" + self.info_callback = info_callback + self.manage_url = manage_url + self.hass.data[DOMAIN][self.domain] = self + + +async def async_check_can_reach_url( + hass: HomeAssistant, url: str, more_info: Optional[str] = None +) -> str: + """Test if the url can be reached.""" + session = aiohttp_client.async_get_clientsession(hass) + + try: + await session.get(url, timeout=5) + return "ok" + except aiohttp.ClientError: + data = {"type": "failed", "error": "unreachable"} + if more_info is not None: + data["more_info"] = more_info + return data diff --git a/homeassistant/components/tado/translations/cs.json b/homeassistant/components/tado/translations/cs.json index 8ddc5522b55..0df3ac83456 100644 --- a/homeassistant/components/tado/translations/cs.json +++ b/homeassistant/components/tado/translations/cs.json @@ -6,6 +6,7 @@ "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", + "no_homes": "S t\u00edmto \u00fa\u010dtem tado nejsou propojeny \u017e\u00e1dn\u00e9 domovy.", "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "step": { diff --git a/homeassistant/components/tado/translations/et.json b/homeassistant/components/tado/translations/et.json index a317cab785f..6a201b4fd2d 100644 --- a/homeassistant/components/tado/translations/et.json +++ b/homeassistant/components/tado/translations/et.json @@ -6,13 +6,27 @@ "error": { "cannot_connect": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamine nurjus", + "no_homes": "Selle Tado kontoga pole \u00fchtegi kodu seotud.", "unknown": "Ootamatu t\u00f5rge" }, "step": { "user": { "data": { - "password": "Salas\u00f5na" - } + "password": "Salas\u00f5na", + "username": "Kasutajanimi" + }, + "title": "Tado kontoga \u00fchenduse loomine" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "fallback": "Luba varure\u017eiim." + }, + "description": "P\u00e4rast tsooni k\u00e4sitsi reguleerimist l\u00fclitub varure\u017eiim j\u00e4rgmisel ajakava l\u00fclitil nutikasse ajakavasse.", + "title": "Kohanda Tado suvandeid." } } } diff --git a/homeassistant/components/tado/translations/lb.json b/homeassistant/components/tado/translations/lb.json index 91a81f03177..d9786f36393 100644 --- a/homeassistant/components/tado/translations/lb.json +++ b/homeassistant/components/tado/translations/lb.json @@ -4,7 +4,7 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen, prob\u00e9ier w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "no_homes": "Keng Immobilien mat d\u00ebsem Tado Kont verbonnen.", "unknown": "Onerwaarte Feeler" diff --git a/homeassistant/components/tasmota/__init__.py b/homeassistant/components/tasmota/__init__.py index a82d95474cc..c0ebae7695e 100644 --- a/homeassistant/components/tasmota/__init__.py +++ b/homeassistant/components/tasmota/__init__.py @@ -11,23 +11,32 @@ from hatasmota.const import ( ) 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 @@ async def async_setup_entry(hass, entry): """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 7cddeb7a603..0f4dfde1646 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 e921a186fea..aab0064bb96 100644 --- a/homeassistant/components/tasmota/device_automation.py +++ b/homeassistant/components/tasmota/device_automation.py @@ -6,10 +6,15 @@ from homeassistant.helpers.device_registry import EVENT_DEVICE_REGISTRY_UPDATED 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_setup_entry(hass, config_entry): """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_setup_entry(hass, config_entry): 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 9db7ca492af..e7dad0885a0 100644 --- a/homeassistant/components/tasmota/device_trigger.py +++ b/homeassistant/components/tasmota/device_trigger.py @@ -224,8 +224,8 @@ async def async_setup_trigger(hass, tasmota_trigger, config_entry, discovery_has 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/homeassistant/components/tasmota/manifest.json b/homeassistant/components/tasmota/manifest.json index a0414b6450b..c270be6e633 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.1"], + "requirements": ["hatasmota==0.0.31"], "dependencies": ["mqtt"], "mqtt": ["tasmota/discovery/#"], "codeowners": ["@emontnemery"] diff --git a/homeassistant/components/tasmota/mixins.py b/homeassistant/components/tasmota/mixins.py index 5a1c7a9f3de..a860b06c574 100644 --- a/homeassistant/components/tasmota/mixins.py +++ b/homeassistant/components/tasmota/mixins.py @@ -95,8 +95,7 @@ class TasmotaAvailability(TasmotaEntity): @callback def availability_updated(self, available: bool) -> None: """Handle updated availability.""" - if available and not self._available: - self._tasmota_entity.poll_status() + self._tasmota_entity.poll_status() self._available = available self.async_write_ha_state() diff --git a/homeassistant/components/tasmota/sensor.py b/homeassistant/components/tasmota/sensor.py index bdaac51f09c..966bf8648d4 100644 --- a/homeassistant/components/tasmota/sensor.py +++ b/homeassistant/components/tasmota/sensor.py @@ -3,6 +3,19 @@ from typing import Optional from hatasmota import status_sensor from hatasmota.const import ( + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER as TASMOTA_CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_BILLION as TASMOTA_CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_PARTS_PER_MILLION as TASMOTA_CONCENTRATION_PARTS_PER_MILLION, + ELECTRICAL_CURRENT_AMPERE as TASMOTA_ELECTRICAL_CURRENT_AMPERE, + ELECTRICAL_VOLT_AMPERE as TASMOTA_ELECTRICAL_VOLT_AMPERE, + ENERGY_KILO_WATT_HOUR as TASMOTA_ENERGY_KILO_WATT_HOUR, + FREQUENCY_HERTZ as TASMOTA_FREQUENCY_HERTZ, + LENGTH_CENTIMETERS as TASMOTA_LENGTH_CENTIMETERS, + LIGHT_LUX as TASMOTA_LIGHT_LUX, + MASS_KILOGRAMS as TASMOTA_MASS_KILOGRAMS, + PERCENTAGE as TASMOTA_PERCENTAGE, + POWER_WATT as TASMOTA_POWER_WATT, + PRESSURE_HPA as TASMOTA_PRESSURE_HPA, SENSOR_AMBIENT, SENSOR_APPARENT_POWERUSAGE, SENSOR_BATTERY, @@ -34,7 +47,14 @@ from hatasmota.const import ( SENSOR_PRESSUREATSEALEVEL, SENSOR_PROXIMITY, SENSOR_REACTIVE_POWERUSAGE, + SENSOR_STATUS_IP, + SENSOR_STATUS_LAST_RESTART_TIME, + SENSOR_STATUS_LINK_COUNT, + SENSOR_STATUS_MQTT_COUNT, + SENSOR_STATUS_RESTART_REASON, + SENSOR_STATUS_RSSI, SENSOR_STATUS_SIGNAL, + SENSOR_STATUS_SSID, SENSOR_TEMPERATURE, SENSOR_TODAY, SENSOR_TOTAL, @@ -43,10 +63,21 @@ from hatasmota.const import ( SENSOR_VOLTAGE, SENSOR_WEIGHT, SENSOR_YESTERDAY, + SIGNAL_STRENGTH_DECIBELS as TASMOTA_SIGNAL_STRENGTH_DECIBELS, + SPEED_KILOMETERS_PER_HOUR as TASMOTA_SPEED_KILOMETERS_PER_HOUR, + SPEED_METERS_PER_SECOND as TASMOTA_SPEED_METERS_PER_SECOND, + SPEED_MILES_PER_HOUR as TASMOTA_SPEED_MILES_PER_HOUR, + TEMP_CELSIUS as TASMOTA_TEMP_CELSIUS, + TEMP_FAHRENHEIT as TASMOTA_TEMP_FAHRENHEIT, + TEMP_KELVIN as TASMOTA_TEMP_KELVIN, + VOLT as TASMOTA_VOLT, ) from homeassistant.components import sensor from homeassistant.const import ( + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_PARTS_PER_MILLION, DEVICE_CLASS_BATTERY, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, @@ -54,6 +85,25 @@ from homeassistant.const import ( DEVICE_CLASS_PRESSURE, DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_TIMESTAMP, + ELECTRICAL_CURRENT_AMPERE, + ELECTRICAL_VOLT_AMPERE, + ENERGY_KILO_WATT_HOUR, + FREQUENCY_HERTZ, + LENGTH_CENTIMETERS, + LIGHT_LUX, + MASS_KILOGRAMS, + PERCENTAGE, + POWER_WATT, + PRESSURE_HPA, + SIGNAL_STRENGTH_DECIBELS, + SPEED_KILOMETERS_PER_HOUR, + SPEED_METERS_PER_SECOND, + SPEED_MILES_PER_HOUR, + TEMP_CELSIUS, + TEMP_FAHRENHEIT, + TEMP_KELVIN, + VOLT, ) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -83,7 +133,10 @@ SENSOR_DEVICE_CLASS_ICON_MAP = { 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,7 +152,11 @@ SENSOR_DEVICE_CLASS_ICON_MAP = { SENSOR_PRESSUREATSEALEVEL: {DEVICE_CLASS: DEVICE_CLASS_PRESSURE}, SENSOR_PROXIMITY: {ICON: "mdi:ruler"}, SENSOR_REACTIVE_POWERUSAGE: {DEVICE_CLASS: DEVICE_CLASS_POWER}, + SENSOR_STATUS_LAST_RESTART_TIME: {DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP}, + SENSOR_STATUS_RESTART_REASON: {ICON: "mdi:information-outline"}, SENSOR_STATUS_SIGNAL: {DEVICE_CLASS: DEVICE_CLASS_SIGNAL_STRENGTH}, + SENSOR_STATUS_RSSI: {ICON: "mdi:access-point"}, + SENSOR_STATUS_SSID: {ICON: "mdi:access-point-network"}, SENSOR_TEMPERATURE: {DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE}, SENSOR_TODAY: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_TOTAL: {DEVICE_CLASS: DEVICE_CLASS_POWER}, @@ -110,6 +167,30 @@ SENSOR_DEVICE_CLASS_ICON_MAP = { SENSOR_YESTERDAY: {DEVICE_CLASS: DEVICE_CLASS_POWER}, } +SENSOR_UNIT_MAP = { + TASMOTA_CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + TASMOTA_CONCENTRATION_PARTS_PER_BILLION: CONCENTRATION_PARTS_PER_BILLION, + TASMOTA_CONCENTRATION_PARTS_PER_MILLION: CONCENTRATION_PARTS_PER_MILLION, + TASMOTA_ELECTRICAL_CURRENT_AMPERE: ELECTRICAL_CURRENT_AMPERE, + TASMOTA_ELECTRICAL_VOLT_AMPERE: ELECTRICAL_VOLT_AMPERE, + TASMOTA_ENERGY_KILO_WATT_HOUR: ENERGY_KILO_WATT_HOUR, + TASMOTA_FREQUENCY_HERTZ: FREQUENCY_HERTZ, + TASMOTA_LENGTH_CENTIMETERS: LENGTH_CENTIMETERS, + TASMOTA_LIGHT_LUX: LIGHT_LUX, + TASMOTA_MASS_KILOGRAMS: MASS_KILOGRAMS, + TASMOTA_PERCENTAGE: PERCENTAGE, + TASMOTA_POWER_WATT: POWER_WATT, + TASMOTA_PRESSURE_HPA: PRESSURE_HPA, + TASMOTA_SIGNAL_STRENGTH_DECIBELS: SIGNAL_STRENGTH_DECIBELS, + TASMOTA_SPEED_KILOMETERS_PER_HOUR: SPEED_KILOMETERS_PER_HOUR, + TASMOTA_SPEED_METERS_PER_SECOND: SPEED_METERS_PER_SECOND, + TASMOTA_SPEED_MILES_PER_HOUR: SPEED_MILES_PER_HOUR, + TASMOTA_TEMP_CELSIUS: TEMP_CELSIUS, + TASMOTA_TEMP_FAHRENHEIT: TEMP_FAHRENHEIT, + TASMOTA_TEMP_KELVIN: TEMP_KELVIN, + TASMOTA_VOLT: VOLT, +} + async def async_setup_entry(hass, config_entry, async_add_entities): """Set up Tasmota sensor dynamically through discovery.""" @@ -178,9 +259,11 @@ class TasmotaSensor(TasmotaAvailability, TasmotaDiscoveryUpdate, Entity): @property def state(self): """Return the state of the entity.""" + if self._state and self.device_class == DEVICE_CLASS_TIMESTAMP: + return self._state.isoformat() return self._state @property def unit_of_measurement(self): """Return the unit this state is expressed in.""" - return self._tasmota_entity.unit + return SENSOR_UNIT_MAP.get(self._tasmota_entity.unit, self._tasmota_entity.unit) diff --git a/homeassistant/components/tasmota/translations/fr.json b/homeassistant/components/tasmota/translations/fr.json new file mode 100644 index 00000000000..901de884bcd --- /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/tasmota/translations/lb.json b/homeassistant/components/tasmota/translations/lb.json index ee93b28f922..a7b8d6d0ce6 100644 --- a/homeassistant/components/tasmota/translations/lb.json +++ b/homeassistant/components/tasmota/translations/lb.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." + }, "error": { "invalid_discovery_topic": "Ong\u00ebltege discovery topic prefix." }, @@ -10,6 +13,9 @@ }, "description": "F\u00ebll Tasmota Konfiguratioun aus.", "title": "Tasmota" + }, + "confirm": { + "description": "Soll Tasmota konfigur\u00e9iert ginn?" } } } diff --git a/homeassistant/components/tasmota/translations/pl.json b/homeassistant/components/tasmota/translations/pl.json index 398b3c50fd4..b6bbf3fe953 100644 --- a/homeassistant/components/tasmota/translations/pl.json +++ b/homeassistant/components/tasmota/translations/pl.json @@ -15,7 +15,7 @@ "title": "Tasmota" }, "confirm": { - "description": "Czy chcesz skonfigurowa\u0107 Tasmota?" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } } diff --git a/homeassistant/components/telegram_bot/__init__.py b/homeassistant/components/telegram_bot/__init__.py index 60e33414b1e..af00c2cb6d0 100644 --- a/homeassistant/components/telegram_bot/__init__.py +++ b/homeassistant/components/telegram_bot/__init__.py @@ -67,6 +67,7 @@ ATTR_USER_ID = "user_id" 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 @@ SERVICE_LEAVE_CHAT = "leave_chat" 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 @@ BASE_SERVICE_SCHEMA = vol.Schema( 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 @@ class TelegramNotificationService: 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 @@ class TelegramNotificationService: 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 @@ class TelegramNotificationService: 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 a87bfdf3af6..8a66d2cab3a 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. diff --git a/homeassistant/components/tellduslive/sensor.py b/homeassistant/components/tellduslive/sensor.py index 3ced0217ea9..1b06fd6ed97 100644 --- a/homeassistant/components/tellduslive/sensor.py +++ b/homeassistant/components/tellduslive/sensor.py @@ -8,9 +8,9 @@ from homeassistant.const import ( LIGHT_LUX, PERCENTAGE, POWER_WATT, + PRECIPITATION_MILLIMETERS_PER_HOUR, SPEED_METERS_PER_SECOND, TEMP_CELSIUS, - TIME_HOURS, UV_INDEX, ) from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -40,7 +40,7 @@ SENSOR_TYPES = { SENSOR_TYPE_HUMIDITY: ["Humidity", PERCENTAGE, None, DEVICE_CLASS_HUMIDITY], SENSOR_TYPE_RAINRATE: [ "Rain rate", - f"{LENGTH_MILLIMETERS}/{TIME_HOURS}", + PRECIPITATION_MILLIMETERS_PER_HOUR, "mdi:water", None, ], diff --git a/homeassistant/components/tellduslive/translations/bg.json b/homeassistant/components/tellduslive/translations/bg.json index 903819c1f3e..232d51f0713 100644 --- a/homeassistant/components/tellduslive/translations/bg.json +++ b/homeassistant/components/tellduslive/translations/bg.json @@ -5,9 +5,6 @@ "authorize_url_timeout": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u0437\u0430 \u043e\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0432 \u0441\u0440\u043e\u043a.", "unknown": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0433\u0440\u0435\u0448\u043a\u0430" }, - "error": { - "auth_error": "\u0413\u0440\u0435\u0448\u043a\u0430 \u0432 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0430\u0446\u0438\u044f\u0442\u0430. \u041c\u043e\u043b\u044f, \u043e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e" - }, "step": { "auth": { "description": "\u0417\u0430 \u0434\u0430 \u0441\u0432\u044a\u0440\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u0430 \u0441\u0438 \u0432 TelldusLive: \n 1. \u041a\u043b\u0438\u043a\u043d\u0435\u0442\u0435 \u0432\u044a\u0440\u0445\u0443 \u0432\u0440\u044a\u0437\u043a\u0430\u0442\u0430 \u043f\u043e-\u0434\u043e\u043b\u0443 \n 2. \u0412\u043b\u0435\u0437\u0442\u0435 \u0432 Telldus Live \n 3. \u041e\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u0430\u0439\u0442\u0435 **{app_name}** (\u0449\u0440\u0430\u043a\u043d\u0435\u0442\u0435 \u0432\u044a\u0440\u0445\u0443 **\u0414\u0430**). \n 4. \u0412\u044a\u0440\u043d\u0435\u0442\u0435 \u0441\u0435 \u0442\u0443\u043a \u0438 \u043a\u043b\u0438\u043a\u043d\u0435\u0442\u0435 \u0432\u044a\u0440\u0445\u0443 **\u0418\u0437\u043f\u0440\u0430\u0449\u0430\u043d\u0435**. \n\n [\u0412\u0440\u044a\u0437\u043a\u0430 \u0441 TelldusLive \u043f\u0440\u043e\u0444\u0438\u043b]({auth_url})", diff --git a/homeassistant/components/tellduslive/translations/ca.json b/homeassistant/components/tellduslive/translations/ca.json index ab5707f1e71..94c78068dd1 100644 --- a/homeassistant/components/tellduslive/translations/ca.json +++ b/homeassistant/components/tellduslive/translations/ca.json @@ -7,7 +7,6 @@ "unknown": "Error inesperat" }, "error": { - "auth_error": "Error d'autenticaci\u00f3, torna-ho a provar", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { diff --git a/homeassistant/components/tellduslive/translations/cs.json b/homeassistant/components/tellduslive/translations/cs.json index efe9a588b3f..82355d34716 100644 --- a/homeassistant/components/tellduslive/translations/cs.json +++ b/homeassistant/components/tellduslive/translations/cs.json @@ -7,7 +7,6 @@ "unknown": "Neo\u010dek\u00e1van\u00e1 chyba" }, "error": { - "auth_error": "Chyba ov\u011b\u0159en\u00ed, zkuste to pros\u00edm znovu", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { diff --git a/homeassistant/components/tellduslive/translations/da.json b/homeassistant/components/tellduslive/translations/da.json index c64e51dd06a..e9a3c1fdd63 100644 --- a/homeassistant/components/tellduslive/translations/da.json +++ b/homeassistant/components/tellduslive/translations/da.json @@ -5,9 +5,6 @@ "authorize_url_timeout": "Timeout ved generering af autoriseret url.", "unknown": "Ukendt fejl opstod" }, - "error": { - "auth_error": "Godkendelsesfejl, pr\u00f8v venligst igen" - }, "step": { "auth": { "description": "For at forbinde din TelldusLive-konto:\n 1. Klik p\u00e5 linket herunder\n 2. Log p\u00e5 Telldus Live\n 3. Tillad **{app_name}** (klik **Ja**). \n 4. Vend tilbage hertil og klik **SUBMIT**.\n\n [Forbind TelldusLive konto]({auth_url})", diff --git a/homeassistant/components/tellduslive/translations/de.json b/homeassistant/components/tellduslive/translations/de.json index 429ca47fbdf..768f114ac4f 100644 --- a/homeassistant/components/tellduslive/translations/de.json +++ b/homeassistant/components/tellduslive/translations/de.json @@ -1,13 +1,11 @@ { "config": { "abort": { + "already_configured": "Dienst ist bereits konfiguriert", "authorize_url_fail": "Unbekannter Fehler beim Erstellen der Authorisierungs-URL", "authorize_url_timeout": "Zeit\u00fcberschreitung beim Erstellen der Authorisierungs-URL.", "unknown": "Unbekannter Fehler ist aufgetreten" }, - "error": { - "auth_error": "Authentifizierungsfehler, bitte versuche es erneut" - }, "step": { "auth": { "description": "So verkn\u00fcpfest du dein TelldusLive-Konto: \n 1. Klicke auf den Link unten \n 2. Melde dich bei Telldus Live an \n 3. Autorisiere ** {app_name} ** (klicke auf ** Yes **). \n 4. Komme hierher zur\u00fcck und klicke auf ** SUBMIT **. \n\n [Link TelldusLive-Konto]({auth_url})", diff --git a/homeassistant/components/tellduslive/translations/en.json b/homeassistant/components/tellduslive/translations/en.json index 4eab9dc1e42..80e6cde7acd 100644 --- a/homeassistant/components/tellduslive/translations/en.json +++ b/homeassistant/components/tellduslive/translations/en.json @@ -7,7 +7,6 @@ "unknown": "Unexpected error" }, "error": { - "auth_error": "Authentication error, please try again", "invalid_auth": "Invalid authentication" }, "step": { diff --git a/homeassistant/components/tellduslive/translations/es-419.json b/homeassistant/components/tellduslive/translations/es-419.json index 0deeb26eea6..064bd4edd33 100644 --- a/homeassistant/components/tellduslive/translations/es-419.json +++ b/homeassistant/components/tellduslive/translations/es-419.json @@ -5,9 +5,6 @@ "authorize_url_timeout": "Tiempo de espera agotado para generar la URL de autorizaci\u00f3n.", "unknown": "Se produjo un error desconocido" }, - "error": { - "auth_error": "Error de autenticaci\u00f3n, por favor intente de nuevo" - }, "step": { "auth": { "description": "Para vincular su cuenta de TelldusLive: \n 1. Haga clic en el siguiente enlace \n 2. Inicia sesi\u00f3n en Telldus Live \n 3. Autorice ** {app_name} ** (haga clic en ** S\u00ed **). \n 4. Vuelve aqu\u00ed y haz clic en ** ENVIAR **. \n\n [Enlace a la cuenta de TelldusLive] ( {auth_url} )", diff --git a/homeassistant/components/tellduslive/translations/es.json b/homeassistant/components/tellduslive/translations/es.json index 0cb63f197fd..2e6f1a64419 100644 --- a/homeassistant/components/tellduslive/translations/es.json +++ b/homeassistant/components/tellduslive/translations/es.json @@ -7,7 +7,6 @@ "unknown": "Se produjo un error desconocido" }, "error": { - "auth_error": "Error de autenticaci\u00f3n, por favor int\u00e9ntalo de nuevo", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { diff --git a/homeassistant/components/tellduslive/translations/et.json b/homeassistant/components/tellduslive/translations/et.json index 37afc808337..b9008e7bc79 100644 --- a/homeassistant/components/tellduslive/translations/et.json +++ b/homeassistant/components/tellduslive/translations/et.json @@ -3,16 +3,23 @@ "abort": { "already_configured": "Teenus on juba seadistatud", "authorize_url_fail": "Tundmatu viga tuvastamise URL-i loomisel.", + "authorize_url_timeout": "Kinnitus-URLi loomise ajal\u00f5pp.", "unknown": "Tundmatu viga" }, "error": { "invalid_auth": "Tuvastamise viga" }, "step": { + "auth": { + "description": "TelldusLive'i konto linkimiseks toimi j\u00e4rgmiselt:\n 1. Kl\u00f5psa allolevat linki\n 2. Logi sisse Telldus Live'i\n 3. Autendi {app_name} ** {app_name} ** (kl\u00f5psa ** Jah **).\n 4. Tule siia tagasi ja kl\u00f5psa ** ESITA **.\n\n [Link TelldusLive account] ( {auth_url} )", + "title": "Autendi TelldusLive'i kaudu" + }, "user": { "data": { "host": "" - } + }, + "description": "", + "title": "Vali l\u00f5pppunkt." } } } diff --git a/homeassistant/components/tellduslive/translations/fr.json b/homeassistant/components/tellduslive/translations/fr.json index a6c125fb04e..cde9d9c2c68 100644 --- a/homeassistant/components/tellduslive/translations/fr.json +++ b/homeassistant/components/tellduslive/translations/fr.json @@ -7,7 +7,7 @@ "unknown": "Une erreur inconnue s'est produite" }, "error": { - "auth_error": "Erreur d'authentification, veuillez r\u00e9essayer." + "invalid_auth": "Authentification invalide" }, "step": { "auth": { diff --git a/homeassistant/components/tellduslive/translations/hu.json b/homeassistant/components/tellduslive/translations/hu.json index c285fd8213d..748189e6427 100644 --- a/homeassistant/components/tellduslive/translations/hu.json +++ b/homeassistant/components/tellduslive/translations/hu.json @@ -5,9 +5,6 @@ "authorize_url_timeout": "Id\u0151t\u00fall\u00e9p\u00e9s az \u00e9rv\u00e9nyes\u00edt\u00e9si url gener\u00e1l\u00e1sa sor\u00e1n.", "unknown": "Ismeretlen hiba t\u00f6rt\u00e9nt" }, - "error": { - "auth_error": "Hiteles\u00edt\u00e9si hiba, pr\u00f3b\u00e1lkozz \u00fajra" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tellduslive/translations/it.json b/homeassistant/components/tellduslive/translations/it.json index 7b7a5ab3ce4..d16b69d577b 100644 --- a/homeassistant/components/tellduslive/translations/it.json +++ b/homeassistant/components/tellduslive/translations/it.json @@ -7,7 +7,6 @@ "unknown": "Errore imprevisto" }, "error": { - "auth_error": "Errore di autenticazione, riprovare", "invalid_auth": "Autenticazione non valida" }, "step": { diff --git a/homeassistant/components/tellduslive/translations/ko.json b/homeassistant/components/tellduslive/translations/ko.json index ef1b20086c5..645b7233bd7 100644 --- a/homeassistant/components/tellduslive/translations/ko.json +++ b/homeassistant/components/tellduslive/translations/ko.json @@ -6,9 +6,6 @@ "authorize_url_timeout": "\uc778\uc99d url \uc0dd\uc131 \uc2dc\uac04\uc774 \ucd08\uacfc\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "unknown": "\uc54c \uc218\uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" }, - "error": { - "auth_error": "\uc778\uc99d\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694." - }, "step": { "auth": { "description": "TelldusLive \uacc4\uc815\uc744 \uc5f0\uacb0\ud558\ub824\uba74:\n 1. \ud558\ub2e8\uc758 \ub9c1\ud06c\ub97c \ud074\ub9ad\ud574\uc8fc\uc138\uc694\n 2. Telldus Live \uc5d0 \ub85c\uadf8\uc778 \ud558\uc138\uc694\n 3. Authorize **{app_name}** (**Yes** \ub97c \ud074\ub9ad\ud558\uc138\uc694).\n 4. \ub2e4\uc2dc \uc5ec\uae30\ub85c \ub3cc\uc544\uc640\uc11c **\ud655\uc778**\uc744 \ud074\ub9ad\ud558\uc138\uc694.\n\n [TelldusLive \uacc4\uc815 \uc5f0\uacb0\ud558\uae30]({auth_url})", diff --git a/homeassistant/components/tellduslive/translations/lb.json b/homeassistant/components/tellduslive/translations/lb.json index ba200074ac5..5e733c2294d 100644 --- a/homeassistant/components/tellduslive/translations/lb.json +++ b/homeassistant/components/tellduslive/translations/lb.json @@ -1,13 +1,13 @@ { "config": { "abort": { - "already_configured": "TelldusLive ass scho konfigur\u00e9iert", + "already_configured": "Service ass scho konfigur\u00e9iert", "authorize_url_fail": "Onbekannte Feeler beim gener\u00e9ieren vun der Autorisatiouns URL.", "authorize_url_timeout": "Z\u00e4it Iwwerschreidung beim gener\u00e9ieren vun der Autorisatiouns URL.", - "unknown": "Onbekannten Feeler opgetrueden" + "unknown": "Onerwaarte Feeler" }, "error": { - "auth_error": "Feeler bei der Authentifikatioun, prob\u00e9iert w.e.g. nach emol" + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "auth": { diff --git a/homeassistant/components/tellduslive/translations/nl.json b/homeassistant/components/tellduslive/translations/nl.json index 1ef78ae1fd3..b3874dac77e 100644 --- a/homeassistant/components/tellduslive/translations/nl.json +++ b/homeassistant/components/tellduslive/translations/nl.json @@ -1,13 +1,11 @@ { "config": { "abort": { + "already_configured": "Service is al geconfigureerd", "authorize_url_fail": "Onbekende fout bij het genereren van een autorisatie url.", "authorize_url_timeout": "Time-out tijdens genereren autorisatie url.", "unknown": "Onbekende fout opgetreden" }, - "error": { - "auth_error": "Authenticatiefout, probeer het opnieuw." - }, "step": { "auth": { "description": "Om uw TelldusLive-account te linken: \n 1. Klik op de onderstaande link \n 2. Log in op Telldus Live \n 3. Autoriseer ** {app_name} ** (klik op ** Ja **). \n 4. Kom hier terug en klik op ** VERSTUREN **. \n\n [Link TelldusLive account]({auth_url})", diff --git a/homeassistant/components/tellduslive/translations/no.json b/homeassistant/components/tellduslive/translations/no.json index 29593f5ccc2..13ad5419215 100644 --- a/homeassistant/components/tellduslive/translations/no.json +++ b/homeassistant/components/tellduslive/translations/no.json @@ -7,7 +7,6 @@ "unknown": "Uventet feil" }, "error": { - "auth_error": "Godkjenningsfeil, vennligst pr\u00f8v igjen", "invalid_auth": "Ugyldig godkjenning" }, "step": { diff --git a/homeassistant/components/tellduslive/translations/pl.json b/homeassistant/components/tellduslive/translations/pl.json index 1fec2ac3350..3571ad8e426 100644 --- a/homeassistant/components/tellduslive/translations/pl.json +++ b/homeassistant/components/tellduslive/translations/pl.json @@ -7,13 +7,12 @@ "unknown": "Nieoczekiwany b\u0142\u0105d" }, "error": { - "auth_error": "B\u0142\u0105d uwierzytelniania, spr\u00f3buj ponownie", "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { "auth": { "description": "Aby po\u0142\u0105czy\u0107 konto TelldusLive: \n 1. Kliknij poni\u017cszy link \n 2. Zaloguj si\u0119 do Telldus Live \n 3. Autoryzuj **{app_name}** (kliknij **Tak**). \n 4. Wr\u00f3\u0107 tutaj i kliknij **SUBMIT**. \n\n [Link do konta TelldusLive]({auth_url})", - "title": "Uwierzytelnienie na TelldusLive" + "title": "Uwierzytelnienie na TelldusLive" }, "user": { "data": { diff --git a/homeassistant/components/tellduslive/translations/pt-BR.json b/homeassistant/components/tellduslive/translations/pt-BR.json index a63d94eb25b..44572d61884 100644 --- a/homeassistant/components/tellduslive/translations/pt-BR.json +++ b/homeassistant/components/tellduslive/translations/pt-BR.json @@ -5,9 +5,6 @@ "authorize_url_timeout": "Tempo limite de gera\u00e7\u00e3o de url de autoriza\u00e7\u00e3o.", "unknown": "Ocorreu um erro desconhecido" }, - "error": { - "auth_error": "Erro de autentica\u00e7\u00e3o, por favor, tente novamente" - }, "step": { "auth": { "description": "Para vincular sua conta do TelldusLive: \n 1. Clique no link abaixo \n 2. Fa\u00e7a o login no Telldus Live \n 3. Autorize **{app_name}** (clique em **Sim**). \n 4. Volte aqui e clique em **ENVIAR**. \n\n [Vincular conta TelldusLive]({auth_url})", diff --git a/homeassistant/components/tellduslive/translations/pt.json b/homeassistant/components/tellduslive/translations/pt.json index ac374ba7b2c..6030c972448 100644 --- a/homeassistant/components/tellduslive/translations/pt.json +++ b/homeassistant/components/tellduslive/translations/pt.json @@ -5,9 +5,6 @@ "authorize_url_timeout": "Limite temporal ultrapassado ao gerar um URL de autoriza\u00e7\u00e3o.", "unknown": "Ocorreu um erro desconhecido" }, - "error": { - "auth_error": "Erro de autentica\u00e7\u00e3o, por favor tente novamente" - }, "step": { "auth": { "description": "Para ligar \u00e0 sua conta do TelldusLive: \n 1. Clique no link abaixo \n 2. Fa\u00e7a o login no Telldus Live \n 3. Autorize **{app_name}** (clique em **Sim**). \n 4. Volte aqui e clique em **ENVIAR**. \n\n [Ligar \u00e0 TelldusLive] ( {auth_url} )", diff --git a/homeassistant/components/tellduslive/translations/ru.json b/homeassistant/components/tellduslive/translations/ru.json index 1113ca73887..0aee4bbd488 100644 --- a/homeassistant/components/tellduslive/translations/ru.json +++ b/homeassistant/components/tellduslive/translations/ru.json @@ -7,7 +7,6 @@ "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." }, "error": { - "auth_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { diff --git a/homeassistant/components/tellduslive/translations/sl.json b/homeassistant/components/tellduslive/translations/sl.json index a0634b3c6e5..9feea6d6288 100644 --- a/homeassistant/components/tellduslive/translations/sl.json +++ b/homeassistant/components/tellduslive/translations/sl.json @@ -5,9 +5,6 @@ "authorize_url_timeout": "\u010casovna omejitev za generiranje URL-ja je potekla.", "unknown": "Pri\u0161lo je do neznane napake" }, - "error": { - "auth_error": "Napaka pri preverjanju pristnosti, poskusite znova" - }, "step": { "auth": { "description": "\u010ce \u017eelite povezati svoj ra\u010dun TelldusLive: \n 1. Kliknite spodnjo povezavo \n 2. Prijavite se v Telldus Live \n 3. Dovolite ** {app_name} ** (kliknite ** Da **). \n 4. Pridi nazaj in kliknite ** SUBMIT **. \n\n [Link TelldusLive ra\u010dun] ( {auth_url} )", diff --git a/homeassistant/components/tellduslive/translations/sv.json b/homeassistant/components/tellduslive/translations/sv.json index 96e1258faa5..48c61bb2b7d 100644 --- a/homeassistant/components/tellduslive/translations/sv.json +++ b/homeassistant/components/tellduslive/translations/sv.json @@ -5,9 +5,6 @@ "authorize_url_timeout": "Timeout n\u00e4r genererar auktorisera url.", "unknown": "Ok\u00e4nt fel intr\u00e4ffade" }, - "error": { - "auth_error": "Autentiseringsfel, v\u00e4nligen f\u00f6rs\u00f6k igen" - }, "step": { "auth": { "description": "F\u00f6r att l\u00e4nka ditt \"Telldus Live!\" konto: \n 1. Klicka p\u00e5 l\u00e4nken nedan \n 2. Logga in p\u00e5 Telldus Live!\n 3. Godk\u00e4nn **{app_name}** (klicka **Yes**). \n 4. Kom tillbaka hit och klicka p\u00e5 **SUBMIT**. \n\n [L\u00e4nk till Telldus Live konto]({auth_url})", diff --git a/homeassistant/components/tellduslive/translations/zh-Hans.json b/homeassistant/components/tellduslive/translations/zh-Hans.json index c1d4a0c54f5..8dcbc144b90 100644 --- a/homeassistant/components/tellduslive/translations/zh-Hans.json +++ b/homeassistant/components/tellduslive/translations/zh-Hans.json @@ -6,7 +6,7 @@ "unknown": "\u53d1\u751f\u672a\u77e5\u7684\u9519\u8bef" }, "error": { - "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/tellduslive/translations/zh-Hant.json b/homeassistant/components/tellduslive/translations/zh-Hant.json index f392958748b..e44c2c45416 100644 --- a/homeassistant/components/tellduslive/translations/zh-Hant.json +++ b/homeassistant/components/tellduslive/translations/zh-Hant.json @@ -7,7 +7,6 @@ "unknown": "\u672a\u9810\u671f\u932f\u8aa4" }, "error": { - "auth_error": "\u8a8d\u8b49\u932f\u8aa4\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { diff --git a/homeassistant/components/tensorflow/image_processing.py b/homeassistant/components/tensorflow/image_processing.py index 0e73d9e871b..e387ae97afe 100644 --- a/homeassistant/components/tensorflow/image_processing.py +++ b/homeassistant/components/tensorflow/image_processing.py @@ -407,7 +407,7 @@ class TensorFlowImageProcessor(ImageProcessingEntity): continue # If we got here, we should include it - if category not in matches.keys(): + if category not in matches: matches[category] = [] matches[category].append({"score": float(score), "box": boxes}) total_matches += 1 diff --git a/homeassistant/components/tesla/translations/ca.json b/homeassistant/components/tesla/translations/ca.json index 0d39ebc2639..4d0583af408 100644 --- a/homeassistant/components/tesla/translations/ca.json +++ b/homeassistant/components/tesla/translations/ca.json @@ -2,13 +2,8 @@ "config": { "error": { "already_configured": "El compte ja ha estat configurat", - "already_configured_account": "El compte ja ha estat configurat", "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "Error de connexi\u00f3; comprova la xarxa i torna-ho a intentar", - "identifier_exists": "Correu electr\u00f2nic ja registrat", - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Credencials inv\u00e0lides", - "unknown_error": "Error desconegut, si us plau, envia la informaci\u00f3 del registre" + "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/cs.json b/homeassistant/components/tesla/translations/cs.json index 7c7e34c201b..c611b85d734 100644 --- a/homeassistant/components/tesla/translations/cs.json +++ b/homeassistant/components/tesla/translations/cs.json @@ -2,13 +2,8 @@ "config": { "error": { "already_configured": "\u00da\u010det je ji\u017e nastaven", - "already_configured_account": "\u00da\u010det je ji\u017e nastaven", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Chyba p\u0159ipojen\u00ed; zkontrolujte s\u00ed\u0165 a zkuste to znovu", - "identifier_exists": "E-mail je ji\u017e zaregistrov\u00e1n", - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje", - "unknown_error": "Nezn\u00e1m\u00e1 chyba, nahlaste pros\u00edm informace z logu" + "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/da.json b/homeassistant/components/tesla/translations/da.json index da4d71058bc..c6cb8b5b208 100644 --- a/homeassistant/components/tesla/translations/da.json +++ b/homeassistant/components/tesla/translations/da.json @@ -1,11 +1,5 @@ { "config": { - "error": { - "connection_error": "Fejl ved tilslutning; tjek netv\u00e6rk og pr\u00f8v igen", - "identifier_exists": "Email er allerede registreret", - "invalid_credentials": "Ugyldige legitimationsoplysninger", - "unknown_error": "Ukendt fejl, rapporter venligst loginfo" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tesla/translations/de.json b/homeassistant/components/tesla/translations/de.json index c6c2bc115f4..67ad3cc5e59 100644 --- a/homeassistant/components/tesla/translations/de.json +++ b/homeassistant/components/tesla/translations/de.json @@ -1,11 +1,5 @@ { "config": { - "error": { - "connection_error": "Fehler beim Verbinden; \u00dcberpr\u00fcfe dein Netzwerk und versuche es erneut", - "identifier_exists": "E-Mail bereits registriert", - "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen", - "unknown_error": "Unbekannter Fehler, bitte Log-Info melden" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tesla/translations/en.json b/homeassistant/components/tesla/translations/en.json index 80d5591b0a1..f2b888552b9 100644 --- a/homeassistant/components/tesla/translations/en.json +++ b/homeassistant/components/tesla/translations/en.json @@ -2,13 +2,8 @@ "config": { "error": { "already_configured": "Account is already configured", - "already_configured_account": "Account is already configured", "cannot_connect": "Failed to connect", - "connection_error": "Error connecting; check network and retry", - "identifier_exists": "Email already registered", - "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid credentials", - "unknown_error": "Unknown error, please report log info" + "invalid_auth": "Invalid authentication" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/es-419.json b/homeassistant/components/tesla/translations/es-419.json index d29077e688d..20fe7b3c436 100644 --- a/homeassistant/components/tesla/translations/es-419.json +++ b/homeassistant/components/tesla/translations/es-419.json @@ -1,11 +1,5 @@ { "config": { - "error": { - "connection_error": "Error al conectar verifique la red y vuelva a intentar", - "identifier_exists": "correo electr\u00f3nico ya registrado", - "invalid_credentials": "Credenciales no v\u00e1lidas", - "unknown_error": "Error desconocido, informe la informaci\u00f3n del registro" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tesla/translations/es.json b/homeassistant/components/tesla/translations/es.json index 074f570ea00..e2c5ed3c0ee 100644 --- a/homeassistant/components/tesla/translations/es.json +++ b/homeassistant/components/tesla/translations/es.json @@ -2,13 +2,8 @@ "config": { "error": { "already_configured": "La cuenta ya ha sido configurada", - "already_configured_account": "La cuenta ya ha sido configurada", "cannot_connect": "No se pudo conectar", - "connection_error": "Error de conexi\u00f3n; comprueba la red y vuelve a intentarlo", - "identifier_exists": "Correo electr\u00f3nico ya registrado", - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_credentials": "Credenciales no v\u00e1lidas", - "unknown_error": "Error desconocido, por favor reporte la informaci\u00f3n de registro" + "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/et.json b/homeassistant/components/tesla/translations/et.json index 31cc796f310..ae427f5d1e7 100644 --- a/homeassistant/components/tesla/translations/et.json +++ b/homeassistant/components/tesla/translations/et.json @@ -2,15 +2,26 @@ "config": { "error": { "already_configured": "Konto on juba h\u00e4\u00e4lestatud", - "already_configured_account": "Kasutaja on juba lisatud", "cannot_connect": "\u00dchendamine nurjus", - "invalid_auth": "Tuvastamise viga", - "unknown_error": "Tundmatu viga, palun lisa logid" + "invalid_auth": "Tuvastamise viga" }, "step": { "user": { "data": { - "password": "Salas\u00f5na" + "password": "Salas\u00f5na", + "username": "E-post" + }, + "description": "Palun sisesta oma andmed.", + "title": "Tesla - seadistamine" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "enable_wake_on_start": "Sunni autod k\u00e4ivitamisel \u00e4rkama (?)", + "scan_interval": "P\u00e4ringute vahe sekundites" } } } diff --git a/homeassistant/components/tesla/translations/fr.json b/homeassistant/components/tesla/translations/fr.json index 96fe2e9d082..c8efc8b4fb5 100644 --- a/homeassistant/components/tesla/translations/fr.json +++ b/homeassistant/components/tesla/translations/fr.json @@ -1,10 +1,9 @@ { "config": { "error": { - "connection_error": "Erreur de connexion; v\u00e9rifier le r\u00e9seau et r\u00e9essayer", - "identifier_exists": "Email d\u00e9j\u00e0 enregistr\u00e9", - "invalid_credentials": "Informations d'identification invalides", - "unknown_error": "Erreur inconnue, veuillez signaler les informations du journal" + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", + "cannot_connect": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/hu.json b/homeassistant/components/tesla/translations/hu.json index 1e8efeec1a1..c6553d4a595 100644 --- a/homeassistant/components/tesla/translations/hu.json +++ b/homeassistant/components/tesla/translations/hu.json @@ -1,11 +1,5 @@ { "config": { - "error": { - "connection_error": "Hiba a csatlakoz\u00e1skor; ellen\u0151rizd a h\u00e1l\u00f3zatot \u00e9s pr\u00f3b\u00e1ld \u00fajra", - "identifier_exists": "Az e-mail c\u00edm m\u00e1r regisztr\u00e1lva van", - "invalid_credentials": "\u00c9rv\u00e9nytelen hiteles\u00edt\u0151 adatok", - "unknown_error": "Ismeretlen hiba, k\u00e9rlek jelentsd a napl\u00f3f\u00e1jlban l\u00e9v\u0151 adatokat" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tesla/translations/it.json b/homeassistant/components/tesla/translations/it.json index 5a14b01cc88..a316b41c29c 100644 --- a/homeassistant/components/tesla/translations/it.json +++ b/homeassistant/components/tesla/translations/it.json @@ -2,13 +2,8 @@ "config": { "error": { "already_configured": "L'account \u00e8 gi\u00e0 configurato", - "already_configured_account": "L'account \u00e8 gi\u00e0 configurato", "cannot_connect": "Impossibile connettersi", - "connection_error": "Errore durante la connessione; controllare la rete e riprovare", - "identifier_exists": "E-mail gi\u00e0 registrata", - "invalid_auth": "Autenticazione non valida", - "invalid_credentials": "Credenziali non valide", - "unknown_error": "Errore sconosciuto, si prega di segnalare le informazioni del registro" + "invalid_auth": "Autenticazione non valida" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/ko.json b/homeassistant/components/tesla/translations/ko.json index 4e48539ccc0..27a96518ca7 100644 --- a/homeassistant/components/tesla/translations/ko.json +++ b/homeassistant/components/tesla/translations/ko.json @@ -1,11 +1,5 @@ { "config": { - "error": { - "connection_error": "\uc5f0\uacb0 \uc624\ub958; \ub124\ud2b8\uc6cc\ud06c\ub97c \ud655\uc778\ud558\uace0 \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694", - "identifier_exists": "\uc774\uba54\uc77c \uc8fc\uc18c\uac00 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "invalid_credentials": "\uc774\uba54\uc77c \uc8fc\uc18c \ud639\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "unknown_error": "\uc54c \uc218 \uc5c6\ub294 \uc624\ub958\uc785\ub2c8\ub2e4. \ub85c\uadf8 \ub0b4\uc6a9\uc744 \uc54c\ub824\uc8fc\uc138\uc694" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tesla/translations/lb.json b/homeassistant/components/tesla/translations/lb.json index 09943e7a14e..32353c99b3e 100644 --- a/homeassistant/components/tesla/translations/lb.json +++ b/homeassistant/components/tesla/translations/lb.json @@ -1,12 +1,9 @@ { "config": { "error": { + "already_configured": "Kont ass scho konfigur\u00e9iert", "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen, Iwwerpr\u00e9ift Netzwierk a prob\u00e9iert nach emol", - "identifier_exists": "E-Mail ass scho registr\u00e9iert", - "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_credentials": "Ong\u00eblteg Login Informatioune", - "unknown_error": "Onbekannte Feeler, mellt w.e.g. Logbuch Info" + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/nl.json b/homeassistant/components/tesla/translations/nl.json index 86f9318f18b..9e79b35165d 100644 --- a/homeassistant/components/tesla/translations/nl.json +++ b/homeassistant/components/tesla/translations/nl.json @@ -2,12 +2,7 @@ "config": { "error": { "already_configured": "Account is al geconfigureerd", - "already_configured_account": "Account is al geconfigureerd", - "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Fout bij verbinden; controleer het netwerk en probeer het opnieuw", - "identifier_exists": "E-mail al geregistreerd", - "invalid_credentials": "Ongeldige inloggegevens", - "unknown_error": "Onbekende fout, meldt u log info" + "cannot_connect": "Kan geen verbinding maken" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/no.json b/homeassistant/components/tesla/translations/no.json index 761aa6d6a10..36cceb97f9f 100644 --- a/homeassistant/components/tesla/translations/no.json +++ b/homeassistant/components/tesla/translations/no.json @@ -2,13 +2,8 @@ "config": { "error": { "already_configured": "Kontoen er allerede konfigurert", - "already_configured_account": "Kontoen er allerede konfigurert", "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Feil ved tilkobling; sjekk nettverket og pr\u00f8v p\u00e5 nytt", - "identifier_exists": "E-post er allerede registrert", - "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldig legitimasjon", - "unknown_error": "Ukjent feil, Vennligst rapporter informasjon fra Loggen" + "invalid_auth": "Ugyldig godkjenning" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/pl.json b/homeassistant/components/tesla/translations/pl.json index 795b2917ef8..dc4144d0f6a 100644 --- a/homeassistant/components/tesla/translations/pl.json +++ b/homeassistant/components/tesla/translations/pl.json @@ -2,13 +2,8 @@ "config": { "error": { "already_configured": "Konto jest ju\u017c skonfigurowane", - "already_configured_account": "Konto jest ju\u017c skonfigurowane", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "B\u0142\u0105d po\u0142\u0105czenia; sprawd\u017a sie\u0107 i spr\u00f3buj ponownie", - "identifier_exists": "Adres e-mail jest ju\u017c zarejestrowany", - "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owe po\u015bwiadczenia", - "unknown_error": "Nieznany b\u0142\u0105d, prosz\u0119 zg\u0142osi\u0107 dane z loga" + "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/pt-BR.json b/homeassistant/components/tesla/translations/pt-BR.json index 7c0a910ca9a..1317f4b1dd7 100644 --- a/homeassistant/components/tesla/translations/pt-BR.json +++ b/homeassistant/components/tesla/translations/pt-BR.json @@ -1,11 +1,5 @@ { "config": { - "error": { - "connection_error": "Erro na conex\u00e3o; verifique a rede e tente novamente", - "identifier_exists": "E-mail j\u00e1 registrado", - "invalid_credentials": "Credenciais inv\u00e1lidas", - "unknown_error": "Erro desconhecido, por favor, relate informa\u00e7\u00f5es do log" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tesla/translations/ru.json b/homeassistant/components/tesla/translations/ru.json index 10a1239279c..8fe167d8631 100644 --- a/homeassistant/components/tesla/translations/ru.json +++ b/homeassistant/components/tesla/translations/ru.json @@ -2,13 +2,8 @@ "config": { "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.", - "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.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0441\u0435\u0442\u044c \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443.", - "identifier_exists": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0430.", - "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_error": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430." + "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { "user": { diff --git a/homeassistant/components/tesla/translations/sl.json b/homeassistant/components/tesla/translations/sl.json index 76890e749d7..e72538e09bc 100644 --- a/homeassistant/components/tesla/translations/sl.json +++ b/homeassistant/components/tesla/translations/sl.json @@ -1,11 +1,5 @@ { "config": { - "error": { - "connection_error": "Napaka pri povezovanju; preverite omre\u017eje in poskusite znova", - "identifier_exists": "E-po\u0161ta je \u017ee registrirana", - "invalid_credentials": "Neveljavne poverilnice", - "unknown_error": "Neznana napaka, sporo\u010dite podatke dnevnika" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tesla/translations/sv.json b/homeassistant/components/tesla/translations/sv.json index 5eebeef1553..d347634cb14 100644 --- a/homeassistant/components/tesla/translations/sv.json +++ b/homeassistant/components/tesla/translations/sv.json @@ -1,11 +1,5 @@ { "config": { - "error": { - "connection_error": "Fel vid anslutning; kontrollera n\u00e4tverket och f\u00f6rs\u00f6k igen", - "identifier_exists": "E-post redan registrerad", - "invalid_credentials": "Ogiltiga autentiseringsuppgifter", - "unknown_error": "Ok\u00e4nt fel, var god att rapportera logginformation" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tesla/translations/zh-Hant.json b/homeassistant/components/tesla/translations/zh-Hant.json index 83f73f85274..235c9036637 100644 --- a/homeassistant/components/tesla/translations/zh-Hant.json +++ b/homeassistant/components/tesla/translations/zh-Hant.json @@ -2,13 +2,8 @@ "config": { "error": { "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "already_configured_account": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u932f\u8aa4\uff1b\u8acb\u6aa2\u5bdf\u7db2\u8def\u5f8c\u518d\u8a66\u4e00\u6b21", - "identifier_exists": "\u90f5\u4ef6\u5df2\u8a3b\u518a", - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u6191\u8b49\u7121\u6548", - "unknown_error": "\u672a\u77e5\u932f\u8aa4\uff0c\u8acb\u56de\u5831\u7d00\u9304" + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { "user": { diff --git a/homeassistant/components/thethingsnetwork/sensor.py b/homeassistant/components/thethingsnetwork/sensor.py index 3555816213a..eab843069f4 100644 --- a/homeassistant/components/thethingsnetwork/sensor.py +++ b/homeassistant/components/thethingsnetwork/sensor.py @@ -147,7 +147,7 @@ class TtnDataStorage: self.data = data[-1] for value in self._values.items(): - if value[0] not in self.data.keys(): + if value[0] not in self.data: _LOGGER.warning("Value not available: %s", value[0]) return response diff --git a/homeassistant/components/tibber/manifest.json b/homeassistant/components/tibber/manifest.json index 3ea64be07bd..d5b19c5094f 100644 --- a/homeassistant/components/tibber/manifest.json +++ b/homeassistant/components/tibber/manifest.json @@ -2,7 +2,7 @@ "domain": "tibber", "name": "Tibber", "documentation": "https://www.home-assistant.io/integrations/tibber", - "requirements": ["pyTibber==0.15.7"], + "requirements": ["pyTibber==0.16.0"], "codeowners": ["@danielhiversen"], "quality_scale": "silver", "config_flow": true diff --git a/homeassistant/components/tibber/strings.json b/homeassistant/components/tibber/strings.json index bf679705b9f..34e218741ca 100644 --- a/homeassistant/components/tibber/strings.json +++ b/homeassistant/components/tibber/strings.json @@ -1,5 +1,4 @@ { - "title": "Tibber", "config": { "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_service%]" diff --git a/homeassistant/components/tibber/translations/ca.json b/homeassistant/components/tibber/translations/ca.json index 22f156ab7a1..bfeb2416e57 100644 --- a/homeassistant/components/tibber/translations/ca.json +++ b/homeassistant/components/tibber/translations/ca.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "Ha fallat la connexi\u00f3", "invalid_access_token": "[%key::common::config_flow::error::invalid_access_token%]", "timeout": "S'ha acabat el temps d'espera durant la connexi\u00f3 a Tibber" }, @@ -18,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/cs.json b/homeassistant/components/tibber/translations/cs.json index 5b2cc898c88..278300caa53 100644 --- a/homeassistant/components/tibber/translations/cs.json +++ b/homeassistant/components/tibber/translations/cs.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_access_token": "Neplatn\u00fd p\u0159\u00edstupov\u00fd token", "timeout": "\u010casov\u00fd limit p\u0159i p\u0159ipojen\u00ed k Tibber" }, @@ -17,6 +16,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/de.json b/homeassistant/components/tibber/translations/de.json index 8ac2219ba60..cd8edbc3e56 100644 --- a/homeassistant/components/tibber/translations/de.json +++ b/homeassistant/components/tibber/translations/de.json @@ -4,7 +4,6 @@ "already_configured": "Ein Tibber-Konto ist bereits konfiguriert." }, "error": { - "connection_error": "Fehler beim Verbinden mit Tibber", "invalid_access_token": "Ung\u00fcltiger Zugriffs-Token", "timeout": "Zeit\u00fcberschreitung beim Verbinden mit Tibber" }, @@ -17,6 +16,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/en.json b/homeassistant/components/tibber/translations/en.json index 3a851ca1283..63df31dca07 100644 --- a/homeassistant/components/tibber/translations/en.json +++ b/homeassistant/components/tibber/translations/en.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect", "invalid_access_token": "Invalid access token", "timeout": "Timeout connecting to Tibber" }, @@ -18,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/es.json b/homeassistant/components/tibber/translations/es.json index bc5e416102b..cdf80422023 100644 --- a/homeassistant/components/tibber/translations/es.json +++ b/homeassistant/components/tibber/translations/es.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "connection_error": "Error de conexi\u00f3n con Tibber", "invalid_access_token": "Token de acceso inv\u00e1lido", "timeout": "Tiempo de espera para conectarse a Tibber" }, @@ -18,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/et.json b/homeassistant/components/tibber/translations/et.json index 94dd4c36e73..5edaac058c6 100644 --- a/homeassistant/components/tibber/translations/et.json +++ b/homeassistant/components/tibber/translations/et.json @@ -5,17 +5,17 @@ }, "error": { "cannot_connect": "\u00dchendus nurjus", - "connection_error": "\u00dchendamine nurjus", - "invalid_access_token": "Vigane juurdep\u00e4\u00e4sut\u00f5end" + "invalid_access_token": "Vigane juurdep\u00e4\u00e4sut\u00f5end", + "timeout": "Tibberiga \u00fchenduse loomise ajal\u00f5pp" }, "step": { "user": { "data": { "access_token": "Juurdep\u00e4\u00e4sut\u00f5end" }, + "description": "Sisesta oma juurdep\u00e4\u00e4suluba saidilt https://developer.tibber.com/settings/accesstoken", "title": "" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/fi.json b/homeassistant/components/tibber/translations/fi.json index ff270732fd9..87e0bef29b2 100644 --- a/homeassistant/components/tibber/translations/fi.json +++ b/homeassistant/components/tibber/translations/fi.json @@ -5,6 +5,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/fr.json b/homeassistant/components/tibber/translations/fr.json index 24fef7886ca..82dd065e53c 100644 --- a/homeassistant/components/tibber/translations/fr.json +++ b/homeassistant/components/tibber/translations/fr.json @@ -4,7 +4,7 @@ "already_configured": "Un compte Tibber est d\u00e9j\u00e0 configur\u00e9." }, "error": { - "connection_error": "Erreur de connexion \u00e0 Tibber", + "cannot_connect": "\u00c9chec de connexion", "invalid_access_token": "Jeton d'acc\u00e8s non valide", "timeout": "D\u00e9lai de connexion \u00e0 Tibber" }, @@ -17,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/he.json b/homeassistant/components/tibber/translations/he.json index 97e67c3c5e7..a2804e54143 100644 --- a/homeassistant/components/tibber/translations/he.json +++ b/homeassistant/components/tibber/translations/he.json @@ -4,7 +4,6 @@ "already_configured": "\u05d7\u05e9\u05d1\u05d5\u05df Tibber \u05d6\u05d4 \u05db\u05d1\u05e8 \u05de\u05d5\u05d2\u05d3\u05e8" }, "error": { - "connection_error": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05dc\u05beTibber \u05e0\u05db\u05e9\u05dc\u05d4", "timeout": "\u05e2\u05d1\u05e8 \u05d4\u05d6\u05de\u05df \u05d4\u05e7\u05e6\u05d5\u05d1 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05dc\u05beTibber" }, "step": { @@ -16,6 +15,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/it.json b/homeassistant/components/tibber/translations/it.json index 1281dd2c5a8..aca7d94083a 100644 --- a/homeassistant/components/tibber/translations/it.json +++ b/homeassistant/components/tibber/translations/it.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi", "invalid_access_token": "Token di accesso non valido", "timeout": "Tempo scaduto per la connessione a Tibber" }, @@ -18,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/ko.json b/homeassistant/components/tibber/translations/ko.json index 6229d2fd138..1f99aa440b4 100644 --- a/homeassistant/components/tibber/translations/ko.json +++ b/homeassistant/components/tibber/translations/ko.json @@ -4,7 +4,6 @@ "already_configured": "Tibber \uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "error": { - "connection_error": "Tibber \uc5f0\uacb0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4", "invalid_access_token": "\uc561\uc138\uc2a4 \ud1a0\ud070\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "timeout": "Tibber \uc5f0\uacb0 \uc2dc\uac04\uc774 \ucd08\uacfc\ud588\uc2b5\ub2c8\ub2e4." }, @@ -17,6 +16,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/lb.json b/homeassistant/components/tibber/translations/lb.json index 90230d20eea..fc84bd1af6f 100644 --- a/homeassistant/components/tibber/translations/lb.json +++ b/homeassistant/components/tibber/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_configured": "Ee Tibber Kont ass scho konfigur\u00e9iert." + "already_configured": "Service ass scho konfigur\u00e9iert." }, "error": { - "connection_error": "Feeler beim verbannen mat Tibber", + "cannot_connect": "Feeler beim verbannen", "invalid_access_token": "Ong\u00ebltegen Acc\u00e8s Jeton", "timeout": "Z\u00e4it Iwwerschreidung beim verbannen mat Tibber" }, @@ -17,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/nl.json b/homeassistant/components/tibber/translations/nl.json new file mode 100644 index 00000000000..4a89639cf50 --- /dev/null +++ b/homeassistant/components/tibber/translations/nl.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_configured": "Service is al geconfigureerd" + }, + "error": { + "invalid_access_token": "Ongeldig toegangstoken", + "timeout": "Time-out om verbinding te maken met Tibber" + }, + "step": { + "user": { + "data": { + "access_token": "Toegangstoken" + }, + "description": "Voer uw toegangstoken in van https://developer.tibber.com/settings/accesstoken", + "title": "Tibber" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/no.json b/homeassistant/components/tibber/translations/no.json index 9eca1edc74c..14bf482e381 100644 --- a/homeassistant/components/tibber/translations/no.json +++ b/homeassistant/components/tibber/translations/no.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes", "invalid_access_token": "Ugyldig tilgangstoken", "timeout": "Tidsavbrudd for tilkobling til Tibber" }, @@ -18,6 +17,5 @@ "title": "" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/pl.json b/homeassistant/components/tibber/translations/pl.json index 53e498c8e97..d62027da3d9 100644 --- a/homeassistant/components/tibber/translations/pl.json +++ b/homeassistant/components/tibber/translations/pl.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "invalid_access_token": "Niepoprawny token dost\u0119pu", "timeout": "Przekroczono limit czasu \u0142\u0105czenia z Tibber" }, @@ -18,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/pt.json b/homeassistant/components/tibber/translations/pt.json index 243987422dd..23f4662a4c1 100644 --- a/homeassistant/components/tibber/translations/pt.json +++ b/homeassistant/components/tibber/translations/pt.json @@ -8,6 +8,5 @@ "title": "" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/ru.json b/homeassistant/components/tibber/translations/ru.json index a301312e11f..7519f581352 100644 --- a/homeassistant/components/tibber/translations/ru.json +++ b/homeassistant/components/tibber/translations/ru.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "invalid_access_token": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430.", "timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f." }, @@ -18,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/sl.json b/homeassistant/components/tibber/translations/sl.json index e97a2aaf031..33ec5ab773b 100644 --- a/homeassistant/components/tibber/translations/sl.json +++ b/homeassistant/components/tibber/translations/sl.json @@ -4,7 +4,6 @@ "already_configured": "Ra\u010dun Tibber je \u017ee konfiguriran." }, "error": { - "connection_error": "Napaka pri povezovanju s Tibberjem", "invalid_access_token": "Neveljaven dostopni \u017eeton", "timeout": "\u010casovna omejitev za priklop na Tibber je potekla" }, @@ -17,6 +16,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tibber/translations/zh-Hant.json b/homeassistant/components/tibber/translations/zh-Hant.json index 3ca7557215e..ce10615a289 100644 --- a/homeassistant/components/tibber/translations/zh-Hant.json +++ b/homeassistant/components/tibber/translations/zh-Hant.json @@ -5,7 +5,6 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557", "invalid_access_token": "\u5b58\u53d6\u5bc6\u9470\u7121\u6548", "timeout": "\u9023\u7dda\u81f3 Tibber \u903e\u6642" }, @@ -18,6 +17,5 @@ "title": "Tibber" } } - }, - "title": "Tibber" + } } \ No newline at end of file diff --git a/homeassistant/components/tile/__init__.py b/homeassistant/components/tile/__init__.py index ad4a8886873..6b43761956e 100644 --- a/homeassistant/components/tile/__init__.py +++ b/homeassistant/components/tile/__init__.py @@ -118,20 +118,18 @@ class TileEntity(CoordinatorEntity): """Return the unique ID of the entity.""" return self._unique_id + @callback + def _handle_coordinator_update(self): + """Respond to a DataUpdateCoordinator update.""" + self._update_from_latest_data() + self.async_write_ha_state() + @callback def _update_from_latest_data(self): """Update the entity from the latest data.""" raise NotImplementedError 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)) - + """Handle entity which will be added.""" + await super().async_added_to_hass() self._update_from_latest_data() diff --git a/homeassistant/components/tile/translations/ca.json b/homeassistant/components/tile/translations/ca.json index 70428873940..60c31b8dce6 100644 --- a/homeassistant/components/tile/translations/ca.json +++ b/homeassistant/components/tile/translations/ca.json @@ -4,8 +4,7 @@ "already_configured": "El compte ja ha estat configurat" }, "error": { - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_credentials": "Credencials de Tile inv\u00e0lides." + "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/de.json b/homeassistant/components/tile/translations/de.json index dfc968eb066..59f48253a18 100644 --- a/homeassistant/components/tile/translations/de.json +++ b/homeassistant/components/tile/translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Konto ist bereits konfiguriert" + }, "step": { "user": { "data": { diff --git a/homeassistant/components/tile/translations/en.json b/homeassistant/components/tile/translations/en.json index ebbd12fc66a..c052cad6d70 100644 --- a/homeassistant/components/tile/translations/en.json +++ b/homeassistant/components/tile/translations/en.json @@ -4,8 +4,7 @@ "already_configured": "Account is already configured" }, "error": { - "invalid_auth": "Invalid authentication", - "invalid_credentials": "Invalid Tile credentials provided." + "invalid_auth": "Invalid authentication" }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/es.json b/homeassistant/components/tile/translations/es.json index b3de73afaf1..f4f5cbec043 100644 --- a/homeassistant/components/tile/translations/es.json +++ b/homeassistant/components/tile/translations/es.json @@ -4,8 +4,7 @@ "already_configured": "La cuenta ya ha sido configurada" }, "error": { - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_credentials": "Credenciales de Tile no v\u00e1lidas" + "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/et.json b/homeassistant/components/tile/translations/et.json index 6fda8553827..de0f91daece 100644 --- a/homeassistant/components/tile/translations/et.json +++ b/homeassistant/components/tile/translations/et.json @@ -11,7 +11,18 @@ "data": { "password": "Salas\u00f5na", "username": "E-post" - } + }, + "title": "Seadista Tile" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "show_inactive": "Kuva passiivsed paanid" + }, + "title": "Seadista Tile" } } } diff --git a/homeassistant/components/tile/translations/fr.json b/homeassistant/components/tile/translations/fr.json index c39730167f9..2af0fbab669 100644 --- a/homeassistant/components/tile/translations/fr.json +++ b/homeassistant/components/tile/translations/fr.json @@ -4,7 +4,7 @@ "already_configured": "Ce compte Tile est d\u00e9j\u00e0 enregistr\u00e9." }, "error": { - "invalid_credentials": "Informations d'identification de Tile non valides." + "invalid_auth": "Authentification invalide" }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/it.json b/homeassistant/components/tile/translations/it.json index 660985d9688..e9655775012 100644 --- a/homeassistant/components/tile/translations/it.json +++ b/homeassistant/components/tile/translations/it.json @@ -4,8 +4,7 @@ "already_configured": "L'account \u00e8 gi\u00e0 configurato" }, "error": { - "invalid_auth": "Autenticazione non valida", - "invalid_credentials": "Fornite credenziali di Tile non valide." + "invalid_auth": "Autenticazione non valida" }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/ko.json b/homeassistant/components/tile/translations/ko.json index 4788269eab1..50ba5000a1a 100644 --- a/homeassistant/components/tile/translations/ko.json +++ b/homeassistant/components/tile/translations/ko.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\uc774 Tile \uacc4\uc815\uc740 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, - "error": { - "invalid_credentials": "\uc774\uba54\uc77c \uc8fc\uc18c \ud639\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tile/translations/lb.json b/homeassistant/components/tile/translations/lb.json index ab2159256a4..fff9aed564a 100644 --- a/homeassistant/components/tile/translations/lb.json +++ b/homeassistant/components/tile/translations/lb.json @@ -4,8 +4,7 @@ "already_configured": "Kont ass scho registr\u00e9iert." }, "error": { - "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_credentials": "Ong\u00eblteg Tile Login Informatioune uginn." + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/nl.json b/homeassistant/components/tile/translations/nl.json new file mode 100644 index 00000000000..31529d69a2d --- /dev/null +++ b/homeassistant/components/tile/translations/nl.json @@ -0,0 +1,14 @@ +{ + "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "step": { + "user": { + "data": { + "password": "Wachtwoord" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/tile/translations/no.json b/homeassistant/components/tile/translations/no.json index c8cb1f9c4f2..9c8c55cd0ed 100644 --- a/homeassistant/components/tile/translations/no.json +++ b/homeassistant/components/tile/translations/no.json @@ -4,8 +4,7 @@ "already_configured": "Kontoen er allerede konfigurert" }, "error": { - "invalid_auth": "Ugyldig godkjenning", - "invalid_credentials": "Ugyldige Tile registreringsinformasjon gitt." + "invalid_auth": "Ugyldig godkjenning" }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/pl.json b/homeassistant/components/tile/translations/pl.json index 3c50630ec25..aff948af08c 100644 --- a/homeassistant/components/tile/translations/pl.json +++ b/homeassistant/components/tile/translations/pl.json @@ -4,8 +4,7 @@ "already_configured": "Konto jest ju\u017c skonfigurowane" }, "error": { - "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_credentials": "Nieprawid\u0142owe dane logowania Tile" + "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/ru.json b/homeassistant/components/tile/translations/ru.json index c02a17b1646..62d0b10857c 100644 --- a/homeassistant/components/tile/translations/ru.json +++ b/homeassistant/components/tile/translations/ru.json @@ -4,8 +4,7 @@ "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." }, "error": { - "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_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { "user": { diff --git a/homeassistant/components/tile/translations/zh-Hant.json b/homeassistant/components/tile/translations/zh-Hant.json index 8e1e51c5682..b44a8a1381f 100644 --- a/homeassistant/components/tile/translations/zh-Hant.json +++ b/homeassistant/components/tile/translations/zh-Hant.json @@ -4,8 +4,7 @@ "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_credentials": "\u6240\u63d0\u4f9b\u7684 Tile \u6191\u8b49\u7121\u6548\u3002" + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { "user": { diff --git a/homeassistant/components/toon/translations/cs.json b/homeassistant/components/toon/translations/cs.json index 3039fa9f061..52a2f7b5742 100644 --- a/homeassistant/components/toon/translations/cs.json +++ b/homeassistant/components/toon/translations/cs.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "authorize_url_fail": "Nezn\u00e1m\u00e1 chyba p\u0159i generov\u00e1n\u00ed autoriza\u010dn\u00ed URL adresy.", "authorize_url_timeout": "\u010casov\u00fd limit autoriza\u010dn\u00edho URL vypr\u0161el", "missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace.", "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})" diff --git a/homeassistant/components/toon/translations/et.json b/homeassistant/components/toon/translations/et.json index 7a4577d91da..a003702d654 100644 --- a/homeassistant/components/toon/translations/et.json +++ b/homeassistant/components/toon/translations/et.json @@ -3,8 +3,22 @@ "abort": { "already_configured": "Valitud n\u00f5usolek on juba seadistatud.", "authorize_url_fail": "Tundmatu viga tuvastamise URL-i loomisel.", + "authorize_url_timeout": "Kinnitus-URLi loomise ajal\u00f5pp.", "missing_configuration": "Osis pole seadistatud. Palun vaata dokumentatsiooni.", + "no_agreements": "Sellel kontol ei ole Toon-i kuvasid.", "no_url_available": "URL pole saadaval. Rohkem teavet [check the help section]({docs_url})" + }, + "step": { + "agreement": { + "data": { + "agreement": "Leping" + }, + "description": "Vali lisatav lepingu aadress.", + "title": "Vali oma leping" + }, + "pick_implementation": { + "title": "Valige oma rentnik, kellega autentida" + } } } } \ No newline at end of file diff --git a/homeassistant/components/toon/translations/nl.json b/homeassistant/components/toon/translations/nl.json index da3ce6d84c7..4f63d7d09da 100644 --- a/homeassistant/components/toon/translations/nl.json +++ b/homeassistant/components/toon/translations/nl.json @@ -1,6 +1,8 @@ { "config": { "abort": { + "already_configured": "De geselecteerde overeenkomst is al geconfigureerd.", + "authorize_url_fail": "Onbekende fout bij het genereren van een autorisatie-URL.", "no_agreements": "Dit account heeft geen Toon schermen.", "no_url_available": "Geen URL beschikbaar. Voor informatie over deze fout [check the help section] ( {docs_url} )" } diff --git a/homeassistant/components/toon/translations/pl.json b/homeassistant/components/toon/translations/pl.json index a74a58339be..2c8715a0044 100644 --- a/homeassistant/components/toon/translations/pl.json +++ b/homeassistant/components/toon/translations/pl.json @@ -17,7 +17,7 @@ "title": "Wybierz swoj\u0105 umow\u0119" }, "pick_implementation": { - "title": "Wybierz dzier\u017cawc\u0119 do uwierzytelnienia" + "title": "Wybierz metod\u0119 uwierzytelniania" } } } diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 665a42aba1a..4ec632f4577 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -3,7 +3,6 @@ "name": "Honeywell Total Connect Alarm", "documentation": "https://www.home-assistant.io/integrations/totalconnect", "requirements": ["total_connect_client==0.55"], - "dependencies": [], "codeowners": ["@austinmroczek"], "config_flow": true } diff --git a/homeassistant/components/totalconnect/translations/ca.json b/homeassistant/components/totalconnect/translations/ca.json index f217eb4f6bc..25dafcf7d21 100644 --- a/homeassistant/components/totalconnect/translations/ca.json +++ b/homeassistant/components/totalconnect/translations/ca.json @@ -4,8 +4,7 @@ "already_configured": "El compte ja ha estat configurat" }, "error": { - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "login": "Error d'inici de sessi\u00f3: comprova el nom d'usuari i la contrasenya" + "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/cs.json b/homeassistant/components/totalconnect/translations/cs.json index f589e592330..60e2196b387 100644 --- a/homeassistant/components/totalconnect/translations/cs.json +++ b/homeassistant/components/totalconnect/translations/cs.json @@ -4,8 +4,7 @@ "already_configured": "\u00da\u010det je ji\u017e nastaven" }, "error": { - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "login": "Chyba p\u0159ihl\u00e1\u0161en\u00ed: zkontrolujte sv\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no a heslo" + "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/de.json b/homeassistant/components/totalconnect/translations/de.json index d3130bd7e80..25069635cca 100644 --- a/homeassistant/components/totalconnect/translations/de.json +++ b/homeassistant/components/totalconnect/translations/de.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Konto bereits konfiguriert" }, - "error": { - "login": "Login-Fehler: Bitte \u00fcberpr\u00fcfen Sie Ihren Benutzernamen & Passwort" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/totalconnect/translations/en.json b/homeassistant/components/totalconnect/translations/en.json index 1174d3e6687..f02a3eadf9c 100644 --- a/homeassistant/components/totalconnect/translations/en.json +++ b/homeassistant/components/totalconnect/translations/en.json @@ -4,8 +4,7 @@ "already_configured": "Account is already configured" }, "error": { - "invalid_auth": "Invalid authentication", - "login": "Login error: please check your username & password" + "invalid_auth": "Invalid authentication" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/es-419.json b/homeassistant/components/totalconnect/translations/es-419.json index 421d2667099..b8507f2b8a7 100644 --- a/homeassistant/components/totalconnect/translations/es-419.json +++ b/homeassistant/components/totalconnect/translations/es-419.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "La cuenta ya ha sido configurada" }, - "error": { - "login": "Error de inicio de sesi\u00f3n: compruebe su nombre de usuario y contrase\u00f1a" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/totalconnect/translations/es.json b/homeassistant/components/totalconnect/translations/es.json index 32d43bb165a..48af1bed0f4 100644 --- a/homeassistant/components/totalconnect/translations/es.json +++ b/homeassistant/components/totalconnect/translations/es.json @@ -4,8 +4,7 @@ "already_configured": "La cuenta ya ha sido configurada" }, "error": { - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "login": "Error de inicio de sesi\u00f3n: comprueba tu nombre de usuario y contrase\u00f1a" + "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/et.json b/homeassistant/components/totalconnect/translations/et.json index 83763a467ac..2940b7a9e65 100644 --- a/homeassistant/components/totalconnect/translations/et.json +++ b/homeassistant/components/totalconnect/translations/et.json @@ -11,7 +11,8 @@ "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "" } } } diff --git a/homeassistant/components/totalconnect/translations/fr.json b/homeassistant/components/totalconnect/translations/fr.json index cf841328d9c..6526d0a9800 100644 --- a/homeassistant/components/totalconnect/translations/fr.json +++ b/homeassistant/components/totalconnect/translations/fr.json @@ -4,8 +4,7 @@ "already_configured": "Compte d\u00e9j\u00e0 configur\u00e9" }, "error": { - "invalid_auth": "Authentification invalide", - "login": "Erreur de connexion: veuillez v\u00e9rifier votre nom d'utilisateur et votre mot de passe" + "invalid_auth": "Authentification invalide" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/it.json b/homeassistant/components/totalconnect/translations/it.json index 369b739e841..2a12d00f57d 100644 --- a/homeassistant/components/totalconnect/translations/it.json +++ b/homeassistant/components/totalconnect/translations/it.json @@ -4,8 +4,7 @@ "already_configured": "L'account \u00e8 gi\u00e0 configurato" }, "error": { - "invalid_auth": "Autenticazione non valida", - "login": "Errore di accesso: si prega di controllare il nome utente e la password" + "invalid_auth": "Autenticazione non valida" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/ko.json b/homeassistant/components/totalconnect/translations/ko.json index fac8916a54f..99513a64508 100644 --- a/homeassistant/components/totalconnect/translations/ko.json +++ b/homeassistant/components/totalconnect/translations/ko.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "\uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, - "error": { - "login": "\ub85c\uadf8\uc778 \uc624\ub958: \uc0ac\uc6a9\uc790 \uc774\ub984 \ubc0f \ube44\ubc00\ubc88\ud638\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/totalconnect/translations/lb.json b/homeassistant/components/totalconnect/translations/lb.json index 53074251944..af76c38d918 100644 --- a/homeassistant/components/totalconnect/translations/lb.json +++ b/homeassistant/components/totalconnect/translations/lb.json @@ -4,8 +4,7 @@ "already_configured": "Kont ass scho konfigur\u00e9iert" }, "error": { - "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "login": "Feeler beim Login: iwwerpr\u00e9if de Benotzernumm & Passwuert" + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/nl.json b/homeassistant/components/totalconnect/translations/nl.json index 508c112ae61..c72b7e368ac 100644 --- a/homeassistant/components/totalconnect/translations/nl.json +++ b/homeassistant/components/totalconnect/translations/nl.json @@ -4,7 +4,7 @@ "already_configured": "Account al geconfigureerd" }, "error": { - "login": "Aanmeldingsfout: controleer uw gebruikersnaam en wachtwoord" + "invalid_auth": "Ongeldige authenticatie" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/no.json b/homeassistant/components/totalconnect/translations/no.json index 62e4fffb1fd..e80f86696fc 100644 --- a/homeassistant/components/totalconnect/translations/no.json +++ b/homeassistant/components/totalconnect/translations/no.json @@ -4,8 +4,7 @@ "already_configured": "Kontoen er allerede konfigurert" }, "error": { - "invalid_auth": "Ugyldig godkjenning", - "login": "P\u00e5loggingsfeil: Vennligst sjekk brukernavnet ditt og passordet ditt" + "invalid_auth": "Ugyldig godkjenning" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/pl.json b/homeassistant/components/totalconnect/translations/pl.json index fd47103360c..530d632040c 100644 --- a/homeassistant/components/totalconnect/translations/pl.json +++ b/homeassistant/components/totalconnect/translations/pl.json @@ -4,8 +4,7 @@ "already_configured": "Konto jest ju\u017c skonfigurowane" }, "error": { - "invalid_auth": "Niepoprawne uwierzytelnienie", - "login": "B\u0142\u0105d logowania: sprawd\u017a swoj\u0105 nazw\u0119 u\u017cytkownika i has\u0142o" + "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/pt-BR.json b/homeassistant/components/totalconnect/translations/pt-BR.json index e651bb03b44..432a49cacf6 100644 --- a/homeassistant/components/totalconnect/translations/pt-BR.json +++ b/homeassistant/components/totalconnect/translations/pt-BR.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Conta j\u00e1 configurada" }, - "error": { - "login": "Erro de login: verifique seu nome de usu\u00e1rio e senha" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/totalconnect/translations/pt.json b/homeassistant/components/totalconnect/translations/pt.json index de29ebd0489..d399370847c 100644 --- a/homeassistant/components/totalconnect/translations/pt.json +++ b/homeassistant/components/totalconnect/translations/pt.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Conta j\u00e1 configurada" }, - "error": { - "login": "Erro de login: verifique seu nome de utilizador e palavra-passe" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/totalconnect/translations/ru.json b/homeassistant/components/totalconnect/translations/ru.json index 29a070d841e..c5221b5e4ca 100644 --- a/homeassistant/components/totalconnect/translations/ru.json +++ b/homeassistant/components/totalconnect/translations/ru.json @@ -4,8 +4,7 @@ "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." }, "error": { - "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", - "login": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u0445\u043e\u0434\u0430: \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c." + "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { "user": { diff --git a/homeassistant/components/totalconnect/translations/sl.json b/homeassistant/components/totalconnect/translations/sl.json index 80127b053d6..7214ff6aeb5 100644 --- a/homeassistant/components/totalconnect/translations/sl.json +++ b/homeassistant/components/totalconnect/translations/sl.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Ra\u010dun \u017ee nastavljen" }, - "error": { - "login": "Napaka pri prijavi: preverite svoje uporabni\u0161ko ime in geslo" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/totalconnect/translations/sv.json b/homeassistant/components/totalconnect/translations/sv.json index 68dc9efeedb..bff6edd489e 100644 --- a/homeassistant/components/totalconnect/translations/sv.json +++ b/homeassistant/components/totalconnect/translations/sv.json @@ -3,9 +3,6 @@ "abort": { "already_configured": "Kontot har redan konfigurerats" }, - "error": { - "login": "Inloggningsfel: v\u00e4nligen kontrollera ditt anv\u00e4ndarnamn och l\u00f6senord" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/totalconnect/translations/zh-Hans.json b/homeassistant/components/totalconnect/translations/zh-Hans.json index 1d0c0eb1071..a5f4ff11f09 100644 --- a/homeassistant/components/totalconnect/translations/zh-Hans.json +++ b/homeassistant/components/totalconnect/translations/zh-Hans.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "login": "\u767b\u5f55\u9519\u8bef\uff1a\u8bf7\u68c0\u67e5\u7528\u6237\u540d\u548c\u5bc6\u7801" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/totalconnect/translations/zh-Hant.json b/homeassistant/components/totalconnect/translations/zh-Hant.json index b9416b0fbf3..c20dd4065b6 100644 --- a/homeassistant/components/totalconnect/translations/zh-Hant.json +++ b/homeassistant/components/totalconnect/translations/zh-Hant.json @@ -4,8 +4,7 @@ "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "login": "\u767b\u5165\u932f\u8aa4\uff1a\u8acb\u78ba\u8a8d\u96fb\u5b50\u90f5\u4ef6\u8207\u5bc6\u78bc" + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { "user": { diff --git a/homeassistant/components/tplink/translations/lb.json b/homeassistant/components/tplink/translations/lb.json index 80369964f11..1560b68d3e4 100644 --- a/homeassistant/components/tplink/translations/lb.json +++ b/homeassistant/components/tplink/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "no_devices_found": "Keng TP-Link Apparater am Netzwierk fonnt.", - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun ass n\u00e9ideg." + "no_devices_found": "Keng Apparater am Netzwierk fonnt.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "confirm": { diff --git a/homeassistant/components/tplink/translations/pl.json b/homeassistant/components/tplink/translations/pl.json index ea531a845ed..a8ee3fa57ac 100644 --- a/homeassistant/components/tplink/translations/pl.json +++ b/homeassistant/components/tplink/translations/pl.json @@ -6,7 +6,7 @@ }, "step": { "confirm": { - "description": "Czy chcesz skonfigurowa\u0107 urz\u0105dzenia TP-Link smart?" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } } diff --git a/homeassistant/components/traccar/strings.json b/homeassistant/components/traccar/strings.json index aef269defcb..d9d9fff4bd3 100644 --- a/homeassistant/components/traccar/strings.json +++ b/homeassistant/components/traccar/strings.json @@ -8,7 +8,7 @@ }, "abort": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Traccar." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup the webhook feature in Traccar.\n\nUse the following url: `{webhook_url}`\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/traccar/translations/bg.json b/homeassistant/components/traccar/translations/bg.json index 19faba84640..5b9d2ae0e6d 100644 --- a/homeassistant/components/traccar/translations/bg.json +++ b/homeassistant/components/traccar/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 Traccar.", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u0441\u044a\u0431\u0438\u0442\u0438\u044f \u0434\u043e Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0442\u0430 webhook \u0432 Traccar. \n\n \u0418\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0438\u044f \u0430\u0434\u0440\u0435\u0441: ` {webhook_url} ` \n\n \u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438." }, diff --git a/homeassistant/components/traccar/translations/ca.json b/homeassistant/components/traccar/translations/ca.json index 8dd1cecf90a..1b00aab4b3e 100644 --- a/homeassistant/components/traccar/translations/ca.json +++ b/homeassistant/components/traccar/translations/ca.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de Traccar.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar esdeveniments a Home Assistant, haur\u00e0s de configurar l'opci\u00f3 webhook de Traccar.\n\nUtilitza el seg\u00fcent enlla\u00e7: `{webhook_url}`\n\nConsulta la [documentaci\u00f3]({docs_url}) per a m\u00e9s detalls." diff --git a/homeassistant/components/traccar/translations/cs.json b/homeassistant/components/traccar/translations/cs.json index 4c41801fb42..523ce487e8e 100644 --- a/homeassistant/components/traccar/translations/cs.json +++ b/homeassistant/components/traccar/translations/cs.json @@ -1,11 +1,12 @@ { "config": { "abort": { - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "step": { "user": { + "description": "Opravdu chcete nastavit Traccar?", "title": "Nastavit Traccar" } } diff --git a/homeassistant/components/traccar/translations/da.json b/homeassistant/components/traccar/translations/da.json index e836d84aea7..cf8f74e5522 100644 --- a/homeassistant/components/traccar/translations/da.json +++ b/homeassistant/components/traccar/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage Traccar-meddelelser.", - "one_instance_allowed": "Kun en enkelt instans er n\u00f8dvendig." - }, "create_entry": { "default": "For at sende h\u00e6ndelser til Home Assistant skal du konfigurere webhook-funktionen i Traccar.\n\nBrug f\u00f8lgende webadresse: `{webhook_url}`\n \nSe [dokumentationen]({docs_url}) for yderligere oplysninger." }, diff --git a/homeassistant/components/traccar/translations/de.json b/homeassistant/components/traccar/translations/de.json index b4488c854f8..5d5969b2d51 100644 --- a/homeassistant/components/traccar/translations/de.json +++ b/homeassistant/components/traccar/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Ihre Home Assistant-Instanz muss \u00fcber das Internet zug\u00e4nglich sein, um Nachrichten von Traccar zu empfangen.", - "one_instance_allowed": "Es ist nur eine einzelne Instanz erforderlich." - }, "create_entry": { "default": "Um Ereignisse an den Heimassistenten zu senden, m\u00fcssen die Webhook-Funktionen in Traccar eingerichtet werden.\n\nVerwende die folgende URL: `{webhook_url}}`\n\nSiehe [die Dokumentation]( {docs_url} ) f\u00fcr weitere Details." }, diff --git a/homeassistant/components/traccar/translations/en.json b/homeassistant/components/traccar/translations/en.json index 2a9c92cc1d0..2231d53ceb8 100644 --- a/homeassistant/components/traccar/translations/en.json +++ b/homeassistant/components/traccar/translations/en.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Traccar.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup the webhook feature in Traccar.\n\nUse the following url: `{webhook_url}`\n\nSee [the documentation]({docs_url}) for further details." diff --git a/homeassistant/components/traccar/translations/es-419.json b/homeassistant/components/traccar/translations/es-419.json index 17f7560a464..3a2b87f8dfe 100644 --- a/homeassistant/components/traccar/translations/es-419.json +++ b/homeassistant/components/traccar/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes de Traccar.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar eventos a Home Assistant, deber\u00e1 configurar la funci\u00f3n webhook en Traccar. \n\n Use la siguiente URL: `{webhook_url}` \n\n Consulte [la documentaci\u00f3n] ({docs_url}) para obtener m\u00e1s detalles." }, diff --git a/homeassistant/components/traccar/translations/es.json b/homeassistant/components/traccar/translations/es.json index 9ce5699526d..a87e7aae2c1 100644 --- a/homeassistant/components/traccar/translations/es.json +++ b/homeassistant/components/traccar/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Traccar.", - "one_instance_allowed": "S\u00f3lo se necesita una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar eventos a Home Assistant, necesitar\u00e1 configurar la funci\u00f3n de webhook en Traccar.\n\nUtilice la siguiente url: ``{webhook_url}``\n\nConsulte la [documentaci\u00f3n]({docs_url}) para m\u00e1s detalles." diff --git a/homeassistant/components/traccar/translations/et.json b/homeassistant/components/traccar/translations/et.json index 2283058c25f..e2c4ad68a8d 100644 --- a/homeassistant/components/traccar/translations/et.json +++ b/homeassistant/components/traccar/translations/et.json @@ -1,12 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Lubatud on ainult \u00fcks sidumine.", - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." + }, + "create_entry": { + "default": "S\u00fcndmuste saatmiseks Home Assistantile pead seadistama Traccar'i veebihaagi. \n\n -Kasuta URLi: \" {webhook_url} \" \n \n Lisateavet leiad [documentation] ( {docs_url} )." }, "step": { "user": { - "description": "Kas soovid seadistada Traccar'i?" + "description": "Kas soovid seadistada Traccar'i?", + "title": "Seadista Traccar" } } } diff --git a/homeassistant/components/traccar/translations/fr.json b/homeassistant/components/traccar/translations/fr.json index e000bbaaac8..3c32100078d 100644 --- a/homeassistant/components/traccar/translations/fr.json +++ b/homeassistant/components/traccar/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance de Home Assistant doit \u00eatre accessible depuis Internet pour recevoir les messages de Traccar.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez configurer la fonction Webhook dans Traccar. \n\n Utilisez l'URL suivante: ` {webhook_url} ` \n\n Voir [la documentation] ( {docs_url} ) pour plus de d\u00e9tails." diff --git a/homeassistant/components/traccar/translations/it.json b/homeassistant/components/traccar/translations/it.json index 86e65ace3db..6d4de5bb13d 100644 --- a/homeassistant/components/traccar/translations/it.json +++ b/homeassistant/components/traccar/translations/it.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi da Traccar.", - "one_instance_allowed": "\u00c8 necessaria solo una singola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare eventi a Home Assistant, \u00e8 necessario configurare la funzionalit\u00e0 webhook in Traccar.\n\nUtilizzare l'URL seguente: `{webhook_url}`\n\nPer ulteriori dettagli, vedere [la documentazione]({docs_url}) ." diff --git a/homeassistant/components/traccar/translations/ko.json b/homeassistant/components/traccar/translations/ko.json index f44030821fd..910281d4b38 100644 --- a/homeassistant/components/traccar/translations/ko.json +++ b/homeassistant/components/traccar/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Traccar \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\ub824\uba74 Traccar \uc5d0\uc11c \uc6f9 \ud6c5\uc744 \uc124\uc815\ud574\uc57c\ud569\ub2c8\ub2e4. \n\n\ub2e4\uc74c URL \uc815\ubcf4\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4: `{webhook_url}`\n \n\uc790\uc138\ud55c \uc815\ubcf4\ub294 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/traccar/translations/lb.json b/homeassistant/components/traccar/translations/lb.json index 3ccacf127e9..d7295252005 100644 --- a/homeassistant/components/traccar/translations/lb.json +++ b/homeassistant/components/traccar/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir Traccar Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { diff --git a/homeassistant/components/traccar/translations/nl.json b/homeassistant/components/traccar/translations/nl.json index 7e9d93bc0c8..251e16d0763 100644 --- a/homeassistant/components/traccar/translations/nl.json +++ b/homeassistant/components/traccar/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Uw Home Assistant-exemplaar moet toegankelijk zijn vanaf internet om berichten van Traccar te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/traccar/translations/no.json b/homeassistant/components/traccar/translations/no.json index 1b0728f26d4..38faa4dc1c1 100644 --- a/homeassistant/components/traccar/translations/no.json +++ b/homeassistant/components/traccar/translations/no.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Din Home Assistant-forekomst m\u00e5 v\u00e6re tilgjengelig fra Internett for \u00e5 motta meldinger fra Traccar.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { "default": "Hvis du vil sende hendelser til Home Assistant, m\u00e5 du konfigurere webhook-funksjonen i Traccar.\n\nBruk f\u00f8lgende URL-adresse: `{webhook_url}`\n\nSe [dokumentasjonen]({docs_url}) for mer informasjon." diff --git a/homeassistant/components/traccar/translations/pl.json b/homeassistant/components/traccar/translations/pl.json index 04d06274ae5..7b990190d84 100644 --- a/homeassistant/components/traccar/translations/pl.json +++ b/homeassistant/components/traccar/translations/pl.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Twoja instancja Home Assistant musi by\u0107 dost\u0119pna z Internetu, aby otrzymywa\u0107 wiadomo\u015bci z Traccar", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant, musisz skonfigurowa\u0107 webhook w Traccar. \n\n U\u017cyj nast\u0119puj\u0105cego URL: `{webhook_url}` \n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}), by pozna\u0107 szczeg\u00f3\u0142y." }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 Traccar?", + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", "title": "Konfiguracja Traccar" } } diff --git a/homeassistant/components/traccar/translations/pt-BR.json b/homeassistant/components/traccar/translations/pt-BR.json index 2a7afb38268..eaaa5717709 100644 --- a/homeassistant/components/traccar/translations/pt-BR.json +++ b/homeassistant/components/traccar/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia do Home Assistant precisa estar acess\u00edvel na Internet para receber mensagens do Traccar.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos ao Home Assistant, voc\u00ea precisar\u00e1 configurar o recurso de webhook no Traccar. \n\n Use o seguinte URL: ` {webhook_url} ` \n\n Veja [a documenta\u00e7\u00e3o] ({docs_url}) para mais detalhes." }, diff --git a/homeassistant/components/traccar/translations/ru.json b/homeassistant/components/traccar/translations/ru.json index f9a23647422..b35b1e74e1e 100644 --- a/homeassistant/components/traccar/translations/ru.json +++ b/homeassistant/components/traccar/translations/ru.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 Traccar.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Webhook \u0434\u043b\u044f Traccar.\n\n\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n\n\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 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438." diff --git a/homeassistant/components/traccar/translations/sl.json b/homeassistant/components/traccar/translations/sl.json index 016f3bbbeb2..e1ea3d3b718 100644 --- a/homeassistant/components/traccar/translations/sl.json +++ b/homeassistant/components/traccar/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Va\u0161 Home Assistant mora biti dostopen prek interneta, da boste lahko prejemali Traccar sporo\u010dila.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "\u010ce \u017eelite poslati dogodke v Home Assistant, boste morali nastaviti funkcijo \"webhook\" v traccar.\n\nUporabite naslednji URL: ' {webhook_url} '\n\nZa podrobnej\u0161e informacije glejte [dokumentacijo] ({docs_url})." }, diff --git a/homeassistant/components/traccar/translations/sv.json b/homeassistant/components/traccar/translations/sv.json index ce32171eba5..274de7cfe7b 100644 --- a/homeassistant/components/traccar/translations/sv.json +++ b/homeassistant/components/traccar/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans m\u00e5ste vara tillg\u00e4nglig fr\u00e5n internet f\u00f6r att ta emot meddelanden fr\u00e5n Traccar.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du st\u00e4lla in webhook-funktionen i Traccar.\n\nAnv\u00e4nd f\u00f6ljande url: `{webhook_url}`\n\nMer information finns i [dokumentationen]({docs_url})." }, diff --git a/homeassistant/components/traccar/translations/zh-Hans.json b/homeassistant/components/traccar/translations/zh-Hans.json deleted file mode 100644 index 248e8f9f44e..00000000000 --- a/homeassistant/components/traccar/translations/zh-Hans.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u53ef\u4ece\u4e92\u8054\u7f51\u8bbf\u95ee\u4ee5\u63a5\u6536Traccar\u6d88\u606f\u3002", - "one_instance_allowed": "\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u662f\u5fc5\u9700\u7684\u3002" - } - } -} \ No newline at end of file diff --git a/homeassistant/components/traccar/translations/zh-Hant.json b/homeassistant/components/traccar/translations/zh-Hant.json index b14b5f12b9f..71d22d66cb0 100644 --- a/homeassistant/components/traccar/translations/zh-Hant.json +++ b/homeassistant/components/traccar/translations/zh-Hant.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u8a2d\u5099\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 Traccar \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u65bc Traccar \u5167\u8a2d\u5b9a webhook \u529f\u80fd\u3002\n\n\u8acb\u4f7f\u7528 url: `{webhook_url}`\n\n\u8acb\u53c3\u95b1 [\u6587\u4ef6]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u8a73\u7d30\u8cc7\u6599\u3002" diff --git a/homeassistant/components/tradfri/manifest.json b/homeassistant/components/tradfri/manifest.json index dace0f0739b..7ffa8ed24bf 100644 --- a/homeassistant/components/tradfri/manifest.json +++ b/homeassistant/components/tradfri/manifest.json @@ -3,15 +3,9 @@ "name": "IKEA TRÅDFRI", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tradfri", - "requirements": [ - "pytradfri[async]==7.0.2" - ], + "requirements": ["pytradfri[async]==7.0.4"], "homekit": { - "models": [ - "TRADFRI" - ] + "models": ["TRADFRI"] }, - "codeowners": [ - "@ggravlingen" - ] + "codeowners": ["@ggravlingen"] } diff --git a/homeassistant/components/tradfri/translations/et.json b/homeassistant/components/tradfri/translations/et.json index c5d97b1c496..00c804e6b05 100644 --- a/homeassistant/components/tradfri/translations/et.json +++ b/homeassistant/components/tradfri/translations/et.json @@ -5,13 +5,18 @@ "already_in_progress": "Seadistamine on juba k\u00e4imas" }, "error": { - "cannot_connect": "\u00dchendamine nurjus" + "cannot_connect": "\u00dchendamine nurjus", + "invalid_key": "Sisestatud v\u00f5tmega registreerimine nurjus. Kui see juhtub, proovi l\u00fc\u00fcs taask\u00e4ivitada.", + "timeout": "Koodi kinnitamise ajal\u00f5pp." }, "step": { "auth": { "data": { - "host": "" - } + "host": "", + "security_code": "Turvakood" + }, + "description": "Turvakoodi leiad l\u00fc\u00fcsiseadme tagak\u00fcljelt.", + "title": "Sisesta turvakood" } } } diff --git a/homeassistant/components/tradfri/translations/lb.json b/homeassistant/components/tradfri/translations/lb.json index c86016fa0b6..7078135c75d 100644 --- a/homeassistant/components/tradfri/translations/lb.json +++ b/homeassistant/components/tradfri/translations/lb.json @@ -1,11 +1,11 @@ { "config": { "abort": { - "already_configured": "Bridge ass schon konfigur\u00e9iert", - "already_in_progress": "Bridge Konfiguratioun ass schonn am gaang." + "already_configured": "Apparat ass schon konfigur\u00e9iert", + "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaang." }, "error": { - "cannot_connect": "Keng Verbindung mat der Gateway m\u00e9iglech.", + "cannot_connect": "Feeler beim verbannen", "invalid_key": "Konnt sech net mam ugebuedenem Schl\u00ebssel registr\u00e9ieren. Falls d\u00ebst widderhuelt optr\u00ebtt, prob\u00e9iert de Gateway fr\u00ebsch ze starten.", "timeout": "Z\u00e4it Iwwerschreidung\u00a0beim valid\u00e9ieren vum Code" }, diff --git a/homeassistant/components/transmission/translations/bg.json b/homeassistant/components/transmission/translations/bg.json index d817129e11a..2e348d59f24 100644 --- a/homeassistant/components/transmission/translations/bg.json +++ b/homeassistant/components/transmission/translations/bg.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u0441 \u0430\u0434\u0440\u0435\u0441\u0430", - "name_exists": "\u0418\u043c\u0435\u0442\u043e \u0432\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430", - "wrong_credentials": "\u0413\u0440\u0435\u0448\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435 \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u0430" + "name_exists": "\u0418\u043c\u0435\u0442\u043e \u0432\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/ca.json b/homeassistant/components/transmission/translations/ca.json index b2ab15a2ace..4049cca3840 100644 --- a/homeassistant/components/transmission/translations/ca.json +++ b/homeassistant/components/transmission/translations/ca.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "Ha fallat la connexi\u00f3", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "name_exists": "Nom ja existeix", - "wrong_credentials": "Nom d'usuari o contrasenya incorrectes" + "name_exists": "Nom ja existeix" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/cs.json b/homeassistant/components/transmission/translations/cs.json index 864630a2896..8ad9e051064 100644 --- a/homeassistant/components/transmission/translations/cs.json +++ b/homeassistant/components/transmission/translations/cs.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "name_exists": "Jm\u00e9no already exists", - "wrong_credentials": "Neplatn\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no nebo heslo" + "name_exists": "Jm\u00e9no already exists" }, "step": { "user": { @@ -25,6 +24,8 @@ "step": { "init": { "data": { + "limit": "Limit", + "order": "Po\u0159ad\u00ed", "scan_interval": "Frekvence aktualizac\u00ed" }, "title": "Nakonfigurujte mo\u017enosti pro Transmission" diff --git a/homeassistant/components/transmission/translations/da.json b/homeassistant/components/transmission/translations/da.json index 469c9ba6ff6..c70bc003c85 100644 --- a/homeassistant/components/transmission/translations/da.json +++ b/homeassistant/components/transmission/translations/da.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Kunne ikke oprette forbindelse til v\u00e6rt", - "name_exists": "Navnet findes allerede", - "wrong_credentials": "Ugyldigt brugernavn eller adgangskode" + "name_exists": "Navnet findes allerede" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/de.json b/homeassistant/components/transmission/translations/de.json index a09fbba4e85..a133cd363e0 100644 --- a/homeassistant/components/transmission/translations/de.json +++ b/homeassistant/components/transmission/translations/de.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Verbindung zum Host nicht m\u00f6glich", - "name_exists": "Name existiert bereits", - "wrong_credentials": "Falscher Benutzername oder Kennwort" + "name_exists": "Name existiert bereits" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/en.json b/homeassistant/components/transmission/translations/en.json index 9f1c5cc90cc..e92e307d3bc 100644 --- a/homeassistant/components/transmission/translations/en.json +++ b/homeassistant/components/transmission/translations/en.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "Failed to connect", "invalid_auth": "Invalid authentication", - "name_exists": "Name already exists", - "wrong_credentials": "Wrong username or password" + "name_exists": "Name already exists" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/es-419.json b/homeassistant/components/transmission/translations/es-419.json index 002d03ee7d2..1e8ceea57dd 100644 --- a/homeassistant/components/transmission/translations/es-419.json +++ b/homeassistant/components/transmission/translations/es-419.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "No se puede conectar al host", - "name_exists": "El nombre ya existe", - "wrong_credentials": "Nombre de usuario o contrase\u00f1a incorrectos" + "name_exists": "El nombre ya existe" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/es.json b/homeassistant/components/transmission/translations/es.json index 62adeaa6ac7..ffa43471673 100644 --- a/homeassistant/components/transmission/translations/es.json +++ b/homeassistant/components/transmission/translations/es.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "No se pudo conectar", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "name_exists": "El nombre ya existe", - "wrong_credentials": "Nombre de usuario o contrase\u00f1a incorrectos" + "name_exists": "El nombre ya existe" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/et.json b/homeassistant/components/transmission/translations/et.json index 6107ac808e6..1329444f7cf 100644 --- a/homeassistant/components/transmission/translations/et.json +++ b/homeassistant/components/transmission/translations/et.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamise viga", - "name_exists": "Nimi on juba olemas", - "wrong_credentials": "Vale kasutajanimi v\u00f5i salas\u00f5na" + "name_exists": "Nimi on juba olemas" }, "step": { "user": { @@ -17,7 +16,20 @@ "password": "Salas\u00f5na", "port": "", "username": "Kasutajanimi" - } + }, + "title": "Seadista Transmission'i klient" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "limit": "Piirang", + "order": "J\u00e4rjekord", + "scan_interval": "V\u00e4rskendussagedus" + }, + "title": "Seadista Transmission'i valikud" } } } diff --git a/homeassistant/components/transmission/translations/fr.json b/homeassistant/components/transmission/translations/fr.json index 6bad4b15a81..45ad7968bcb 100644 --- a/homeassistant/components/transmission/translations/fr.json +++ b/homeassistant/components/transmission/translations/fr.json @@ -5,8 +5,8 @@ }, "error": { "cannot_connect": "Impossible de se connecter \u00e0 l'h\u00f4te", - "name_exists": "Ce nom est d\u00e9j\u00e0 utilis\u00e9", - "wrong_credentials": "Mauvais nom d'utilisateur ou mot de passe" + "invalid_auth": "Authentification invalide", + "name_exists": "Ce nom est d\u00e9j\u00e0 utilis\u00e9" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/hu.json b/homeassistant/components/transmission/translations/hu.json index 79fdbe9c7f0..f2fd2ca79e5 100644 --- a/homeassistant/components/transmission/translations/hu.json +++ b/homeassistant/components/transmission/translations/hu.json @@ -2,8 +2,7 @@ "config": { "error": { "cannot_connect": "Nem lehet csatlakozni az \u00e1llom\u00e1shoz", - "name_exists": "A n\u00e9v m\u00e1r l\u00e9tezik", - "wrong_credentials": "Rossz felhaszn\u00e1l\u00f3n\u00e9v vagy jelsz\u00f3" + "name_exists": "A n\u00e9v m\u00e1r l\u00e9tezik" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/it.json b/homeassistant/components/transmission/translations/it.json index daf7088ee8d..0e1cc009824 100644 --- a/homeassistant/components/transmission/translations/it.json +++ b/homeassistant/components/transmission/translations/it.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "Impossibile connettersi", "invalid_auth": "Autenticazione non valida", - "name_exists": "Nome gi\u00e0 esistente", - "wrong_credentials": "Nome utente o password non validi" + "name_exists": "Nome gi\u00e0 esistente" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/ko.json b/homeassistant/components/transmission/translations/ko.json index 5a041d8a54b..7f5d67114a1 100644 --- a/homeassistant/components/transmission/translations/ko.json +++ b/homeassistant/components/transmission/translations/ko.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "\ud638\uc2a4\ud2b8\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", - "name_exists": "\uc774\ub984\uc774 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4", - "wrong_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ub610\ub294 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" + "name_exists": "\uc774\ub984\uc774 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/lb.json b/homeassistant/components/transmission/translations/lb.json index e9afd3d58c3..4e35a966481 100644 --- a/homeassistant/components/transmission/translations/lb.json +++ b/homeassistant/components/transmission/translations/lb.json @@ -4,10 +4,9 @@ "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Kann sech net mam Server verbannen.", + "cannot_connect": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "name_exists": "Numm g\u00ebtt et schonn", - "wrong_credentials": "Falsche Benotzernumm oder Passwuert" + "name_exists": "Numm g\u00ebtt et schonn" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/nl.json b/homeassistant/components/transmission/translations/nl.json index 3f6fba583c0..8cfa9333ba4 100644 --- a/homeassistant/components/transmission/translations/nl.json +++ b/homeassistant/components/transmission/translations/nl.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Kan geen verbinding maken met host", - "name_exists": "Naam bestaat al", - "wrong_credentials": "verkeerde gebruikersnaam of wachtwoord" + "name_exists": "Naam bestaat al" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/no.json b/homeassistant/components/transmission/translations/no.json index 2abf1b2a9d7..cab8fd22659 100644 --- a/homeassistant/components/transmission/translations/no.json +++ b/homeassistant/components/transmission/translations/no.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "Tilkobling mislyktes", "invalid_auth": "Ugyldig godkjenning", - "name_exists": "Navn eksisterer allerede", - "wrong_credentials": "Feil brukernavn eller passord" + "name_exists": "Navn eksisterer allerede" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/pl.json b/homeassistant/components/transmission/translations/pl.json index 882a0762e4f..dd2b28ad65f 100644 --- a/homeassistant/components/transmission/translations/pl.json +++ b/homeassistant/components/transmission/translations/pl.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "invalid_auth": "Niepoprawne uwierzytelnienie", - "name_exists": "Nazwa ju\u017c istnieje", - "wrong_credentials": "Nieprawid\u0142owa nazwa u\u017cytkownika lub has\u0142o" + "name_exists": "Nazwa ju\u017c istnieje" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/pt-BR.json b/homeassistant/components/transmission/translations/pt-BR.json index 92921d34512..fdc42bcf303 100644 --- a/homeassistant/components/transmission/translations/pt-BR.json +++ b/homeassistant/components/transmission/translations/pt-BR.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "N\u00e3o foi poss\u00edvel conectar ao host", - "name_exists": "O nome j\u00e1 existe", - "wrong_credentials": "Nome de usu\u00e1rio ou senha incorretos" + "name_exists": "O nome j\u00e1 existe" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/pt.json b/homeassistant/components/transmission/translations/pt.json index 70b7789adee..a68c7635501 100644 --- a/homeassistant/components/transmission/translations/pt.json +++ b/homeassistant/components/transmission/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "wrong_credentials": "Nome de utilizador ou palavra passe incorretos" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/transmission/translations/ru.json b/homeassistant/components/transmission/translations/ru.json index 42b4da357fa..d1fbd592f0f 100644 --- a/homeassistant/components/transmission/translations/ru.json +++ b/homeassistant/components/transmission/translations/ru.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", - "name_exists": "\u042d\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f.", - "wrong_credentials": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c." + "name_exists": "\u042d\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f." }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/sl.json b/homeassistant/components/transmission/translations/sl.json index 90ae364c97b..e2e2a633652 100644 --- a/homeassistant/components/transmission/translations/sl.json +++ b/homeassistant/components/transmission/translations/sl.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Ni mogo\u010de vzpostaviti povezave z gostiteljem", - "name_exists": "Ime \u017ee obstaja", - "wrong_credentials": "Napa\u010dno uporabni\u0161ko ime ali geslo" + "name_exists": "Ime \u017ee obstaja" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/sv.json b/homeassistant/components/transmission/translations/sv.json index 1e485ebbbe7..848fa71de60 100644 --- a/homeassistant/components/transmission/translations/sv.json +++ b/homeassistant/components/transmission/translations/sv.json @@ -5,8 +5,7 @@ }, "error": { "cannot_connect": "Det g\u00e5r inte att ansluta till v\u00e4rden", - "name_exists": "Namnet finns redan", - "wrong_credentials": "Fel anv\u00e4ndarnamn eller l\u00f6senord" + "name_exists": "Namnet finns redan" }, "step": { "user": { diff --git a/homeassistant/components/transmission/translations/zh-Hans.json b/homeassistant/components/transmission/translations/zh-Hans.json index feebc8ea8a2..d217ccdc842 100644 --- a/homeassistant/components/transmission/translations/zh-Hans.json +++ b/homeassistant/components/transmission/translations/zh-Hans.json @@ -1,7 +1,11 @@ { "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/transmission/translations/zh-Hant.json b/homeassistant/components/transmission/translations/zh-Hant.json index f4485f347a1..fc75254a9e2 100644 --- a/homeassistant/components/transmission/translations/zh-Hant.json +++ b/homeassistant/components/transmission/translations/zh-Hant.json @@ -6,8 +6,7 @@ "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "name_exists": "\u8a72\u540d\u7a31\u5df2\u5b58\u5728", - "wrong_credentials": "\u4f7f\u7528\u8005\u540d\u7a31\u6216\u5bc6\u78bc\u932f\u8aa4" + "name_exists": "\u8a72\u540d\u7a31\u5df2\u5b58\u5728" }, "step": { "user": { diff --git a/homeassistant/components/tuya/__init__.py b/homeassistant/components/tuya/__init__.py index 9d8bb873836..64a2d203695 100644 --- a/homeassistant/components/tuya/__init__.py +++ b/homeassistant/components/tuya/__init__.py @@ -4,12 +4,17 @@ from datetime import timedelta import logging from tuyaha import TuyaApi -from tuyaha.tuyaapi import TuyaAPIException, TuyaNetException, TuyaServerException +from tuyaha.tuyaapi import ( + TuyaAPIException, + TuyaFrequentlyInvokeException, + TuyaNetException, + TuyaServerException, +) import voluptuous as vol -from homeassistant.config_entries import SOURCE_IMPORT +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_PLATFORM, CONF_USERNAME -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady import homeassistant.helpers.config_validation as cv from homeassistant.helpers.dispatcher import ( @@ -21,24 +26,30 @@ from homeassistant.helpers.event import async_track_time_interval from .const import ( CONF_COUNTRYCODE, + CONF_DISCOVERY_INTERVAL, + CONF_QUERY_DEVICE, + CONF_QUERY_INTERVAL, + DEFAULT_DISCOVERY_INTERVAL, + DEFAULT_QUERY_INTERVAL, DOMAIN, + SIGNAL_CONFIG_ENTITY, + SIGNAL_DELETE_ENTITY, + SIGNAL_UPDATE_ENTITY, TUYA_DATA, + TUYA_DEVICES_CONF, TUYA_DISCOVERY_NEW, TUYA_PLATFORMS, + TUYA_TYPE_NOT_QUERY, ) _LOGGER = logging.getLogger(__name__) +ATTR_TUYA_DEV_ID = "tuya_device_id" ENTRY_IS_SETUP = "tuya_entry_is_setup" -PARALLEL_UPDATES = 0 - SERVICE_FORCE_UPDATE = "force_update" SERVICE_PULL_DEVICES = "pull_devices" -SIGNAL_DELETE_ENTITY = "tuya_delete" -SIGNAL_UPDATE_ENTITY = "tuya_update" - TUYA_TYPE_TO_HA = { "climate": "climate", "cover": "cover", @@ -56,9 +67,9 @@ CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( { - vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_COUNTRYCODE): cv.string, + vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_PLATFORM, default="tuya"): cv.string, } ) @@ -68,6 +79,30 @@ CONFIG_SCHEMA = vol.Schema( ) +def _update_discovery_interval(hass, interval): + tuya = hass.data[DOMAIN].get(TUYA_DATA) + if not tuya: + return + + try: + tuya.discovery_interval = interval + _LOGGER.info("Tuya discovery device poll interval set to %s seconds", interval) + except ValueError as ex: + _LOGGER.warning(ex) + + +def _update_query_interval(hass, interval): + tuya = hass.data[DOMAIN].get(TUYA_DATA) + if not tuya: + return + + try: + tuya.query_interval = interval + _LOGGER.info("Tuya query device poll interval set to %s seconds", interval) + except ValueError as ex: + _LOGGER.warning(ex) + + async def async_setup(hass, config): """Set up the Tuya integration.""" @@ -82,7 +117,7 @@ async def async_setup(hass, config): return True -async def async_setup_entry(hass, entry): +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): """Set up Tuya platform.""" tuya = TuyaApi() @@ -95,7 +130,11 @@ async def async_setup_entry(hass, entry): await hass.async_add_executor_job( tuya.init, username, password, country_code, platform ) - except (TuyaNetException, TuyaServerException) as exc: + except ( + TuyaNetException, + TuyaServerException, + TuyaFrequentlyInvokeException, + ) as exc: raise ConfigEntryNotReady() from exc except TuyaAPIException as exc: @@ -107,12 +146,22 @@ async def async_setup_entry(hass, entry): hass.data[DOMAIN] = { TUYA_DATA: tuya, + TUYA_DEVICES_CONF: entry.options.copy(), TUYA_TRACKER: None, ENTRY_IS_SETUP: set(), "entities": {}, "pending": {}, + "listener": entry.add_update_listener(update_listener), } + _update_discovery_interval( + hass, entry.options.get(CONF_DISCOVERY_INTERVAL, DEFAULT_DISCOVERY_INTERVAL) + ) + + _update_query_interval( + hass, entry.options.get(CONF_QUERY_INTERVAL, DEFAULT_QUERY_INTERVAL) + ) + async def async_load_devices(device_list): """Load new devices by device_list.""" device_type_list = {} @@ -139,11 +188,13 @@ async def async_setup_entry(hass, entry): else: async_dispatcher_send(hass, TUYA_DISCOVERY_NEW.format(ha_type), dev_ids) - device_list = await hass.async_add_executor_job(tuya.get_all_devices) - await async_load_devices(device_list) + await async_load_devices(tuya.get_all_devices()) def _get_updated_devices(): - tuya.poll_devices_update() + try: + tuya.poll_devices_update() + except TuyaFrequentlyInvokeException as exc: + _LOGGER.error(exc) return tuya.get_all_devices() async def async_poll_devices_update(event_time): @@ -162,7 +213,7 @@ async def async_setup_entry(hass, entry): hass.data[DOMAIN]["entities"].pop(dev_id) hass.data[DOMAIN][TUYA_TRACKER] = async_track_time_interval( - hass, async_poll_devices_update, timedelta(minutes=5) + hass, async_poll_devices_update, timedelta(minutes=2) ) hass.services.async_register( @@ -178,7 +229,7 @@ async def async_setup_entry(hass, entry): return True -async def async_unload_entry(hass, entry): +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unloading the Tuya platforms.""" unload_ok = all( await asyncio.gather( @@ -191,10 +242,8 @@ async def async_unload_entry(hass, entry): ) ) if unload_ok: - hass.data[DOMAIN][ENTRY_IS_SETUP] = set() + hass.data[DOMAIN]["listener"]() hass.data[DOMAIN][TUYA_TRACKER]() - hass.data[DOMAIN][TUYA_TRACKER] = None - hass.data[DOMAIN][TUYA_DATA] = None hass.services.async_remove(DOMAIN, SERVICE_FORCE_UPDATE) hass.services.async_remove(DOMAIN, SERVICE_PULL_DEVICES) hass.data.pop(DOMAIN) @@ -202,20 +251,86 @@ async def async_unload_entry(hass, entry): return unload_ok +async def update_listener(hass: HomeAssistant, entry: ConfigEntry): + """Update when config_entry options update.""" + hass.data[DOMAIN][TUYA_DEVICES_CONF] = entry.options.copy() + _update_discovery_interval( + hass, entry.options.get(CONF_DISCOVERY_INTERVAL, DEFAULT_DISCOVERY_INTERVAL) + ) + _update_query_interval( + hass, entry.options.get(CONF_QUERY_INTERVAL, DEFAULT_QUERY_INTERVAL) + ) + async_dispatcher_send(hass, SIGNAL_CONFIG_ENTITY) + + +async def cleanup_device_registry(hass: HomeAssistant, device_id): + """Remove device registry entry if there are no remaining entities.""" + + device_registry = await hass.helpers.device_registry.async_get_registry() + entity_registry = await hass.helpers.entity_registry.async_get_registry() + if device_id and not hass.helpers.entity_registry.async_entries_for_device( + entity_registry, device_id + ): + device_registry.async_remove_device(device_id) + + class TuyaDevice(Entity): """Tuya base device.""" + _dev_can_query_count = 0 + def __init__(self, tuya, platform): """Init Tuya devices.""" self._tuya = tuya self._tuya_platform = platform + def _device_can_query(self): + """Check if device can also use query method.""" + dev_type = self._tuya.device_type() + return dev_type not in TUYA_TYPE_NOT_QUERY + + def _inc_device_count(self): + """Increment static variable device count.""" + if not self._device_can_query(): + return + TuyaDevice._dev_can_query_count += 1 + + def _dec_device_count(self): + """Decrement static variable device count.""" + if not self._device_can_query(): + return + TuyaDevice._dev_can_query_count -= 1 + + def _get_device_config(self): + """Get updated device options.""" + devices_config = self.hass.data[DOMAIN].get(TUYA_DEVICES_CONF) + if not devices_config: + return {} + dev_conf = devices_config.get(self.object_id, {}) + if dev_conf: + _LOGGER.debug( + "Configuration for deviceID %s: %s", self.object_id, str(dev_conf) + ) + return dev_conf + async def async_added_to_hass(self): """Call when entity is added to hass.""" - dev_id = self._tuya.object_id() - self.hass.data[DOMAIN]["entities"][dev_id] = self.entity_id - async_dispatcher_connect(self.hass, SIGNAL_DELETE_ENTITY, self._delete_callback) - async_dispatcher_connect(self.hass, SIGNAL_UPDATE_ENTITY, self._update_callback) + self.hass.data[DOMAIN]["entities"][self.object_id] = self.entity_id + self.async_on_remove( + async_dispatcher_connect( + self.hass, SIGNAL_DELETE_ENTITY, self._delete_callback + ) + ) + self.async_on_remove( + async_dispatcher_connect( + self.hass, SIGNAL_UPDATE_ENTITY, self._update_callback + ) + ) + self._inc_device_count() + + async def async_will_remove_from_hass(self): + """Call when entity is removed from hass.""" + self._dec_device_count() @property def object_id(self): @@ -252,7 +367,14 @@ class TuyaDevice(Entity): def update(self): """Refresh Tuya device data.""" - self._tuya.update() + query_dev = self.hass.data[DOMAIN][TUYA_DEVICES_CONF].get(CONF_QUERY_DEVICE, "") + use_discovery = ( + TuyaDevice._dev_can_query_count > 1 and self.object_id != query_dev + ) + try: + self._tuya.update(use_discovery=use_discovery) + except TuyaFrequentlyInvokeException as exc: + _LOGGER.error(exc) async def _delete_callback(self, dev_id): """Remove this entity.""" @@ -261,7 +383,9 @@ class TuyaDevice(Entity): await self.hass.helpers.entity_registry.async_get_registry() ) if entity_registry.async_is_registered(self.entity_id): + entity_entry = entity_registry.async_get(self.entity_id) entity_registry.async_remove(self.entity_id) + await cleanup_device_registry(self.hass, entity_entry.device_id) else: await self.async_remove() diff --git a/homeassistant/components/tuya/climate.py b/homeassistant/components/tuya/climate.py index 99939c4b9c0..6da15b0d29e 100644 --- a/homeassistant/components/tuya/climate.py +++ b/homeassistant/components/tuya/climate.py @@ -1,4 +1,7 @@ """Support for the Tuya climate devices.""" +from datetime import timedelta +import logging + from homeassistant.components.climate import ( DOMAIN as SENSOR_DOMAIN, ENTITY_ID_FORMAT, @@ -19,18 +22,30 @@ from homeassistant.components.climate.const import ( from homeassistant.const import ( ATTR_TEMPERATURE, CONF_PLATFORM, + CONF_UNIT_OF_MEASUREMENT, + PRECISION_TENTHS, PRECISION_WHOLE, TEMP_CELSIUS, TEMP_FAHRENHEIT, ) +from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from . import TuyaDevice -from .const import DOMAIN, TUYA_DATA, TUYA_DISCOVERY_NEW +from .const import ( + CONF_CURR_TEMP_DIVIDER, + CONF_MAX_TEMP, + CONF_MIN_TEMP, + CONF_TEMP_DIVIDER, + DOMAIN, + SIGNAL_CONFIG_ENTITY, + TUYA_DATA, + TUYA_DISCOVERY_NEW, +) DEVICE_TYPE = "climate" -PARALLEL_UPDATES = 0 +SCAN_INTERVAL = timedelta(seconds=15) HA_STATE_TO_TUYA = { HVAC_MODE_AUTO: "auto", @@ -43,6 +58,8 @@ TUYA_STATE_TO_HA = {value: key for key, value in HA_STATE_TO_TUYA.items()} FAN_MODES = {FAN_LOW, FAN_MEDIUM, FAN_HIGH} +_LOGGER = logging.getLogger(__name__) + async def async_setup_entry(hass, config_entry, async_add_entities): """Set up tuya sensors dynamically through tuya discovery.""" @@ -89,21 +106,59 @@ class TuyaClimateEntity(TuyaDevice, ClimateEntity): super().__init__(tuya, platform) self.entity_id = ENTITY_ID_FORMAT.format(tuya.object_id()) self.operations = [HVAC_MODE_OFF] + self._has_operation = False + self._def_hvac_mode = HVAC_MODE_AUTO + self._min_temp = None + self._max_temp = None + + @callback + def _process_config(self): + """Set device config parameter.""" + config = self._get_device_config() + if not config: + return + unit = config.get(CONF_UNIT_OF_MEASUREMENT) + if unit: + self._tuya.set_unit("FAHRENHEIT" if unit == TEMP_FAHRENHEIT else "CELSIUS") + self._tuya.temp_divider = config.get(CONF_TEMP_DIVIDER, 0) + self._tuya.curr_temp_divider = config.get(CONF_CURR_TEMP_DIVIDER, 0) + min_temp = config.get(CONF_MIN_TEMP, 0) + max_temp = config.get(CONF_MAX_TEMP, 0) + if min_temp >= max_temp: + self._min_temp = self._max_temp = None + else: + self._min_temp = min_temp + self._max_temp = max_temp async def async_added_to_hass(self): """Create operation list when add to hass.""" await super().async_added_to_hass() + self._process_config() + self.async_on_remove( + async_dispatcher_connect( + self.hass, SIGNAL_CONFIG_ENTITY, self._process_config + ) + ) + modes = self._tuya.operation_list() if modes is None: + if self._def_hvac_mode not in self.operations: + self.operations.append(self._def_hvac_mode) return for mode in modes: - if mode in TUYA_STATE_TO_HA: - self.operations.append(TUYA_STATE_TO_HA[mode]) + if mode not in TUYA_STATE_TO_HA: + continue + ha_mode = TUYA_STATE_TO_HA[mode] + if ha_mode not in self.operations: + self.operations.append(ha_mode) + self._has_operation = True @property def precision(self): """Return the precision of the system.""" + if self._tuya.has_decimal(): + return PRECISION_TENTHS return PRECISION_WHOLE @property @@ -120,6 +175,9 @@ class TuyaClimateEntity(TuyaDevice, ClimateEntity): if not self._tuya.state(): return HVAC_MODE_OFF + if not self._has_operation: + return self._def_hvac_mode + mode = self._tuya.current_operation() if mode is None: return None @@ -168,11 +226,13 @@ class TuyaClimateEntity(TuyaDevice, ClimateEntity): """Set new target operation mode.""" if hvac_mode == HVAC_MODE_OFF: self._tuya.turn_off() + return if not self._tuya.state(): self._tuya.turn_on() - self._tuya.set_operation_mode(HA_STATE_TO_TUYA.get(hvac_mode)) + if self._has_operation: + self._tuya.set_operation_mode(HA_STATE_TO_TUYA.get(hvac_mode)) @property def supported_features(self): @@ -187,9 +247,19 @@ class TuyaClimateEntity(TuyaDevice, ClimateEntity): @property def min_temp(self): """Return the minimum temperature.""" - return self._tuya.min_temp() + min_temp = ( + self._min_temp if self._min_temp is not None else self._tuya.min_temp() + ) + if min_temp is not None: + return min_temp + return super().min_temp @property def max_temp(self): """Return the maximum temperature.""" - return self._tuya.max_temp() + max_temp = ( + self._max_temp if self._max_temp is not None else self._tuya.max_temp() + ) + if max_temp is not None: + return max_temp + return super().max_temp diff --git a/homeassistant/components/tuya/config_flow.py b/homeassistant/components/tuya/config_flow.py index f00396d4405..e2048aaf7bf 100644 --- a/homeassistant/components/tuya/config_flow.py +++ b/homeassistant/components/tuya/config_flow.py @@ -6,13 +6,46 @@ from tuyaha.tuyaapi import TuyaAPIException, TuyaNetException, TuyaServerExcepti import voluptuous as vol from homeassistant import config_entries -from homeassistant.const import CONF_PASSWORD, CONF_PLATFORM, CONF_USERNAME +from homeassistant.const import ( + CONF_PASSWORD, + CONF_PLATFORM, + CONF_UNIT_OF_MEASUREMENT, + CONF_USERNAME, + ENTITY_MATCH_NONE, + TEMP_CELSIUS, + TEMP_FAHRENHEIT, +) +from homeassistant.core import callback +import homeassistant.helpers.config_validation as cv # pylint:disable=unused-import -from .const import CONF_COUNTRYCODE, DOMAIN, TUYA_PLATFORMS +from .const import ( + CONF_BRIGHTNESS_RANGE_MODE, + CONF_COUNTRYCODE, + CONF_CURR_TEMP_DIVIDER, + CONF_DISCOVERY_INTERVAL, + CONF_MAX_KELVIN, + CONF_MAX_TEMP, + CONF_MIN_KELVIN, + CONF_MIN_TEMP, + CONF_QUERY_DEVICE, + CONF_QUERY_INTERVAL, + CONF_SUPPORT_COLOR, + CONF_TEMP_DIVIDER, + CONF_TUYA_MAX_COLTEMP, + DEFAULT_DISCOVERY_INTERVAL, + DEFAULT_QUERY_INTERVAL, + DEFAULT_TUYA_MAX_COLTEMP, + DOMAIN, + TUYA_DATA, + TUYA_PLATFORMS, + TUYA_TYPE_NOT_QUERY, +) _LOGGER = logging.getLogger(__name__) +CONF_LIST_DEVICES = "list_devices" + DATA_SCHEMA_USER = vol.Schema( { vol.Required(CONF_USERNAME): str, @@ -22,6 +55,10 @@ DATA_SCHEMA_USER = vol.Schema( } ) +ERROR_DEV_MULTI_TYPE = "dev_multi_type" +ERROR_DEV_NOT_CONFIG = "dev_not_config" +ERROR_DEV_NOT_FOUND = "dev_not_found" + RESULT_AUTH_FAILED = "invalid_auth" RESULT_CONN_ERROR = "cannot_connect" RESULT_SUCCESS = "success" @@ -31,6 +68,8 @@ RESULT_LOG_MESSAGE = { RESULT_CONN_ERROR: "Connection error", } +TUYA_TYPE_CONFIG = ["climate", "light"] + class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a tuya config flow.""" @@ -46,7 +85,7 @@ class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): self._username = None self._is_import = False - def _get_entry(self): + def _save_entry(self): return self.async_create_entry( title=self._username, data={ @@ -93,7 +132,7 @@ class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): result = await self.hass.async_add_executor_job(self._try_connect) if result == RESULT_SUCCESS: - return self._get_entry() + return self._save_entry() if result != RESULT_AUTH_FAILED or self._is_import: if self._is_import: _LOGGER.error( @@ -106,3 +145,249 @@ class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): return self.async_show_form( step_id="user", data_schema=DATA_SCHEMA_USER, errors=errors ) + + @staticmethod + @callback + def async_get_options_flow(config_entry): + """Get the options flow for this handler.""" + return OptionsFlowHandler(config_entry) + + +class OptionsFlowHandler(config_entries.OptionsFlow): + """Handle a option flow for Tuya.""" + + def __init__(self, config_entry: config_entries.ConfigEntry): + """Initialize options flow.""" + self.config_entry = config_entry + self._conf_devs_id = None + self._conf_devs_option = {} + self._form_error = None + + def _get_form_error(self): + """Set the error to be shown in the options form.""" + errors = {} + if self._form_error: + errors["base"] = self._form_error + self._form_error = None + return errors + + def _get_tuya_devices_filtered(self, types, exclude_mode=False, type_prefix=True): + """Get the list of Tuya device to filtered by types.""" + config_list = {} + types_filter = set(types) + tuya = self.hass.data[DOMAIN][TUYA_DATA] + devices_list = tuya.get_all_devices() + for device in devices_list: + dev_type = device.device_type() + exclude = ( + dev_type in types_filter + if exclude_mode + else dev_type not in types_filter + ) + if exclude: + continue + dev_id = device.object_id() + if type_prefix: + dev_id = f"{dev_type}-{dev_id}" + config_list[dev_id] = f"{device.name()} ({dev_type})" + + return config_list + + def _get_device(self, dev_id): + """Get specific device from tuya library.""" + tuya = self.hass.data[DOMAIN][TUYA_DATA] + return tuya.get_device_by_id(dev_id) + + def _save_config(self, data): + """Save the updated options.""" + curr_conf = self.config_entry.options.copy() + curr_conf.update(data) + curr_conf.update(self._conf_devs_option) + + return self.async_create_entry(title="", data=curr_conf) + + async def _async_device_form(self, devs_id): + """Return configuration form for devices.""" + conf_devs_id = [] + for count, dev_id in enumerate(devs_id): + device_info = dev_id.split("-") + if count == 0: + device_type = device_info[0] + device_id = device_info[1] + elif device_type != device_info[0]: + self._form_error = ERROR_DEV_MULTI_TYPE + return await self.async_step_init() + conf_devs_id.append(device_info[1]) + + device = self._get_device(device_id) + if not device: + self._form_error = ERROR_DEV_NOT_FOUND + return await self.async_step_init() + + curr_conf = self._conf_devs_option.get( + device_id, self.config_entry.options.get(device_id, {}) + ) + + config_schema = self._get_device_schema(device_type, curr_conf, device) + if not config_schema: + self._form_error = ERROR_DEV_NOT_CONFIG + return await self.async_step_init() + + self._conf_devs_id = conf_devs_id + device_name = ( + "(multiple devices selected)" if len(conf_devs_id) > 1 else device.name() + ) + + return self.async_show_form( + step_id="device", + data_schema=config_schema, + description_placeholders={ + "device_type": device_type, + "device_name": device_name, + }, + ) + + async def async_step_init(self, user_input=None): + """Handle options flow.""" + if user_input is not None: + dev_ids = user_input.get(CONF_LIST_DEVICES) + if dev_ids: + return await self.async_step_device(None, dev_ids) + + user_input.pop(CONF_LIST_DEVICES, []) + return self._save_config(data=user_input) + + data_schema = vol.Schema( + { + vol.Optional( + CONF_DISCOVERY_INTERVAL, + default=self.config_entry.options.get( + CONF_DISCOVERY_INTERVAL, DEFAULT_DISCOVERY_INTERVAL + ), + ): vol.All(vol.Coerce(int), vol.Clamp(min=30, max=900)), + } + ) + + query_devices = self._get_tuya_devices_filtered( + TUYA_TYPE_NOT_QUERY, True, False + ) + if query_devices: + devices = {ENTITY_MATCH_NONE: "Default"} + devices.update(query_devices) + def_val = self.config_entry.options.get(CONF_QUERY_DEVICE) + if not def_val or not query_devices.get(def_val): + def_val = ENTITY_MATCH_NONE + data_schema = data_schema.extend( + { + vol.Optional( + CONF_QUERY_INTERVAL, + default=self.config_entry.options.get( + CONF_QUERY_INTERVAL, DEFAULT_QUERY_INTERVAL + ), + ): vol.All(vol.Coerce(int), vol.Clamp(min=30, max=240)), + vol.Optional(CONF_QUERY_DEVICE, default=def_val): vol.In(devices), + } + ) + + config_devices = self._get_tuya_devices_filtered(TUYA_TYPE_CONFIG, False, True) + if config_devices: + data_schema = data_schema.extend( + {vol.Optional(CONF_LIST_DEVICES): cv.multi_select(config_devices)} + ) + + return self.async_show_form( + step_id="init", + data_schema=data_schema, + errors=self._get_form_error(), + ) + + async def async_step_device(self, user_input=None, dev_ids=None): + """Handle options flow for device.""" + if dev_ids is not None: + return await self._async_device_form(dev_ids) + if user_input is not None: + for device_id in self._conf_devs_id: + self._conf_devs_option[device_id] = user_input + + return await self.async_step_init() + + def _get_device_schema(self, device_type, curr_conf, device): + """Return option schema for device.""" + if device_type == "light": + return self._get_light_schema(curr_conf, device) + if device_type == "climate": + return self._get_climate_schema(curr_conf, device) + return None + + @staticmethod + def _get_light_schema(curr_conf, device): + """Create option schema for light device.""" + min_kelvin = device.max_color_temp() + max_kelvin = device.min_color_temp() + + config_schema = vol.Schema( + { + vol.Optional( + CONF_SUPPORT_COLOR, + default=curr_conf.get(CONF_SUPPORT_COLOR, False), + ): bool, + vol.Optional( + CONF_BRIGHTNESS_RANGE_MODE, + default=curr_conf.get(CONF_BRIGHTNESS_RANGE_MODE, 0), + ): vol.In({0: "Range 1-255", 1: "Range 10-1000"}), + vol.Optional( + CONF_MIN_KELVIN, + default=curr_conf.get(CONF_MIN_KELVIN, min_kelvin), + ): vol.All(vol.Coerce(int), vol.Clamp(min=min_kelvin, max=max_kelvin)), + vol.Optional( + CONF_MAX_KELVIN, + default=curr_conf.get(CONF_MAX_KELVIN, max_kelvin), + ): vol.All(vol.Coerce(int), vol.Clamp(min=min_kelvin, max=max_kelvin)), + vol.Optional( + CONF_TUYA_MAX_COLTEMP, + default=curr_conf.get( + CONF_TUYA_MAX_COLTEMP, DEFAULT_TUYA_MAX_COLTEMP + ), + ): vol.All( + vol.Coerce(int), + vol.Clamp( + min=DEFAULT_TUYA_MAX_COLTEMP, max=DEFAULT_TUYA_MAX_COLTEMP * 10 + ), + ), + } + ) + + return config_schema + + @staticmethod + def _get_climate_schema(curr_conf, device): + """Create option schema for climate device.""" + unit = device.temperature_unit() + def_unit = TEMP_FAHRENHEIT if unit == "FAHRENHEIT" else TEMP_CELSIUS + + config_schema = vol.Schema( + { + vol.Optional( + CONF_UNIT_OF_MEASUREMENT, + default=curr_conf.get(CONF_UNIT_OF_MEASUREMENT, def_unit), + ): vol.In({TEMP_CELSIUS: "Celsius", TEMP_FAHRENHEIT: "Fahrenheit"}), + vol.Optional( + CONF_TEMP_DIVIDER, + default=curr_conf.get(CONF_TEMP_DIVIDER, 0), + ): vol.All(vol.Coerce(int), vol.Clamp(min=0)), + vol.Optional( + CONF_CURR_TEMP_DIVIDER, + default=curr_conf.get(CONF_CURR_TEMP_DIVIDER, 0), + ): vol.All(vol.Coerce(int), vol.Clamp(min=0)), + vol.Optional( + CONF_MIN_TEMP, + default=curr_conf.get(CONF_MIN_TEMP, 0), + ): int, + vol.Optional( + CONF_MAX_TEMP, + default=curr_conf.get(CONF_MAX_TEMP, 0), + ): int, + } + ) + + return config_schema diff --git a/homeassistant/components/tuya/const.py b/homeassistant/components/tuya/const.py index 4e395750b23..4f4ec342b15 100644 --- a/homeassistant/components/tuya/const.py +++ b/homeassistant/components/tuya/const.py @@ -1,10 +1,31 @@ """Constants for the Tuya integration.""" +CONF_BRIGHTNESS_RANGE_MODE = "brightness_range_mode" CONF_COUNTRYCODE = "country_code" +CONF_CURR_TEMP_DIVIDER = "curr_temp_divider" +CONF_DISCOVERY_INTERVAL = "discovery_interval" +CONF_MAX_KELVIN = "max_kelvin" +CONF_MAX_TEMP = "max_temp" +CONF_MIN_KELVIN = "min_kelvin" +CONF_MIN_TEMP = "min_temp" +CONF_QUERY_DEVICE = "query_device" +CONF_QUERY_INTERVAL = "query_interval" +CONF_SUPPORT_COLOR = "support_color" +CONF_TEMP_DIVIDER = "temp_divider" +CONF_TUYA_MAX_COLTEMP = "tuya_max_coltemp" + +DEFAULT_DISCOVERY_INTERVAL = 605 +DEFAULT_QUERY_INTERVAL = 120 +DEFAULT_TUYA_MAX_COLTEMP = 10000 DOMAIN = "tuya" +SIGNAL_CONFIG_ENTITY = "tuya_config" +SIGNAL_DELETE_ENTITY = "tuya_delete" +SIGNAL_UPDATE_ENTITY = "tuya_update" + TUYA_DATA = "tuya_data" +TUYA_DEVICES_CONF = "devices_config" TUYA_DISCOVERY_NEW = "tuya_discovery_new_{}" TUYA_PLATFORMS = { @@ -12,3 +33,5 @@ TUYA_PLATFORMS = { "smart_life": "Smart Life", "jinvoo_smart": "Jinvoo Smart", } + +TUYA_TYPE_NOT_QUERY = ["scene", "switch"] diff --git a/homeassistant/components/tuya/cover.py b/homeassistant/components/tuya/cover.py index 3c94ed6a53d..08f1d92aca5 100644 --- a/homeassistant/components/tuya/cover.py +++ b/homeassistant/components/tuya/cover.py @@ -1,4 +1,6 @@ """Support for Tuya covers.""" +from datetime import timedelta + from homeassistant.components.cover import ( DOMAIN as SENSOR_DOMAIN, ENTITY_ID_FORMAT, @@ -13,7 +15,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from . import TuyaDevice from .const import DOMAIN, TUYA_DATA, TUYA_DISCOVERY_NEW -PARALLEL_UPDATES = 0 +SCAN_INTERVAL = timedelta(seconds=15) async def async_setup_entry(hass, config_entry, async_add_entities): @@ -60,23 +62,44 @@ class TuyaCover(TuyaDevice, CoverEntity): """Init tuya cover device.""" super().__init__(tuya, platform) self.entity_id = ENTITY_ID_FORMAT.format(tuya.object_id()) + self._was_closing = False + self._was_opening = False @property def supported_features(self): """Flag supported features.""" - supported_features = SUPPORT_OPEN | SUPPORT_CLOSE if self._tuya.support_stop(): - supported_features |= SUPPORT_STOP - return supported_features + return SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP + return SUPPORT_OPEN | SUPPORT_CLOSE + + @property + def is_opening(self): + """Return if the cover is opening or not.""" + state = self._tuya.state() + if state == 1: + self._was_opening = True + self._was_closing = False + return True + return False + + @property + def is_closing(self): + """Return if the cover is closing or not.""" + state = self._tuya.state() + if state == 2: + self._was_opening = False + self._was_closing = True + return True + return False @property def is_closed(self): """Return if the cover is closed or not.""" state = self._tuya.state() - if state == 1: - return False - if state == 2: + if state != 2 and self._was_closing: return True + if state != 1 and self._was_opening: + return False return None def open_cover(self, **kwargs): @@ -89,4 +112,7 @@ class TuyaCover(TuyaDevice, CoverEntity): def stop_cover(self, **kwargs): """Stop the cover.""" + if self.is_closed is None: + self._was_opening = False + self._was_closing = False self._tuya.stop_cover() diff --git a/homeassistant/components/tuya/fan.py b/homeassistant/components/tuya/fan.py index cc8272fabba..e88349cf795 100644 --- a/homeassistant/components/tuya/fan.py +++ b/homeassistant/components/tuya/fan.py @@ -1,4 +1,6 @@ """Support for Tuya fans.""" +from datetime import timedelta + from homeassistant.components.fan import ( DOMAIN as SENSOR_DOMAIN, ENTITY_ID_FORMAT, @@ -12,7 +14,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from . import TuyaDevice from .const import DOMAIN, TUYA_DATA, TUYA_DISCOVERY_NEW -PARALLEL_UPDATES = 0 +SCAN_INTERVAL = timedelta(seconds=15) async def async_setup_entry(hass, config_entry, async_add_entities): @@ -117,7 +119,6 @@ class TuyaFanDevice(TuyaDevice, FanEntity): @property def supported_features(self) -> int: """Flag supported features.""" - supports = SUPPORT_SET_SPEED if self._tuya.support_oscillate(): - supports = supports | SUPPORT_OSCILLATE - return supports + return SUPPORT_SET_SPEED | SUPPORT_OSCILLATE + return SUPPORT_SET_SPEED diff --git a/homeassistant/components/tuya/light.py b/homeassistant/components/tuya/light.py index ee9c92221df..4602e65a4d5 100644 --- a/homeassistant/components/tuya/light.py +++ b/homeassistant/components/tuya/light.py @@ -1,4 +1,6 @@ """Support for the Tuya lights.""" +from datetime import timedelta + from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, @@ -11,13 +13,33 @@ from homeassistant.components.light import ( LightEntity, ) from homeassistant.const import CONF_PLATFORM +from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.util import color as colorutil from . import TuyaDevice -from .const import DOMAIN, TUYA_DATA, TUYA_DISCOVERY_NEW +from .const import ( + CONF_BRIGHTNESS_RANGE_MODE, + CONF_MAX_KELVIN, + CONF_MIN_KELVIN, + CONF_SUPPORT_COLOR, + CONF_TUYA_MAX_COLTEMP, + DEFAULT_TUYA_MAX_COLTEMP, + DOMAIN, + SIGNAL_CONFIG_ENTITY, + TUYA_DATA, + TUYA_DISCOVERY_NEW, +) -PARALLEL_UPDATES = 0 +SCAN_INTERVAL = timedelta(seconds=15) + +TUYA_BRIGHTNESS_RANGE0 = (1, 255) +TUYA_BRIGHTNESS_RANGE1 = (10, 1000) + +BRIGHTNESS_MODES = { + 0: TUYA_BRIGHTNESS_RANGE0, + 1: TUYA_BRIGHTNESS_RANGE1, +} async def async_setup_entry(hass, config_entry, async_add_entities): @@ -64,6 +86,49 @@ class TuyaLight(TuyaDevice, LightEntity): """Init Tuya light device.""" super().__init__(tuya, platform) self.entity_id = ENTITY_ID_FORMAT.format(tuya.object_id()) + self._min_kelvin = tuya.max_color_temp() + self._max_kelvin = tuya.min_color_temp() + + @callback + def _process_config(self): + """Set device config parameter.""" + config = self._get_device_config() + if not config: + return + + # support color config + supp_color = config.get(CONF_SUPPORT_COLOR, False) + if supp_color: + self._tuya.force_support_color() + # brightness range config + self._tuya.brightness_white_range = BRIGHTNESS_MODES.get( + config.get(CONF_BRIGHTNESS_RANGE_MODE, 0), + TUYA_BRIGHTNESS_RANGE0, + ) + # color set temp range + min_tuya = self._tuya.max_color_temp() + min_kelvin = config.get(CONF_MIN_KELVIN, min_tuya) + max_tuya = self._tuya.min_color_temp() + max_kelvin = config.get(CONF_MAX_KELVIN, max_tuya) + self._min_kelvin = min(max(min_kelvin, min_tuya), max_tuya) + self._max_kelvin = min(max(max_kelvin, self._min_kelvin), max_tuya) + # color shown temp range + max_color_temp = max( + config.get(CONF_TUYA_MAX_COLTEMP, DEFAULT_TUYA_MAX_COLTEMP), + DEFAULT_TUYA_MAX_COLTEMP, + ) + self._tuya.color_temp_range = (1000, max_color_temp) + + async def async_added_to_hass(self): + """Set config parameter when add to hass.""" + await super().async_added_to_hass() + self._process_config() + self.async_on_remove( + async_dispatcher_connect( + self.hass, SIGNAL_CONFIG_ENTITY, self._process_config + ) + ) + return @property def brightness(self): @@ -93,12 +158,12 @@ class TuyaLight(TuyaDevice, LightEntity): @property def min_mireds(self): """Return color temperature min mireds.""" - return colorutil.color_temperature_kelvin_to_mired(self._tuya.min_color_temp()) + return colorutil.color_temperature_kelvin_to_mired(self._max_kelvin) @property def max_mireds(self): """Return color temperature max mireds.""" - return colorutil.color_temperature_kelvin_to_mired(self._tuya.max_color_temp()) + return colorutil.color_temperature_kelvin_to_mired(self._min_kelvin) def turn_on(self, **kwargs): """Turn on or control the light.""" diff --git a/homeassistant/components/tuya/scene.py b/homeassistant/components/tuya/scene.py index 40f9fca11ee..430b2bc7e27 100644 --- a/homeassistant/components/tuya/scene.py +++ b/homeassistant/components/tuya/scene.py @@ -10,8 +10,6 @@ from .const import DOMAIN, TUYA_DATA, TUYA_DISCOVERY_NEW ENTITY_ID_FORMAT = SENSOR_DOMAIN + ".{}" -PARALLEL_UPDATES = 0 - async def async_setup_entry(hass, config_entry, async_add_entities): """Set up tuya sensors dynamically through tuya discovery.""" diff --git a/homeassistant/components/tuya/strings.json b/homeassistant/components/tuya/strings.json index 08123db3a36..84575906010 100644 --- a/homeassistant/components/tuya/strings.json +++ b/homeassistant/components/tuya/strings.json @@ -21,5 +21,40 @@ "error": { "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]" } + }, + "options": { + "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)", + "max_temp": "Max target temperature (use min and max = 0 for default)" + } + } + }, + "error": { + "dev_multi_type": "Multiple selected devices to configure must be of the same type", + "dev_not_config": "Device type not configurable", + "dev_not_found": "Device not found" + } } } diff --git a/homeassistant/components/tuya/switch.py b/homeassistant/components/tuya/switch.py index e4d0778cab0..3f5ff6db163 100644 --- a/homeassistant/components/tuya/switch.py +++ b/homeassistant/components/tuya/switch.py @@ -1,4 +1,6 @@ """Support for Tuya switches.""" +from datetime import timedelta + from homeassistant.components.switch import ( DOMAIN as SENSOR_DOMAIN, ENTITY_ID_FORMAT, @@ -10,7 +12,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from . import TuyaDevice from .const import DOMAIN, TUYA_DATA, TUYA_DISCOVERY_NEW -PARALLEL_UPDATES = 0 +SCAN_INTERVAL = timedelta(seconds=15) async def async_setup_entry(hass, config_entry, async_add_entities): diff --git a/homeassistant/components/tuya/translations/af.json b/homeassistant/components/tuya/translations/af.json new file mode 100644 index 00000000000..71ac741b6b8 --- /dev/null +++ b/homeassistant/components/tuya/translations/af.json @@ -0,0 +1,8 @@ +{ + "options": { + "error": { + "dev_not_config": "Ger\u00e4tetyp nicht konfigurierbar", + "dev_not_found": "Ger\u00e4t nicht gefunden" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/ca.json b/homeassistant/components/tuya/translations/ca.json index ca88e8b54a4..d891eea20a8 100644 --- a/homeassistant/components/tuya/translations/ca.json +++ b/homeassistant/components/tuya/translations/ca.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "Autenticaci\u00f3 inv\u00e0lida", "cannot_connect": "Ha fallat la connexi\u00f3", - "conn_error": "Ha fallat la connexi\u00f3", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "error": { - "auth_failed": "Autenticaci\u00f3 inv\u00e0lida", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "flow_title": "Configuraci\u00f3 de Tuya", @@ -24,5 +21,40 @@ "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)", + "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/cs.json b/homeassistant/components/tuya/translations/cs.json index 88bfb2e7322..99cf4be4fff 100644 --- a/homeassistant/components/tuya/translations/cs.json +++ b/homeassistant/components/tuya/translations/cs.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "conn_error": "Nepoda\u0159ilo se p\u0159ipojit", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "error": { - "auth_failed": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "flow_title": "Konfigurace Tuya", @@ -24,5 +21,37 @@ "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", + "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/de.json b/homeassistant/components/tuya/translations/de.json index 3108e34f11f..07e72a29609 100644 --- a/homeassistant/components/tuya/translations/de.json +++ b/homeassistant/components/tuya/translations/de.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "conn_error": "Verbindung fehlgeschlagen" - }, "flow_title": "Tuya Konfiguration", "step": { "user": { @@ -14,5 +11,11 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_not_config": "Ger\u00e4tetyp nicht konfigurierbar", + "dev_not_found": "Ger\u00e4t nicht gefunden" + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/en.json b/homeassistant/components/tuya/translations/en.json index 8b013c6c062..75c84a5337e 100644 --- a/homeassistant/components/tuya/translations/en.json +++ b/homeassistant/components/tuya/translations/en.json @@ -1,14 +1,11 @@ { "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", @@ -24,5 +21,40 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "Multiple selected devices to configure must be of the same type", + "dev_not_config": "Device type not configurable", + "dev_not_found": "Device not found" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Brightness range used by device", + "curr_temp_divider": "Current Temperature value divider (0 = use default)", + "max_kelvin": "Max color temperature supported in kelvin", + "max_temp": "Max target temperature (use min and max = 0 for default)", + "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" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/es.json b/homeassistant/components/tuya/translations/es.json index 41ab447ec8e..3107b919e5a 100644 --- a/homeassistant/components/tuya/translations/es.json +++ b/homeassistant/components/tuya/translations/es.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "Autenticaci\u00f3n no v\u00e1lida", "cannot_connect": "No se pudo conectar", - "conn_error": "No se pudo conectar", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "error": { - "auth_failed": "Autenticaci\u00f3n no v\u00e1lida", "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "flow_title": "Configuraci\u00f3n Tuya", @@ -24,5 +21,40 @@ "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)", + "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": { + "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_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" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/et.json b/homeassistant/components/tuya/translations/et.json index c7323e3c189..52f502b546f 100644 --- a/homeassistant/components/tuya/translations/et.json +++ b/homeassistant/components/tuya/translations/et.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "Viga tuvastamisel", "cannot_connect": "\u00dchendamine nurjus", - "conn_error": "\u00dchendamine nurjus", "invalid_auth": "Tuvastamise viga", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks sidumine." }, "error": { - "auth_failed": "Vigane tuvastamine", "invalid_auth": "Tuvastamise viga" }, "flow_title": "Tuya seaded", @@ -24,5 +21,40 @@ "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)", + "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)", + "tuya_max_coltemp": "Seadme teatatud maksimaalne v\u00e4rvitemperatuur", + "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_device": "Vali seade, mis kasutab oleku kiiremaks v\u00e4rskendamiseks p\u00e4ringumeetodit", + "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" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/fi.json b/homeassistant/components/tuya/translations/fi.json index a2efee7e5ec..3c74a9b8eeb 100644 --- a/homeassistant/components/tuya/translations/fi.json +++ b/homeassistant/components/tuya/translations/fi.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "conn_error": "Yhdist\u00e4minen ep\u00e4onnistui" - }, - "error": { - "auth_failed": "Virheellinen tunnistautuminen" - }, "flow_title": "Tuya-asetukset", "step": { "user": { diff --git a/homeassistant/components/tuya/translations/fr.json b/homeassistant/components/tuya/translations/fr.json index cbd71b0cbd1..e25dcb40d42 100644 --- a/homeassistant/components/tuya/translations/fr.json +++ b/homeassistant/components/tuya/translations/fr.json @@ -1,12 +1,12 @@ { "config": { "abort": { - "auth_failed": "Authentification invalide", - "conn_error": "\u00c9chec de connexion", + "cannot_connect": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide", "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { - "auth_failed": "Authentification invalide" + "invalid_auth": "Authentification invalide" }, "flow_title": "Configuration Tuya", "step": { @@ -21,5 +21,40 @@ "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)", + "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/he.json b/homeassistant/components/tuya/translations/he.json index 439a2442bad..98dafb882c7 100644 --- a/homeassistant/components/tuya/translations/he.json +++ b/homeassistant/components/tuya/translations/he.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "conn_error": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05e0\u05db\u05e9\u05dc\u05d4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tuya/translations/hu.json b/homeassistant/components/tuya/translations/hu.json index 69681ee800a..97359a9a787 100644 --- a/homeassistant/components/tuya/translations/hu.json +++ b/homeassistant/components/tuya/translations/hu.json @@ -1,13 +1,8 @@ { "config": { "abort": { - "auth_failed": "\u00c9rv\u00e9nytelen hiteles\u00edt\u00e9s", - "conn_error": "Sikertelen csatlakoz\u00e1s", "single_instance_allowed": "M\u00e1r konfigur\u00e1lva van. Csak egy konfigur\u00e1ci\u00f3 lehets\u00e9ges." }, - "error": { - "auth_failed": "\u00c9rv\u00e9nytelen hiteles\u00edt\u00e9s" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/tuya/translations/it.json b/homeassistant/components/tuya/translations/it.json index 027764d614f..1277d8fca89 100644 --- a/homeassistant/components/tuya/translations/it.json +++ b/homeassistant/components/tuya/translations/it.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "Autenticazione non valida", "cannot_connect": "Impossibile connettersi", - "conn_error": "Impossibile connettersi", "invalid_auth": "Autenticazione non valida", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "error": { - "auth_failed": "Autenticazione non valida", "invalid_auth": "Autenticazione non valida" }, "flow_title": "Configurazione di Tuya", @@ -24,5 +21,40 @@ "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)", + "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/tuya/translations/ko.json b/homeassistant/components/tuya/translations/ko.json index a028fc2ed56..e123bc2b6f9 100644 --- a/homeassistant/components/tuya/translations/ko.json +++ b/homeassistant/components/tuya/translations/ko.json @@ -1,13 +1,8 @@ { "config": { "abort": { - "auth_failed": "\uc778\uc99d\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "conn_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4", "single_instance_allowed": "\uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ud558\ub098\uc758 \uad6c\uc131\ub9cc \uac00\ub2a5\ud569\ub2c8\ub2e4." }, - "error": { - "auth_failed": "\uc778\uc99d\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "flow_title": "Tuya \uad6c\uc131\ud558\uae30", "step": { "user": { diff --git a/homeassistant/components/tuya/translations/lb.json b/homeassistant/components/tuya/translations/lb.json index db47c64ce11..884eb328fe4 100644 --- a/homeassistant/components/tuya/translations/lb.json +++ b/homeassistant/components/tuya/translations/lb.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "Ong\u00eblteg Authentifikatioun", "cannot_connect": "Feeler beim verbannen", - "conn_error": "Feeler beim verbannen", "invalid_auth": "Ong\u00eblteg Authentifikatioun", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "error": { - "auth_failed": "Ong\u00eblteg Authentifikatioun", "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "flow_title": "Tuya Konfiguratioun", @@ -24,5 +21,36 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "Multiple ausgewielte Ger\u00e4ter fir ze konfigur\u00e9ieren musse vum selwechten Typ sinn", + "dev_not_config": "Typ vun Apparat net konfigur\u00e9ierbar", + "dev_not_found": "Apparat net fonnt" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Hellegkeetsber\u00e4ich vum Apparat", + "curr_temp_divider": "Aktuell Temperatur W\u00e4erter Deeler (0= benotz Standard)", + "max_kelvin": "Maximal Faarftemperatur \u00ebnnerst\u00ebtzt a Kelvin", + "max_temp": "Maximal Zil Temperatur (benotz min a max = 0 fir standard)", + "min_kelvin": "Minimal Faarftemperatur \u00ebnnerst\u00ebtzt a Kelvin", + "min_temp": "Minimal Zil Temperatur (benotz min a max = 0 fir standard)", + "support_color": "Forc\u00e9ier Faarf \u00cbnnerst\u00ebtzung", + "temp_divider": "Temperatur W\u00e4erter Deeler (0= benotz Standard)", + "tuya_max_coltemp": "Max Faarftemperatur vum Apparat gemellt", + "unit_of_measurement": "Temperatur Eenheet vum Apparat" + }, + "description": "Konfigur\u00e9ier Optioune fir ugewisen Informatioune fir {device_type} Apparat `{device_name}` unzepassen", + "title": "Tuya Apparat ariichten" + }, + "init": { + "data": { + "list_devices": "Wiel d'Apparater fir ze konfigur\u00e9ieren aus oder loss se eidel fir d'Konfiguratioun ze sp\u00e4icheren" + }, + "title": "Tuya Optioune konfigur\u00e9ieren" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/nl.json b/homeassistant/components/tuya/translations/nl.json index f513168a9e1..5a0e3691d5b 100644 --- a/homeassistant/components/tuya/translations/nl.json +++ b/homeassistant/components/tuya/translations/nl.json @@ -1,14 +1,9 @@ { "config": { "abort": { - "auth_failed": "Verkeerde gegevens", "cannot_connect": "Kan geen verbinding maken", - "conn_error": "Niet gelukt om te verbinden.", "single_instance_allowed": "Al geconfigureerd. Er is maar een configuratie mogelijk." }, - "error": { - "auth_failed": "Verkeerde gegevens" - }, "flow_title": "Tuya-configuratie", "step": { "user": { @@ -22,5 +17,12 @@ "title": "Tuya" } } + }, + "options": { + "step": { + "init": { + "title": "Configureer Tuya opties" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/no.json b/homeassistant/components/tuya/translations/no.json index b2245361e9c..38f054ae4c4 100644 --- a/homeassistant/components/tuya/translations/no.json +++ b/homeassistant/components/tuya/translations/no.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "Ugyldig godkjenning", "cannot_connect": "Tilkobling mislyktes", - "conn_error": "Tilkobling mislyktes", "invalid_auth": "Ugyldig godkjenning", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "error": { - "auth_failed": "Ugyldig godkjenning", "invalid_auth": "Ugyldig godkjenning" }, "flow_title": "Tuya konfigurasjon", @@ -24,5 +21,40 @@ "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)", + "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/pl.json b/homeassistant/components/tuya/translations/pl.json index 3e7b62d21ea..ba4810c3f96 100644 --- a/homeassistant/components/tuya/translations/pl.json +++ b/homeassistant/components/tuya/translations/pl.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "Niepoprawne uwierzytelnienie", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "conn_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "invalid_auth": "Niepoprawne uwierzytelnienie", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "error": { - "auth_failed": "Niepoprawne uwierzytelnienie", "invalid_auth": "Niepoprawne uwierzytelnienie" }, "flow_title": "Konfiguracja integracji Tuya", @@ -24,5 +21,40 @@ "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)", + "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/tuya/translations/ru.json b/homeassistant/components/tuya/translations/ru.json index bdb3ad91c35..31e2791c9f4 100644 --- a/homeassistant/components/tuya/translations/ru.json +++ b/homeassistant/components/tuya/translations/ru.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "conn_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "error": { - "auth_failed": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "flow_title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Tuya", @@ -24,5 +21,40 @@ "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)", + "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/sv.json b/homeassistant/components/tuya/translations/sv.json index 762baa2af63..85cc9c57fd3 100644 --- a/homeassistant/components/tuya/translations/sv.json +++ b/homeassistant/components/tuya/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "auth_failed": "Ogiltig anv\u00e4ndarinformation" - }, "flow_title": "Tuya-konfiguration", "step": { "user": { diff --git a/homeassistant/components/tuya/translations/tr.json b/homeassistant/components/tuya/translations/tr.json new file mode 100644 index 00000000000..d2af1633f99 --- /dev/null +++ b/homeassistant/components/tuya/translations/tr.json @@ -0,0 +1,13 @@ +{ + "options": { + "step": { + "init": { + "data": { + "query_interval": "Ayg\u0131t yoklama aral\u0131\u011f\u0131 saniye cinsinden" + }, + "description": "Yoklama aral\u0131\u011f\u0131 de\u011ferlerini \u00e7ok d\u00fc\u015f\u00fck ayarlamay\u0131n, aksi takdirde \u00e7a\u011fr\u0131lar g\u00fcnl\u00fckte hata mesaj\u0131 olu\u015fturarak ba\u015far\u0131s\u0131z olur", + "title": "Tuya Se\u00e7eneklerini Konfig\u00fcre Et" + } + } + } +} \ 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 a667ac76b15..f2fb4c0926c 100644 --- a/homeassistant/components/tuya/translations/zh-Hant.json +++ b/homeassistant/components/tuya/translations/zh-Hant.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "auth_failed": "\u9a57\u8b49\u78bc\u7121\u6548", "cannot_connect": "\u9023\u7dda\u5931\u6557", - "conn_error": "\u9023\u7dda\u5931\u6557", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "error": { - "auth_failed": "\u9a57\u8b49\u78bc\u7121\u6548", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "flow_title": "Tuya \u8a2d\u5b9a", @@ -24,5 +21,40 @@ "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", + "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/twentemilieu/translations/bg.json b/homeassistant/components/twentemilieu/translations/bg.json index bff7e40f8ce..8844b6124e0 100644 --- a/homeassistant/components/twentemilieu/translations/bg.json +++ b/homeassistant/components/twentemilieu/translations/bg.json @@ -1,10 +1,6 @@ { "config": { - "abort": { - "address_exists": "\u0410\u0434\u0440\u0435\u0441\u044a\u0442 \u0432\u0435\u0447\u0435 \u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d." - }, "error": { - "connection_error": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435.", "invalid_address": "\u0410\u0434\u0440\u0435\u0441\u044a\u0442 \u043d\u0435 \u0435 \u043d\u0430\u043c\u0435\u0440\u0435\u043d \u0432 \u0437\u043e\u043d\u0430 \u0437\u0430 \u043e\u0431\u0441\u043b\u0443\u0436\u0432\u0430\u043d\u0435 \u043d\u0430 Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/ca.json b/homeassistant/components/twentemilieu/translations/ca.json index 6c97b4bd83d..6c1469f16c1 100644 --- a/homeassistant/components/twentemilieu/translations/ca.json +++ b/homeassistant/components/twentemilieu/translations/ca.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "Adre\u00e7a ja configurada.", "already_configured": "La ubicaci\u00f3 ja est\u00e0 configurada" }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar.", "invalid_address": "No s'ha trobat l'adre\u00e7a a l'\u00e0rea de servei de Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/cs.json b/homeassistant/components/twentemilieu/translations/cs.json index 58c5185f6aa..708796d04c5 100644 --- a/homeassistant/components/twentemilieu/translations/cs.json +++ b/homeassistant/components/twentemilieu/translations/cs.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "Adresa je ji\u017e nastavena.", "already_configured": "Um\u00edst\u011bn\u00ed je ji\u017e nastaveno" }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "Nepoda\u0159ilo se p\u0159ipojit." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "user": { diff --git a/homeassistant/components/twentemilieu/translations/da.json b/homeassistant/components/twentemilieu/translations/da.json index 23dfbb372ed..e1c9b6024ad 100644 --- a/homeassistant/components/twentemilieu/translations/da.json +++ b/homeassistant/components/twentemilieu/translations/da.json @@ -1,10 +1,6 @@ { "config": { - "abort": { - "address_exists": "Adresse er allerede konfigureret." - }, "error": { - "connection_error": "Forbindelse mislykkedes.", "invalid_address": "Adresse ikke fundet i Twente Milieu serviceomr\u00e5de." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/de.json b/homeassistant/components/twentemilieu/translations/de.json index 8a1bf403940..2ae8c2863af 100644 --- a/homeassistant/components/twentemilieu/translations/de.json +++ b/homeassistant/components/twentemilieu/translations/de.json @@ -1,10 +1,6 @@ { "config": { - "abort": { - "address_exists": "Adresse bereits eingerichtet." - }, "error": { - "connection_error": "Fehler beim Herstellen einer Verbindung.", "invalid_address": "Adresse nicht im Einzugsgebiet von Twente Milieu gefunden." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/en.json b/homeassistant/components/twentemilieu/translations/en.json index 1f96f5f2fad..fdc4023f89b 100644 --- a/homeassistant/components/twentemilieu/translations/en.json +++ b/homeassistant/components/twentemilieu/translations/en.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "Address already set up.", "already_configured": "Location is already configured" }, "error": { "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect.", "invalid_address": "Address not found in Twente Milieu service area." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/es-419.json b/homeassistant/components/twentemilieu/translations/es-419.json index 6f190ba503c..8adddffd407 100644 --- a/homeassistant/components/twentemilieu/translations/es-419.json +++ b/homeassistant/components/twentemilieu/translations/es-419.json @@ -1,10 +1,6 @@ { "config": { - "abort": { - "address_exists": "Direcci\u00f3n ya configurada." - }, "error": { - "connection_error": "Error al conectar.", "invalid_address": "Direcci\u00f3n no encontrada en el \u00e1rea de servicio de Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/es.json b/homeassistant/components/twentemilieu/translations/es.json index f557ddc77cf..cf8410c55ad 100644 --- a/homeassistant/components/twentemilieu/translations/es.json +++ b/homeassistant/components/twentemilieu/translations/es.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "Direcci\u00f3n ya configurada.", "already_configured": "La ubicaci\u00f3n ya est\u00e1 configurada" }, "error": { "cannot_connect": "No se pudo conectar", - "connection_error": "No se conect\u00f3.", "invalid_address": "Direcci\u00f3n no encontrada en el \u00e1rea de servicio de Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/et.json b/homeassistant/components/twentemilieu/translations/et.json index 43b7989a125..a77657d19ff 100644 --- a/homeassistant/components/twentemilieu/translations/et.json +++ b/homeassistant/components/twentemilieu/translations/et.json @@ -5,10 +5,16 @@ }, "error": { "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "\u00dchenduse loomine nurjus" + "invalid_address": "Aadress ei kuuluTwente Milieu teeninduspiirkondat." }, "step": { "user": { + "data": { + "house_letter": "Maja numbri laiendus", + "house_number": "Maja number", + "post_code": "Sihtnumber" + }, + "description": "Seadista Twente Milieu, mis pakub j\u00e4\u00e4tmekogumist teie aadressil.", "title": "" } } diff --git a/homeassistant/components/twentemilieu/translations/fr.json b/homeassistant/components/twentemilieu/translations/fr.json index bbdd8f92d7b..6530216a5a4 100644 --- a/homeassistant/components/twentemilieu/translations/fr.json +++ b/homeassistant/components/twentemilieu/translations/fr.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "address_exists": "Adresse d\u00e9j\u00e0 configur\u00e9e." + "already_configured": "L'emplacement est d\u00e9j\u00e0 configur\u00e9" }, "error": { - "connection_error": "\u00c9chec de connexion.", + "cannot_connect": "\u00c9chec de connexion", "invalid_address": "Adresse introuvable dans la zone de service de Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/hu.json b/homeassistant/components/twentemilieu/translations/hu.json index 439e02d1027..8f88f82f2e5 100644 --- a/homeassistant/components/twentemilieu/translations/hu.json +++ b/homeassistant/components/twentemilieu/translations/hu.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "address_exists": "A c\u00edm m\u00e1r be lett \u00e1ll\u00edtva." - }, - "error": { - "connection_error": "Nem siker\u00fclt csatlakozni." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/twentemilieu/translations/it.json b/homeassistant/components/twentemilieu/translations/it.json index 939a0495992..886f0dd2ffd 100644 --- a/homeassistant/components/twentemilieu/translations/it.json +++ b/homeassistant/components/twentemilieu/translations/it.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "Indirizzo gi\u00e0 impostato.", "already_configured": "La posizione \u00e8 gi\u00e0 configurata" }, "error": { "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi.", "invalid_address": "Indirizzo non trovato nell'area di servizio di Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/ko.json b/homeassistant/components/twentemilieu/translations/ko.json index 1f3359ca184..3efc227abf7 100644 --- a/homeassistant/components/twentemilieu/translations/ko.json +++ b/homeassistant/components/twentemilieu/translations/ko.json @@ -1,10 +1,6 @@ { "config": { - "abort": { - "address_exists": "\uc8fc\uc18c\uac00 \uc774\ubbf8 \uc124\uc815\ub418\uc5c8\uc2b5\ub2c8\ub2e4." - }, "error": { - "connection_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.", "invalid_address": "Twente Milieu \uc11c\ube44\uc2a4 \uc9c0\uc5ed\uc5d0\uc11c \uc8fc\uc18c\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/lb.json b/homeassistant/components/twentemilieu/translations/lb.json index 8af5df35f1d..98454f62dbb 100644 --- a/homeassistant/components/twentemilieu/translations/lb.json +++ b/homeassistant/components/twentemilieu/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "address_exists": "Adresse ass scho ageriicht." + "already_configured": "Standuert ass scho konfigur\u00e9iert" }, "error": { - "connection_error": "Feeler beim verbannen.", + "cannot_connect": "Feeler beim verbannen", "invalid_address": "Adresse net am Twente Milieu Service Ber\u00e4ich fonnt" }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/nl.json b/homeassistant/components/twentemilieu/translations/nl.json index 32177d590f4..ca5abd7e37c 100644 --- a/homeassistant/components/twentemilieu/translations/nl.json +++ b/homeassistant/components/twentemilieu/translations/nl.json @@ -1,10 +1,9 @@ { "config": { "abort": { - "address_exists": "Adres al ingesteld." + "already_configured": "Locatie is al geconfigureerd" }, "error": { - "connection_error": "Kon niet verbinden.", "invalid_address": "Adres niet gevonden in servicegebied Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/no.json b/homeassistant/components/twentemilieu/translations/no.json index 05cdee7504a..ea7df786247 100644 --- a/homeassistant/components/twentemilieu/translations/no.json +++ b/homeassistant/components/twentemilieu/translations/no.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "Adressen er allerede satt opp.", "already_configured": "Plasseringen er allerede konfigurert" }, "error": { "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Tilkobling mislyktes.", "invalid_address": "Adresse ble ikke funnet i Twente Milieu tjenesteomr\u00e5de." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/pl.json b/homeassistant/components/twentemilieu/translations/pl.json index 33d03480310..67f2d2b362b 100644 --- a/homeassistant/components/twentemilieu/translations/pl.json +++ b/homeassistant/components/twentemilieu/translations/pl.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "Adres jest ju\u017c skonfigurowany", "already_configured": "Lokalizacja jest ju\u017c skonfigurowana" }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "invalid_address": "Nie znaleziono adresu w obszarze us\u0142ugi Twente Milieu" }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/pt-BR.json b/homeassistant/components/twentemilieu/translations/pt-BR.json index 127f0241a3f..cc71ffde0e8 100644 --- a/homeassistant/components/twentemilieu/translations/pt-BR.json +++ b/homeassistant/components/twentemilieu/translations/pt-BR.json @@ -1,10 +1,6 @@ { "config": { - "abort": { - "address_exists": "Endere\u00e7o j\u00e1 configurado." - }, "error": { - "connection_error": "Falha ao conectar.", "invalid_address": "Endere\u00e7o n\u00e3o encontrado na \u00e1rea de servi\u00e7o de Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/pt.json b/homeassistant/components/twentemilieu/translations/pt.json deleted file mode 100644 index 3d982a98998..00000000000 --- a/homeassistant/components/twentemilieu/translations/pt.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "error": { - "connection_error": "Falha na liga\u00e7\u00e3o" - } - } -} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/translations/ru.json b/homeassistant/components/twentemilieu/translations/ru.json index 8a222657c6c..f7da9b628fd 100644 --- a/homeassistant/components/twentemilieu/translations/ru.json +++ b/homeassistant/components/twentemilieu/translations/ru.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "\u0410\u0434\u0440\u0435\u0441 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d.", "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.", "invalid_address": "\u0410\u0434\u0440\u0435\u0441 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0432 \u0437\u043e\u043d\u0435 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/sl.json b/homeassistant/components/twentemilieu/translations/sl.json index 00c8a01e3b9..affe8269613 100644 --- a/homeassistant/components/twentemilieu/translations/sl.json +++ b/homeassistant/components/twentemilieu/translations/sl.json @@ -1,10 +1,6 @@ { "config": { - "abort": { - "address_exists": "Naslov je \u017ee nastavljen." - }, "error": { - "connection_error": "Povezava ni uspela.", "invalid_address": "V storitvenem obmo\u010dju Twente Milieu ni mogo\u010de najti naslova." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/sv.json b/homeassistant/components/twentemilieu/translations/sv.json index f3a60a56c99..fa1481f7e10 100644 --- a/homeassistant/components/twentemilieu/translations/sv.json +++ b/homeassistant/components/twentemilieu/translations/sv.json @@ -1,10 +1,6 @@ { "config": { - "abort": { - "address_exists": "Adressen har redan st\u00e4llts in." - }, "error": { - "connection_error": "Det gick inte att ansluta.", "invalid_address": "Adress hittades inte i serviceomr\u00e5det Twente Milieu." }, "step": { diff --git a/homeassistant/components/twentemilieu/translations/tr.json b/homeassistant/components/twentemilieu/translations/tr.json deleted file mode 100644 index ebe13a37003..00000000000 --- a/homeassistant/components/twentemilieu/translations/tr.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "abort": { - "address_exists": "Adres zaten kurulmu\u015f." - } - } -} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/translations/zh-Hans.json b/homeassistant/components/twentemilieu/translations/zh-Hans.json index 507422c7355..2941dfd9383 100644 --- a/homeassistant/components/twentemilieu/translations/zh-Hans.json +++ b/homeassistant/components/twentemilieu/translations/zh-Hans.json @@ -1,11 +1,7 @@ { "config": { - "abort": { - "address_exists": "\u5730\u5740\u5df2\u7ecf\u8bbe\u7f6e\u597d\u4e86\u3002" - }, "error": { - "cannot_connect": "\u8fde\u63a5\u5931\u8d25", - "connection_error": "\u8fde\u63a5\u5931\u8d25\u3002" + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" } } } \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/translations/zh-Hant.json b/homeassistant/components/twentemilieu/translations/zh-Hant.json index 1a20f1ba1ac..11cf62d2d60 100644 --- a/homeassistant/components/twentemilieu/translations/zh-Hant.json +++ b/homeassistant/components/twentemilieu/translations/zh-Hant.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "address_exists": "\u5730\u5740\u5df2\u8a2d\u5b9a\u3002", "already_configured": "\u5ea7\u6a19\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "\u9023\u7dda\u5931\u6557\u3002", "invalid_address": "Twente Milieu \u670d\u52d9\u5340\u57df\u5167\u627e\u4e0d\u5230\u6b64\u5730\u5740\u3002" }, "step": { diff --git a/homeassistant/components/twilio/strings.json b/homeassistant/components/twilio/strings.json index 0480fdae7c8..ad91271f160 100644 --- a/homeassistant/components/twilio/strings.json +++ b/homeassistant/components/twilio/strings.json @@ -3,12 +3,12 @@ "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": { "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive Twilio messages." + "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]" }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup [Webhooks with Twilio]({twilio_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data." diff --git a/homeassistant/components/twilio/translations/bg.json b/homeassistant/components/twilio/translations/bg.json index 0bf90ce427b..4ea3d470281 100644 --- a/homeassistant/components/twilio/translations/bg.json +++ b/homeassistant/components/twilio/translations/bg.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Home Assistant \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u0435\u043d \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0432\u0430 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 Twilio.", - "one_instance_allowed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f." - }, "create_entry": { "default": "\u0417\u0430 \u0434\u0430 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u0442\u0435 \u0441\u044a\u0431\u0438\u0442\u0438\u044f \u0434\u043e Home Assistant, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 [Webhooks \u0441 Twilio]({twilio_url}). \n\n\u041f\u043e\u043f\u044a\u043b\u043d\u0435\u0442\u0435 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: \n\n - URL: `{webhook_url}` \n - Method: POST \n - Content Type: application/x-www-form-urlencoded\n\n\u0412\u0438\u0436\u0442\u0435 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430]({docs_url}) \u0437\u0430 \u0442\u043e\u0432\u0430 \u043a\u0430\u043a \u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0442\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438\u0442\u0435 \u0437\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0430 \u0432\u0445\u043e\u0434\u044f\u0449\u0438 \u0434\u0430\u043d\u043d\u0438." }, diff --git a/homeassistant/components/twilio/translations/ca.json b/homeassistant/components/twilio/translations/ca.json index b4adcdb1cb4..22c5e00a8e7 100644 --- a/homeassistant/components/twilio/translations/ca.json +++ b/homeassistant/components/twilio/translations/ca.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de Twilio.", - "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia.", - "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." + "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3.", + "webhook_not_internet_accessible": "La teva inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per poder rebre missatges webhook." }, "create_entry": { "default": "Per enviar esdeveniments a Home Assistant, haur\u00e0s de configurar [Webhooks amb Twilio]({twilio_url}).\n\nCompleta la seg\u00fcent informaci\u00f3 : \n\n- URL: `{webhook_url}` \n- M\u00e8tode: POST \n- Tipus de contingut: application/x-www-form-urlencoded\n\nConsulta la [documentaci\u00f3]({docs_url}) sobre com configurar les automatitzacions per gestionar dades entrants." }, "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 1b5acf21077..f45c4bf881e 100644 --- a/homeassistant/components/twilio/translations/cs.json +++ b/homeassistant/components/twilio/translations/cs.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "V\u00e1\u0161 Home Asistent mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy od Twilio.", - "one_instance_allowed": "Povolena je pouze jedna instance.", - "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." + "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace.", + "webhook_not_internet_accessible": "V\u00e1\u0161 Home Assistant mus\u00ed b\u00fdt p\u0159\u00edstupn\u00fd z internetu, aby mohl p\u0159ij\u00edmat zpr\u00e1vy webhook." }, "create_entry": { - "default": "Chcete-li odeslat ud\u00e1losti do aplikace Home Assistant, mus\u00edte nastavit [Webhooks s Twilio]({twilio_url}). \n\n Vypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: `{webhook_url}' \n - Metoda: POST \n - Typ obsahu: application/x-www-form-urlencoded \n\n Viz [dokumentace]({docs_url}), jak konfigurovat automatizace pro zpracov\u00e1n\u00ed p\u0159\u00edchoz\u00edch dat." + "default": "Chcete-li odeslat ud\u00e1losti do aplikace Home Assistant, mus\u00edte nastavit [Webhooks s Twilio]({twilio_url}). \n\nVypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: `{webhook_url}' \n - Metoda: POST \n - Typ obsahu: application/x-www-form-urlencoded \n\nViz [dokumentace]({docs_url}), jak konfigurovat automatizace pro zpracov\u00e1n\u00ed p\u0159\u00edchoz\u00edch dat." }, "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/da.json b/homeassistant/components/twilio/translations/da.json index 0e89342bb0e..1bb167620c7 100644 --- a/homeassistant/components/twilio/translations/da.json +++ b/homeassistant/components/twilio/translations/da.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant-instans skal v\u00e6re tilg\u00e6ngelig fra internettet for at modtage Twilio-meddelelser.", - "one_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning." - }, "create_entry": { "default": "For at sende h\u00e6ndelser til Home Assistant skal du konfigurere [Webhooks med Twilio]({twilio_url}).\n\n Udfyld f\u00f8lgende oplysninger: \n\n - Webadresse: `{webhook_url}`\n - Metode: POST\n - Indholdstype: application/x-www-form-urlencoded\n\nSe [dokumentationen]({docs_url}) om hvordan du konfigurerer automatiseringer til at h\u00e5ndtere indg\u00e5ende data." }, diff --git a/homeassistant/components/twilio/translations/de.json b/homeassistant/components/twilio/translations/de.json index 07860456754..864fee4c238 100644 --- a/homeassistant/components/twilio/translations/de.json +++ b/homeassistant/components/twilio/translations/de.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Ihre Home Assistant-Instanz muss \u00fcber das Internet erreichbar sein, um Twilio-Nachrichten empfangen zu k\u00f6nnen.", - "one_instance_allowed": "Es ist nur eine einzige Instanz erforderlich." - }, "create_entry": { "default": "Um Ereignisse an den Home Assistant zu senden, musst du [Webhooks mit Twilio]({twilio_url}) einrichten. \n\n F\u00fclle die folgenden Informationen aus: \n\n - URL: ` {webhook_url} ` \n - Methode: POST \n - Inhaltstyp: application / x-www-form-urlencoded \n\nLies in der [Dokumentation]({docs_url}) wie du Automationen f\u00fcr die Verarbeitung eingehender Daten konfigurierst." }, diff --git a/homeassistant/components/twilio/translations/en.json b/homeassistant/components/twilio/translations/en.json index de5d921dec2..953b807c081 100644 --- a/homeassistant/components/twilio/translations/en.json +++ b/homeassistant/components/twilio/translations/en.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive Twilio messages.", - "one_instance_allowed": "Only a single instance is necessary.", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "single_instance_allowed": "Already configured. Only a single configuration possible.", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages." }, "create_entry": { "default": "To send events to Home Assistant, you will need to setup [Webhooks with Twilio]({twilio_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data." }, "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/es-419.json b/homeassistant/components/twilio/translations/es-419.json index f2772383104..278742df1a7 100644 --- a/homeassistant/components/twilio/translations/es-419.json +++ b/homeassistant/components/twilio/translations/es-419.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Su instancia de Home Assistant debe ser accesible desde Internet para recibir los mensajes de Twilio.", - "one_instance_allowed": "Solo una instancia es necesaria." - }, "create_entry": { "default": "Para enviar eventos a Home Assistant, deber\u00e1 configurar [Webhooks with Twilio] ( {twilio_url} ). \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n - Tipo de contenido: application / x-www-form-urlencoded \n\n Consulte [la documentaci\u00f3n] ( {docs_url} ) sobre c\u00f3mo configurar las automatizaciones para manejar los datos entrantes." }, diff --git a/homeassistant/components/twilio/translations/es.json b/homeassistant/components/twilio/translations/es.json index b7ba037eef6..46499faca59 100644 --- a/homeassistant/components/twilio/translations/es.json +++ b/homeassistant/components/twilio/translations/es.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Tu instancia de Home Assistant debe ser accesible desde Internet para recibir mensajes de Twilio.", - "one_instance_allowed": "Solo es necesaria una instancia.", - "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." + "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n.", + "webhook_not_internet_accessible": "Tu instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes webhook." }, "create_entry": { "default": "Para enviar eventos a Home Assistant debes configurar los [Webhooks en Twilio]({twilio_url}). \n\n Completa la siguiente informaci\u00f3n: \n\n - URL: `{webhook_url}` \n - M\u00e9todo: POST \n - Tipo de contenido: application/x-www-form-urlencoded \n\nConsulta [la documentaci\u00f3n]({docs_url}) sobre c\u00f3mo configurar las automatizaciones para manejar los datos entrantes." diff --git a/homeassistant/components/twilio/translations/et.json b/homeassistant/components/twilio/translations/et.json index faa0ab7769e..3d06e7f1db0 100644 --- a/homeassistant/components/twilio/translations/et.json +++ b/homeassistant/components/twilio/translations/et.json @@ -1,12 +1,16 @@ { "config": { "abort": { - "one_instance_allowed": "Lubatud on ainult \u00fcks sidumine.", - "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine.", + "webhook_not_internet_accessible": "Veebikonksu s\u00f5numite vastuv\u00f5tmiseks peab Home Assistant olema Interneti kaudu juurdep\u00e4\u00e4setav." + }, + "create_entry": { + "default": "S\u00fcndmuste saatmiseks Home Assistantile pead seadistama [Webhooks with Twilio] ( {twilio_url} ).\n\n Sisesta j\u00e4rgmine teave:\n\n - URL: \" {webhook_url} \"\n - Meetod: POST\n - Sisu t\u00fc\u00fcp: application/x-www-form-urlencoded\n\n Vaata [documentation] ( {docs_url} ) kuidas seadistada automatiseeringud sissetulevate andmete k\u00e4itlemiseks." }, "step": { "user": { - "description": "Kas soovid Twilio-t seadistada?" + "description": "Kas soovid seadistada Twilio-t?", + "title": "Seadista Twilio Webhook" } } } diff --git a/homeassistant/components/twilio/translations/fr.json b/homeassistant/components/twilio/translations/fr.json index 3136fb53974..cfd4d9813c8 100644 --- a/homeassistant/components/twilio/translations/fr.json +++ b/homeassistant/components/twilio/translations/fr.json @@ -1,9 +1,8 @@ { "config": { "abort": { - "not_internet_accessible": "Votre instance de Home Assistant doit \u00eatre accessible depuis Internet pour recevoir les messages Twilio.", - "one_instance_allowed": "Une seule instance est n\u00e9cessaire.", - "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "webhook_not_internet_accessible": "Votre installation de Home Assistant doit \u00eatre accessible depuis internet pour recevoir des messages webhook." }, "create_entry": { "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez configurer [Webhooks avec Twilio] ( {twilio_url} ). \n\n Remplissez les informations suivantes: \n\n - URL: ` {webhook_url} ` \n - M\u00e9thode: POST \n - Type de contenu: application / x-www-form-urlencoded \n\n Voir [la documentation] ( {docs_url} ) pour savoir comment configurer les automatisations pour g\u00e9rer les donn\u00e9es entrantes." diff --git a/homeassistant/components/twilio/translations/hu.json b/homeassistant/components/twilio/translations/hu.json index 92e797917ed..f68f610bf2f 100644 --- a/homeassistant/components/twilio/translations/hu.json +++ b/homeassistant/components/twilio/translations/hu.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A Home Assistant rendszerednek el\u00e9rhet\u0151nek kell lennie az internetr\u0151l a Twilio \u00fczenetek fogad\u00e1s\u00e1hoz.", - "one_instance_allowed": "Csak egyetlen konfigur\u00e1ci\u00f3 sz\u00fcks\u00e9ges." - }, "step": { "user": { "description": "Biztosan be szeretn\u00e9d \u00e1ll\u00edtani a Twilio-t?", diff --git a/homeassistant/components/twilio/translations/it.json b/homeassistant/components/twilio/translations/it.json index ee7ed374cea..a4fe3efcaa2 100644 --- a/homeassistant/components/twilio/translations/it.json +++ b/homeassistant/components/twilio/translations/it.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "La tua istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi da Twilio.", - "one_instance_allowed": "\u00c8 necessaria una sola istanza.", - "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." + "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione.", + "webhook_not_internet_accessible": "L'istanza di Home Assistant deve essere accessibile da Internet per ricevere messaggi webhook." }, "create_entry": { "default": "Per inviare eventi a Home Assistant, dovrai configurare [Webhooks con Twilio]({twilio_url})\n\n Compila le seguenti informazioni: \n\n - URL: `{webhook_url}` \n - Method: POST \n - Content Type: application/x-www-form-urlencoded\n\n Vedi [la documentazione]({docs_url}) su come configurare le automazioni per gestire i dati in arrivo." }, "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/twilio/translations/ko.json b/homeassistant/components/twilio/translations/ko.json index 9ceca7c23dc..b6be32e1de4 100644 --- a/homeassistant/components/twilio/translations/ko.json +++ b/homeassistant/components/twilio/translations/ko.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Twilio \uba54\uc2dc\uc9c0\ub97c \ubc1b\uc73c\ub824\uba74 \uc778\ud130\ub137\uc5d0\uc11c Home Assistant \uc778\uc2a4\ud134\uc2a4\uc5d0 \uc561\uc138\uc2a4 \ud560 \uc218 \uc788\uc5b4\uc57c\ud569\ub2c8\ub2e4.", - "one_instance_allowed": "\ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \ud544\uc694\ud569\ub2c8\ub2e4." - }, "create_entry": { "default": "Home Assistant \ub85c \uc774\ubca4\ud2b8\ub97c \ubcf4\ub0b4\ub824\uba74 [Twilio \uc6f9 \ud6c5]({twilio_url}) \uc744 \uc124\uc815\ud574\uc57c\ud569\ub2c8\ub2e4. \n\n\ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574\uc8fc\uc138\uc694:\n\n - URL: `{webhook_url}`\n - Method: POST\n - Content Type: application/x-www-form-urlencoded\n \nHome Assistant \ub85c \ub4e4\uc5b4\uc624\ub294 \ub370\uc774\ud130\ub97c \ucc98\ub9ac\ud558\uae30 \uc704\ud55c \uc790\ub3d9\ud654\ub97c \uad6c\uc131\ud558\ub294 \ubc29\ubc95\uc740 [\uc548\ub0b4]({docs_url}) \ub97c \ucc38\uc870\ud574\uc8fc\uc138\uc694." }, diff --git a/homeassistant/components/twilio/translations/lb.json b/homeassistant/components/twilio/translations/lb.json index 5183c9f12fd..2721402c1f3 100644 --- a/homeassistant/components/twilio/translations/lb.json +++ b/homeassistant/components/twilio/translations/lb.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "\u00c4r Home Assistant Instanz muss iwwert Internet accessibel si fir Twilio Noriichten z'empf\u00e4nken.", - "one_instance_allowed": "N\u00ebmmen eng eenzeg Instanz ass n\u00e9ideg.", "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech." }, "create_entry": { @@ -10,7 +8,7 @@ }, "step": { "user": { - "description": "S\u00e9cher fir Twilio anzeriichten?", + "description": "Soll den Ariichtungs Prozess gestart ginn?", "title": "Twilio Webhook ariichten" } } diff --git a/homeassistant/components/twilio/translations/nl.json b/homeassistant/components/twilio/translations/nl.json index f65a06061c0..ee97ef4f6cd 100644 --- a/homeassistant/components/twilio/translations/nl.json +++ b/homeassistant/components/twilio/translations/nl.json @@ -1,8 +1,6 @@ { "config": { "abort": { - "not_internet_accessible": "Uw Home Assistant instantie moet toegankelijk zijn vanaf het internet om Twillo-berichten te ontvangen.", - "one_instance_allowed": "Slechts \u00e9\u00e9n exemplaar is nodig.", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "create_entry": { diff --git a/homeassistant/components/twilio/translations/no.json b/homeassistant/components/twilio/translations/no.json index 3f73ce0d3e0..81c5c35e430 100644 --- a/homeassistant/components/twilio/translations/no.json +++ b/homeassistant/components/twilio/translations/no.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Din Home Assistant forekomst m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 motta Twilio-meldinger.", - "one_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", - "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." + "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig.", + "webhook_not_internet_accessible": "Home Assistant forekomsten din m\u00e5 v\u00e6re tilgjengelig fra internett for \u00e5 kunne motta webhook meldinger" }, "create_entry": { - "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du sette opp [Webhooks with Twilio]({twilio_url}). \n\nFyll ut f\u00f8lgende informasjon: \n\n- URL: `{webhook_url}` \n- Metode: POST\n- Innholdstype: application/x-www-form-urlencoded \n\n Se [dokumentasjonen]({docs_url}) om hvordan du konfigurerer automatiseringer for \u00e5 h\u00e5ndtere innkommende data." + "default": "For \u00e5 sende hendelser til Home Assistant, m\u00e5 du sette opp [Webhooks with Twilio]({twilio_url}). \n\nFyll ut f\u00f8lgende informasjon: \n\n- URL: `{webhook_url}` \n- Metode: POST\n- Innholdstype: application/x-www-form-urlencoded \n\nSe [dokumentasjonen]({docs_url}) om hvordan du konfigurerer automasjoner for \u00e5 h\u00e5ndtere innkommende data." }, "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/pl.json b/homeassistant/components/twilio/translations/pl.json index 2a4b6766b98..667dddd747e 100644 --- a/homeassistant/components/twilio/translations/pl.json +++ b/homeassistant/components/twilio/translations/pl.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty Twilio", - "one_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", - "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." + "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja.", + "webhook_not_internet_accessible": "Tw\u00f3j Home Assistant musi by\u0107 dost\u0119pny z Internetu, aby odbiera\u0107 komunikaty webhook" }, "create_entry": { "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant, musisz skonfigurowa\u0107 [Twilio Webhook]({twilio_url}). \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n - Typ zawarto\u015bci: application/x-www-form-urlencoded \n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}) na temat konfiguracji automatyzacji, by obs\u0142u\u017cy\u0107 przychodz\u0105ce dane." }, "step": { "user": { - "description": "Na pewno chcesz skonfigurowa\u0107 Twilio?", + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?", "title": "Konfiguracja Twilio Webhook" } } diff --git a/homeassistant/components/twilio/translations/pt-BR.json b/homeassistant/components/twilio/translations/pt-BR.json index 0b377b5ab24..9c474ca31b7 100644 --- a/homeassistant/components/twilio/translations/pt-BR.json +++ b/homeassistant/components/twilio/translations/pt-BR.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Sua inst\u00e2ncia do Home Assistant precisa estar acess\u00edvel na Internet para receber mensagens do Twilio.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, voc\u00ea precisar\u00e1 configurar [Webhooks com Twilio] ( {twilio_url} ). \n\n Preencha as seguintes informa\u00e7\u00f5es: \n\n - URL: ` {webhook_url} ` \n - M\u00e9todo: POST \n - Tipo de Conte\u00fado: application / x-www-form-urlencoded \n\n Veja [a documenta\u00e7\u00e3o] ( {docs_url} ) sobre como configurar automa\u00e7\u00f5es para manipular dados de entrada." }, diff --git a/homeassistant/components/twilio/translations/pt.json b/homeassistant/components/twilio/translations/pt.json index 27f0f3d4888..a5a1d76bfbb 100644 --- a/homeassistant/components/twilio/translations/pt.json +++ b/homeassistant/components/twilio/translations/pt.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "A sua inst\u00e2ncia Home Assistant precisa de ser acess\u00edvel a partir da internet para receber mensagens Twilio.", - "one_instance_allowed": "Apenas uma \u00fanica inst\u00e2ncia \u00e9 necess\u00e1ria." - }, "create_entry": { "default": "Para enviar eventos para o Home Assistant, \u00e9 necess\u00e1rio configurar [Webhooks with Twilio] ({twilio_url}). \n\nPreencha as seguintes informa\u00e7\u00f5es: \n\n- URL: `{webhook_url}`\n- M\u00e9todo: POST \n- Tipo de Conte\u00fado: application/x-www-form-urlencoded \n\nVeja [a documenta\u00e7\u00e3o] ({docs_url}) sobre como configurar automa\u00e7\u00f5es para manipular dados de entrada." }, diff --git a/homeassistant/components/twilio/translations/ru.json b/homeassistant/components/twilio/translations/ru.json index 74972ab9b08..69402e55a82 100644 --- a/homeassistant/components/twilio/translations/ru.json +++ b/homeassistant/components/twilio/translations/ru.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 Twilio.", - "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." + "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.", + "webhook_not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Webhook-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439." }, "create_entry": { "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Webhook \u0434\u043b\u044f [Twilio]({twilio_url}).\n\n\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\n\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 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0439 \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445." }, "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/sl.json b/homeassistant/components/twilio/translations/sl.json index a0ce124c69a..50d40a95fa6 100644 --- a/homeassistant/components/twilio/translations/sl.json +++ b/homeassistant/components/twilio/translations/sl.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u010ce \u017eelite prejemati sporo\u010dila Twilio, mora biti Home Assistant dostopen prek interneta.", - "one_instance_allowed": "Potrebna je samo ena instanca." - }, "create_entry": { "default": "Za po\u0161iljanje dogodkov Home Assistant-u, boste morali nastaviti [Webhooks z Twilio]({twilio_url}).\n\nIzpolnite naslednje informacije:\n\n- URL: `{webhook_url}`\n- Metoda: POST\n- Vrsta vsebine: application/x-www-form-urlencoded\n\nGlej [dokumentacijo]({docs_url}) o tem, kako nastavite avtomatizacijo za obravnavo dohodnih podatkov." }, diff --git a/homeassistant/components/twilio/translations/sv.json b/homeassistant/components/twilio/translations/sv.json index 47c7bc15be7..c2e9f425f1c 100644 --- a/homeassistant/components/twilio/translations/sv.json +++ b/homeassistant/components/twilio/translations/sv.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "Din Home Assistant instans m\u00e5ste vara tillg\u00e4nglig fr\u00e5n internet f\u00f6r att ta emot Twilio meddelanden.", - "one_instance_allowed": "Endast en enda instans \u00e4r n\u00f6dv\u00e4ndig." - }, "create_entry": { "default": "F\u00f6r att skicka h\u00e4ndelser till Home Assistant m\u00e5ste du konfigurera [Webhooks med Twilio]({twilio_url}).\n\n Fyll i f\u00f6ljande information:\n \n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\n Se [dokumentationen]({docs_url}) om hur du konfigurerar automatiseringar f\u00f6r att hantera inkommande data." }, diff --git a/homeassistant/components/twilio/translations/zh-Hans.json b/homeassistant/components/twilio/translations/zh-Hans.json index 0f769fecb5e..f59a6334403 100644 --- a/homeassistant/components/twilio/translations/zh-Hans.json +++ b/homeassistant/components/twilio/translations/zh-Hans.json @@ -1,9 +1,5 @@ { "config": { - "abort": { - "not_internet_accessible": "\u60a8\u7684 Home Assistant \u5b9e\u4f8b\u9700\u8981\u63a5\u5165\u4e92\u8054\u7f51\u4ee5\u63a5\u6536 Twilio \u6d88\u606f\u3002", - "one_instance_allowed": "\u4ec5\u9700\u4e00\u4e2a\u5b9e\u4f8b" - }, "create_entry": { "default": "\u8981\u5411 Home Assistant \u53d1\u9001\u4e8b\u4ef6\uff0c\u60a8\u9700\u8981\u914d\u7f6e [Twilio \u7684 Webhook]({twilio_url})\u3002\n\n\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\n\u6709\u5173\u5982\u4f55\u914d\u7f6e\u81ea\u52a8\u5316\u4ee5\u5904\u7406\u4f20\u5165\u7684\u6570\u636e\uff0c\u8bf7\u53c2\u9605[\u6587\u6863]({docs_url})\u3002" }, diff --git a/homeassistant/components/twilio/translations/zh-Hant.json b/homeassistant/components/twilio/translations/zh-Hant.json index 1f07a1f44e1..630afb02973 100644 --- a/homeassistant/components/twilio/translations/zh-Hant.json +++ b/homeassistant/components/twilio/translations/zh-Hant.json @@ -1,16 +1,15 @@ { "config": { "abort": { - "not_internet_accessible": "Home Assistant \u8a2d\u5099\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 Twilio \u8a0a\u606f\u3002", - "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u7269\u4ef6\u5373\u53ef\u3002", - "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" + "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002", + "webhook_not_internet_accessible": "Home Assistant \u5be6\u9ad4\u5fc5\u9808\u8981\u80fd\u5f9e\u7db2\u969b\u7db2\u8def\u5b58\u53d6\u65b9\u80fd\u63a5\u6536 Webhook \u8a0a\u606f\u3002" }, "create_entry": { "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u8a2d\u5b9a [Webhooks with Twilio]({twilio_url})\u3002\n\n\u8acb\u586b\u5beb\u4e0b\u5217\u8cc7\u8a0a\uff1a\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\n\u95dc\u65bc\u5982\u4f55\u50b3\u5165\u8cc7\u6599\u81ea\u52d5\u5316\u8a2d\u5b9a\uff0c\u8acb\u53c3\u95b1[\u6587\u4ef6]({docs_url})\u4ee5\u9032\u884c\u4e86\u89e3\u3002" }, "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/unifi/config_flow.py b/homeassistant/components/unifi/config_flow.py index e40fb30a62c..f29c3951869 100644 --- a/homeassistant/components/unifi/config_flow.py +++ b/homeassistant/components/unifi/config_flow.py @@ -20,6 +20,7 @@ from .const import ( CONF_BLOCK_CLIENT, CONF_CONTROLLER, CONF_DETECTION_TIME, + CONF_DPI_RESTRICTIONS, CONF_IGNORE_WIRED_BUG, CONF_POE_CLIENTS, CONF_SITE_ID, @@ -28,6 +29,7 @@ from .const import ( CONF_TRACK_DEVICES, CONF_TRACK_WIRED_CLIENTS, CONTROLLER_ID, + DEFAULT_DPI_RESTRICTIONS, DEFAULT_POE_CLIENTS, DOMAIN as UNIFI_DOMAIN, LOGGER, @@ -295,6 +297,12 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow): CONF_POE_CLIENTS, default=self.options.get(CONF_POE_CLIENTS, DEFAULT_POE_CLIENTS), ): bool, + vol.Optional( + CONF_DPI_RESTRICTIONS, + default=self.options.get( + CONF_DPI_RESTRICTIONS, DEFAULT_DPI_RESTRICTIONS + ), + ): bool, } ), errors=errors, diff --git a/homeassistant/components/unifi/const.py b/homeassistant/components/unifi/const.py index 42d160f2dea..ba16612a903 100644 --- a/homeassistant/components/unifi/const.py +++ b/homeassistant/components/unifi/const.py @@ -15,6 +15,7 @@ CONF_ALLOW_BANDWIDTH_SENSORS = "allow_bandwidth_sensors" CONF_ALLOW_UPTIME_SENSORS = "allow_uptime_sensors" CONF_BLOCK_CLIENT = "block_client" CONF_DETECTION_TIME = "detection_time" +CONF_DPI_RESTRICTIONS = "dpi_restrictions" CONF_IGNORE_WIRED_BUG = "ignore_wired_bug" CONF_POE_CLIENTS = "poe_clients" CONF_TRACK_CLIENTS = "track_clients" @@ -24,6 +25,7 @@ CONF_SSID_FILTER = "ssid_filter" DEFAULT_ALLOW_BANDWIDTH_SENSORS = False DEFAULT_ALLOW_UPTIME_SENSORS = False +DEFAULT_DPI_RESTRICTIONS = True DEFAULT_IGNORE_WIRED_BUG = False DEFAULT_POE_CLIENTS = True DEFAULT_TRACK_CLIENTS = True diff --git a/homeassistant/components/unifi/controller.py b/homeassistant/components/unifi/controller.py index 6fc5b3d9ed7..4d5bfa20215 100644 --- a/homeassistant/components/unifi/controller.py +++ b/homeassistant/components/unifi/controller.py @@ -7,6 +7,8 @@ from aiohttp import CookieJar import aiounifi from aiounifi.controller import ( DATA_CLIENT_REMOVED, + DATA_DPI_GROUP, + DATA_DPI_GROUP_REMOVED, DATA_EVENT, SIGNAL_CONNECTION_STATE, SIGNAL_DATA, @@ -37,6 +39,7 @@ from .const import ( CONF_BLOCK_CLIENT, CONF_CONTROLLER, CONF_DETECTION_TIME, + CONF_DPI_RESTRICTIONS, CONF_IGNORE_WIRED_BUG, CONF_POE_CLIENTS, CONF_SITE_ID, @@ -48,6 +51,7 @@ from .const import ( DEFAULT_ALLOW_BANDWIDTH_SENSORS, DEFAULT_ALLOW_UPTIME_SENSORS, DEFAULT_DETECTION_TIME, + DEFAULT_DPI_RESTRICTIONS, DEFAULT_IGNORE_WIRED_BUG, DEFAULT_POE_CLIENTS, DEFAULT_TRACK_CLIENTS, @@ -177,6 +181,13 @@ class UniFiController: """Config entry option with list of clients to control network access.""" return self.config_entry.options.get(CONF_BLOCK_CLIENT, []) + @property + def option_dpi_restrictions(self): + """Config entry option to control DPI restriction groups.""" + return self.config_entry.options.get( + CONF_DPI_RESTRICTIONS, DEFAULT_DPI_RESTRICTIONS + ) + # Statistics sensor options @property @@ -248,6 +259,18 @@ class UniFiController: self.hass, self.signal_remove, data[DATA_CLIENT_REMOVED] ) + elif DATA_DPI_GROUP in data: + for key in data[DATA_DPI_GROUP]: + if self.api.dpi_groups[key].dpiapp_ids: + async_dispatcher_send(self.hass, self.signal_update) + else: + async_dispatcher_send(self.hass, self.signal_remove, {key}) + + elif DATA_DPI_GROUP_REMOVED in data: + async_dispatcher_send( + self.hass, self.signal_remove, data[DATA_DPI_GROUP_REMOVED] + ) + @property def signal_reachable(self) -> str: """Integration specific event to signal a change in connection status.""" diff --git a/homeassistant/components/unifi/manifest.json b/homeassistant/components/unifi/manifest.json index 9c1896f0c48..48c080f82f7 100644 --- a/homeassistant/components/unifi/manifest.json +++ b/homeassistant/components/unifi/manifest.json @@ -3,7 +3,7 @@ "name": "Ubiquiti UniFi", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/unifi", - "requirements": ["aiounifi==23"], + "requirements": ["aiounifi==25"], "codeowners": ["@Kane610"], "quality_scale": "platinum" } diff --git a/homeassistant/components/unifi/strings.json b/homeassistant/components/unifi/strings.json index 9deb68f4e3b..75e23ae2ed1 100644 --- a/homeassistant/components/unifi/strings.json +++ b/homeassistant/components/unifi/strings.json @@ -39,7 +39,8 @@ "client_control": { "data": { "block_client": "Network access controlled clients", - "poe_clients": "Allow POE control of clients" + "poe_clients": "Allow POE control of clients", + "dpi_restrictions": "Allow control of DPI restriction groups" }, "description": "Configure client controls\n\nCreate switches for serial numbers you want to control network access for.", "title": "UniFi options 2/3" diff --git a/homeassistant/components/unifi/switch.py b/homeassistant/components/unifi/switch.py index 9bdb35baf4d..6aa42b0d291 100644 --- a/homeassistant/components/unifi/switch.py +++ b/homeassistant/components/unifi/switch.py @@ -1,5 +1,6 @@ """Support for devices connected to UniFi POE.""" import logging +from typing import Any from aiounifi.api import SOURCE_EVENT from aiounifi.events import ( @@ -14,12 +15,14 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.restore_state import RestoreEntity -from .const import DOMAIN as UNIFI_DOMAIN +from .const import ATTR_MANUFACTURER, DOMAIN as UNIFI_DOMAIN from .unifi_client import UniFiClient +from .unifi_entity_base import UniFiBase _LOGGER = logging.getLogger(__name__) BLOCK_SWITCH = "block" +DPI_SWITCH = "dpi" POE_SWITCH = "poe" CLIENT_BLOCKED = (WIRED_CLIENT_BLOCKED, WIRELESS_CLIENT_BLOCKED) @@ -32,7 +35,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): Switches are controlling network access and switch ports with POE. """ controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id] - controller.entities[DOMAIN] = {BLOCK_SWITCH: set(), POE_SWITCH: set()} + controller.entities[DOMAIN] = { + BLOCK_SWITCH: set(), + POE_SWITCH: set(), + DPI_SWITCH: set(), + } if controller.site_role != "admin": return @@ -59,7 +66,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): @callback def items_added( - clients: set = controller.api.clients, devices: set = controller.api.devices + clients: set = controller.api.clients, + devices: set = controller.api.devices, + dpi_groups: set = controller.api.dpi_groups, ) -> None: """Update the values of the controller.""" if controller.option_block_clients: @@ -70,6 +79,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): controller, async_add_entities, clients, previously_known_poe_clients ) + if controller.option_dpi_restrictions: + add_dpi_entities(controller, async_add_entities, dpi_groups) + for signal in (controller.signal_update, controller.signal_options_update): controller.listeners.append(async_dispatcher_connect(hass, signal, items_added)) @@ -143,6 +155,24 @@ def add_poe_entities( async_add_entities(switches) +@callback +def add_dpi_entities(controller, async_add_entities, dpi_groups): + """Add new switch entities from the controller.""" + switches = [] + + for group in dpi_groups: + if ( + group in controller.entities[DOMAIN][DPI_SWITCH] + or not dpi_groups[group].dpiapp_ids + ): + continue + + switches.append(UniFiDPIRestrictionSwitch(dpi_groups[group], controller)) + + if switches: + async_add_entities(switches) + + class UniFiPOEClientSwitch(UniFiClient, SwitchEntity, RestoreEntity): """Representation of a client that uses POE.""" @@ -284,3 +314,61 @@ class UniFiBlockClientSwitch(UniFiClient, SwitchEntity): """Config entry options are updated, remove entity if option is disabled.""" if self.client.mac not in self.controller.option_block_clients: await self.remove_item({self.client.mac}) + + +class UniFiDPIRestrictionSwitch(UniFiBase, SwitchEntity): + """Representation of a DPI restriction group.""" + + DOMAIN = DOMAIN + TYPE = DPI_SWITCH + + @property + def key(self) -> Any: + """Return item key.""" + return self._item.id + + @property + def unique_id(self): + """Return a unique identifier for this switch.""" + return self._item.id + + @property + def name(self) -> str: + """Return the name of the client.""" + return self._item.name + + @property + def icon(self): + """Return the icon to use in the frontend.""" + if self._item.enabled: + return "mdi:network" + return "mdi:network-off" + + @property + def is_on(self): + """Return true if client is allowed to connect.""" + return self._item.enabled + + async def async_turn_on(self, **kwargs): + """Turn on connectivity for client.""" + await self.controller.api.dpi_groups.async_enable(self._item) + + async def async_turn_off(self, **kwargs): + """Turn off connectivity for client.""" + await self.controller.api.dpi_groups.async_disable(self._item) + + async def options_updated(self) -> None: + """Config entry options are updated, remove entity if option is disabled.""" + if not self.controller.option_dpi_restrictions: + await self.remove_item({self.key}) + + @property + def device_info(self) -> dict: + """Return a service description for device registry.""" + return { + "identifiers": {(DOMAIN, f"unifi_controller_{self._item.site_id}")}, + "name": "UniFi Controller", + "manufacturer": ATTR_MANUFACTURER, + "model": "UniFi Controller", + "entry_type": "service", + } diff --git a/homeassistant/components/unifi/translations/ca.json b/homeassistant/components/unifi/translations/ca.json index fb52e583d36..a07c034fe12 100644 --- a/homeassistant/components/unifi/translations/ca.json +++ b/homeassistant/components/unifi/translations/ca.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "Clients controlats amb acc\u00e9s a la xarxa", + "dpi_restrictions": "Permet el control de grups de restricci\u00f3 DPI", "poe_clients": "Permet control POE dels clients" }, "description": "Configura els controls del client \n\nConfigura interruptors per als n\u00fameros de s\u00e8rie als quals vulguis controlar l'acc\u00e9s a la xarxa.", diff --git a/homeassistant/components/unifi/translations/cs.json b/homeassistant/components/unifi/translations/cs.json index b599756677e..1247a97de9d 100644 --- a/homeassistant/components/unifi/translations/cs.json +++ b/homeassistant/components/unifi/translations/cs.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "Klienti s p\u0159\u00edstupem k s\u00edti", + "dpi_restrictions": "Povolit kontrolu nad skupinami omezen\u00ed DPI", "poe_clients": "Povolit u klient\u016f ovl\u00e1d\u00e1n\u00ed POE" }, "description": "Nakonfigurujte ovl\u00e1dac\u00ed prvky klienta\n\nVytvo\u0159te vyp\u00edna\u010de pro s\u00e9riov\u00e1 \u010d\u00edsla, pro kter\u00e1 chcete \u0159\u00eddit p\u0159\u00edstup k s\u00edti.", diff --git a/homeassistant/components/unifi/translations/en.json b/homeassistant/components/unifi/translations/en.json index ed3a26b335a..968d90e377c 100644 --- a/homeassistant/components/unifi/translations/en.json +++ b/homeassistant/components/unifi/translations/en.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "Network access controlled clients", + "dpi_restrictions": "Allow control of DPI restriction groups", "poe_clients": "Allow POE control of clients" }, "description": "Configure client controls\n\nCreate switches for serial numbers you want to control network access for.", diff --git a/homeassistant/components/unifi/translations/es.json b/homeassistant/components/unifi/translations/es.json index 35b1d3d6e29..0fa4aaf2eb7 100644 --- a/homeassistant/components/unifi/translations/es.json +++ b/homeassistant/components/unifi/translations/es.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "Clientes con acceso controlado a la red", + "dpi_restrictions": "Permitir el control de los grupos de restricci\u00f3n de DPI", "poe_clients": "Permitir control PoE de clientes" }, "description": "Configurar controles de cliente\n\nCrea conmutadores para los n\u00fameros de serie para los que deseas controlar el acceso a la red.", diff --git a/homeassistant/components/unifi/translations/et.json b/homeassistant/components/unifi/translations/et.json index 99a7ed01077..8e95da9aa5b 100644 --- a/homeassistant/components/unifi/translations/et.json +++ b/homeassistant/components/unifi/translations/et.json @@ -14,18 +14,52 @@ "host": "", "password": "Salas\u00f5na", "port": "", + "site": "", "username": "Kasutajanimi", "verify_ssl": "Kontrolli SSL sertifikaati" - } + }, + "title": "Seadista UniFi kontroller" } } }, "options": { "step": { + "client_control": { + "data": { + "block_client": "V\u00f5rgujuurdep\u00e4\u00e4suga kontrollitavad kliendid", + "dpi_restrictions": "Luba DPI piirangugruppide juhtimine", + "poe_clients": "Luba klientide POE kontroll" + }, + "description": "Seadista kliendi juhtelemendid \n\n Loo seerianumbrite. mille v\u00f5rgule juurdep\u00e4\u00e4su soovite kontrollida, jaoks l\u00fclitid.", + "title": "UniFi valikud 2/3" + }, + "device_tracker": { + "data": { + "detection_time": "Aeg sekundites alates viimasest ilmnemisest kuni olekuni '\u00e4ra'", + "ignore_wired_bug": "UniFi kaabel\u00fchenduse vealoogika keelamine", + "ssid_filter": "Vali WiFi klientide j\u00e4lgimiseks SSID", + "track_clients": "J\u00e4lgi v\u00f5rgu kliente", + "track_devices": "V\u00f5rguseadmete j\u00e4lgimine (Ubiquiti seadmed)", + "track_wired_clients": "Kaasa juhtmega v\u00f5rgukliendid" + }, + "description": "Seadista seadme j\u00e4lgimine", + "title": "UniFi valikud 1/3" + }, + "simple_options": { + "data": { + "block_client": "V\u00f5rgujuurdep\u00e4\u00e4suga kontrollitavad kliendid", + "track_clients": "J\u00e4lgi v\u00f5rgu kliente", + "track_devices": "J\u00e4lgi v\u00f5rgu seadmeid (Ubiquiti seadmed)" + }, + "description": "Seadista UniFi sidumine" + }, "statistics_sensors": { "data": { + "allow_bandwidth_sensors": "Ribalaiuse andurid v\u00f5rguklientidele", "allow_uptime_sensors": "V\u00f5rguklientide t\u00f6\u00f6soleku andurid" - } + }, + "description": "Seadista statistikaandurid", + "title": "UniFi valikud 3/3" } } } diff --git a/homeassistant/components/unifi/translations/fr.json b/homeassistant/components/unifi/translations/fr.json index 03a872a8f96..6e5412ba3d2 100644 --- a/homeassistant/components/unifi/translations/fr.json +++ b/homeassistant/components/unifi/translations/fr.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "Clients contr\u00f4l\u00e9s par acc\u00e8s r\u00e9seau", + "dpi_restrictions": "Autoriser le contr\u00f4le des groupes de restrictions DPI", "poe_clients": "Autoriser le contr\u00f4le POE des clients" }, "description": "Configurer les contr\u00f4les client \n\n Cr\u00e9ez des interrupteurs pour les num\u00e9ros de s\u00e9rie pour lesquels vous souhaitez contr\u00f4ler l'acc\u00e8s au r\u00e9seau.", diff --git a/homeassistant/components/unifi/translations/it.json b/homeassistant/components/unifi/translations/it.json index 91326796740..e530f600a04 100644 --- a/homeassistant/components/unifi/translations/it.json +++ b/homeassistant/components/unifi/translations/it.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "Client controllati per l'accesso alla rete", + "dpi_restrictions": "Consenti il controllo dei gruppi di restrizione DPI", "poe_clients": "Consentire il controllo POE dei client" }, "description": "Configurare i controlli client \n\nCreare interruttori per i numeri di serie dei quali si desidera controllare l'accesso alla rete.", diff --git a/homeassistant/components/unifi/translations/lb.json b/homeassistant/components/unifi/translations/lb.json index 992ee8192e3..1e4870e6ab8 100644 --- a/homeassistant/components/unifi/translations/lb.json +++ b/homeassistant/components/unifi/translations/lb.json @@ -15,8 +15,8 @@ "password": "Passwuert", "port": "Port", "site": "Site ID", - "username": "Benotzer", - "verify_ssl": "Kontroller benotzt g\u00ebltegen Zertifikat" + "username": "Benotzernumm", + "verify_ssl": "SSL Zertifikat iwwerpr\u00e9iwen" }, "title": "Unifi Kontroller ariichten" } diff --git a/homeassistant/components/unifi/translations/nl.json b/homeassistant/components/unifi/translations/nl.json index 9c4804c09a2..4e9aa16a245 100644 --- a/homeassistant/components/unifi/translations/nl.json +++ b/homeassistant/components/unifi/translations/nl.json @@ -53,7 +53,8 @@ "simple_options": { "data": { "block_client": "Cli\u00ebnten met netwerktoegang", - "track_clients": "Volg netwerkclients" + "track_clients": "Volg netwerkclients", + "track_devices": "Volg netwerkapparaten (Ubiquiti-apparaten)" }, "description": "Configureer UniFi-integratie" }, diff --git a/homeassistant/components/unifi/translations/no.json b/homeassistant/components/unifi/translations/no.json index 4b2c6d3d4f7..58af2bd5e54 100644 --- a/homeassistant/components/unifi/translations/no.json +++ b/homeassistant/components/unifi/translations/no.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "Nettverkskontrollerte klienter", + "dpi_restrictions": "Tillat kontroll av DPI-begrensningsgrupper", "poe_clients": "Tillat POE-kontroll av klienter" }, "description": "Konfigurere klient-kontroller\n\nOpprette brytere for serienumre du \u00f8nsker \u00e5 kontrollere tilgang til nettverk for.", diff --git a/homeassistant/components/unifi/translations/pl.json b/homeassistant/components/unifi/translations/pl.json index b24105478f4..8ff5f1e4793 100644 --- a/homeassistant/components/unifi/translations/pl.json +++ b/homeassistant/components/unifi/translations/pl.json @@ -27,9 +27,10 @@ "client_control": { "data": { "block_client": "Klienci z kontrol\u0105 dost\u0119pu do sieci", + "dpi_restrictions": "Zezwalaj na kontrolowanie grupowych ogranicze\u0144 g\u0142\u0119bokiej inspekcji pakiet\u00f3w (DPI)", "poe_clients": "Zezwalaj na kontrol\u0119 POE klient\u00f3w" }, - "description": "Konfigurowanie kontroli klienta\n\nUtw\u00f3rz prze\u0142\u0105czniki dla numer\u00f3w seryjnych, dla kt\u00f3rych chcesz kontrolowa\u0107 dost\u0119p do sieci.", + "description": "Konfigurowanie kontroli klienta.\n\nUtw\u00f3rz prze\u0142\u0105czniki dla numer\u00f3w seryjnych, dla kt\u00f3rych chcesz kontrolowa\u0107 dost\u0119p do sieci.", "title": "UniFi opcje 2/3" }, "device_tracker": { diff --git a/homeassistant/components/unifi/translations/ru.json b/homeassistant/components/unifi/translations/ru.json index 9096408474a..789212dca17 100644 --- a/homeassistant/components/unifi/translations/ru.json +++ b/homeassistant/components/unifi/translations/ru.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "\u041a\u043b\u0438\u0435\u043d\u0442\u044b \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u043c \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430", + "dpi_restrictions": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0433\u0440\u0443\u043f\u043f\u0430\u043c\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 DPI", "poe_clients": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c POE \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432" }, "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f.\n\n\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u0438 \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0439\u043d\u044b\u0445 \u043d\u043e\u043c\u0435\u0440\u043e\u0432, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0435\u0442\u0438.", diff --git a/homeassistant/components/unifi/translations/tr.json b/homeassistant/components/unifi/translations/tr.json index 667a5e676fb..903a7aaa21f 100644 --- a/homeassistant/components/unifi/translations/tr.json +++ b/homeassistant/components/unifi/translations/tr.json @@ -8,5 +8,14 @@ } } } + }, + "options": { + "step": { + "client_control": { + "data": { + "dpi_restrictions": "DPI k\u0131s\u0131tlama gruplar\u0131n\u0131n kontrol\u00fcne izin ver" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/unifi/translations/zh-Hant.json b/homeassistant/components/unifi/translations/zh-Hant.json index 1ed8d8d8856..b17ad0b5511 100644 --- a/homeassistant/components/unifi/translations/zh-Hant.json +++ b/homeassistant/components/unifi/translations/zh-Hant.json @@ -27,6 +27,7 @@ "client_control": { "data": { "block_client": "\u7db2\u8def\u5b58\u53d6\u63a7\u5236\u5ba2\u6236\u7aef", + "dpi_restrictions": "\u5141\u8a31 DPI \u9650\u5236\u7fa4\u7d44\u63a7\u5236", "poe_clients": "\u5141\u8a31 POE \u63a7\u5236\u5ba2\u6236\u7aef" }, "description": "\u8a2d\u5b9a\u5ba2\u6236\u7aef\u63a7\u5236\n\n\u65b0\u589e\u9396\u8981\u63a7\u5236\u7db2\u8def\u5b58\u53d6\u7684\u958b\u95dc\u5e8f\u865f\u3002", diff --git a/homeassistant/components/unifi/unifi_entity_base.py b/homeassistant/components/unifi/unifi_entity_base.py index 42820cf69b0..a730c134603 100644 --- a/homeassistant/components/unifi/unifi_entity_base.py +++ b/homeassistant/components/unifi/unifi_entity_base.py @@ -1,5 +1,6 @@ """Base class for UniFi entities.""" import logging +from typing import Any from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -22,12 +23,20 @@ class UniFiBase(Entity): """ self._item = item self.controller = controller - self.controller.entities[self.DOMAIN][self.TYPE].add(item.mac) + self.controller.entities[self.DOMAIN][self.TYPE].add(self.key) + + @property + def key(self) -> Any: + """Return item key.""" + return self._item.mac async def async_added_to_hass(self) -> None: """Entity created.""" _LOGGER.debug( - "New %s entity %s (%s)", self.TYPE, self.entity_id, self._item.mac + "New %s entity %s (%s)", + self.TYPE, + self.entity_id, + self.key, ) for signal, method in ( (self.controller.signal_reachable, self.async_update_callback), @@ -40,16 +49,22 @@ class UniFiBase(Entity): async def async_will_remove_from_hass(self) -> None: """Disconnect object when removed.""" _LOGGER.debug( - "Removing %s entity %s (%s)", self.TYPE, self.entity_id, self._item.mac + "Removing %s entity %s (%s)", + self.TYPE, + self.entity_id, + self.key, ) self._item.remove_callback(self.async_update_callback) - self.controller.entities[self.DOMAIN][self.TYPE].remove(self._item.mac) + self.controller.entities[self.DOMAIN][self.TYPE].remove(self.key) @callback def async_update_callback(self) -> None: """Update the entity's state.""" _LOGGER.debug( - "Updating %s entity %s (%s)", self.TYPE, self.entity_id, self._item.mac + "Updating %s entity %s (%s)", + self.TYPE, + self.entity_id, + self.key, ) self.async_write_ha_state() @@ -57,15 +72,15 @@ class UniFiBase(Entity): """Config entry options are updated, remove entity if option is disabled.""" raise NotImplementedError - async def remove_item(self, mac_addresses: set) -> None: - """Remove entity if MAC is part of set. + async def remove_item(self, keys: set) -> None: + """Remove entity if key is part of set. Remove entity if no entry in entity registry exist. Remove entity registry entry if no entry in device registry exist. Remove device registry entry if there is only one linked entity (this entity). Remove entity registry entry if there are more than one entity linked to the device registry entry. """ - if self._item.mac not in mac_addresses: + if self.key not in keys: return entity_registry = await self.hass.helpers.entity_registry.async_get_registry() diff --git a/homeassistant/components/upb/translations/ca.json b/homeassistant/components/upb/translations/ca.json index 5b9cd3c4e02..5cb77428676 100644 --- a/homeassistant/components/upb/translations/ca.json +++ b/homeassistant/components/upb/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "address_already_configured": "Ja hi ha un UPB PIM configurat amb aquesta adre\u00e7a.", "already_configured": "El dispositiu ja est\u00e0 configurat" }, "error": { diff --git a/homeassistant/components/upb/translations/de.json b/homeassistant/components/upb/translations/de.json index 12ecaebe688..ea6f1d37150 100644 --- a/homeassistant/components/upb/translations/de.json +++ b/homeassistant/components/upb/translations/de.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "address_already_configured": "Ein UPB PIM mit dieser Adresse ist bereits konfiguriert." - }, "error": { "cannot_connect": "Fehler beim Herstellen einer Verbindung zu UPB PIM. Versuchen Sie es erneut.", "invalid_upb_file": "Fehlende oder ung\u00fcltige UPB UPStart-Exportdatei, \u00fcberpr\u00fcfen Sie den Namen und den Pfad der Datei.", diff --git a/homeassistant/components/upb/translations/en.json b/homeassistant/components/upb/translations/en.json index 79853a8727e..3c6ae4cb8c2 100644 --- a/homeassistant/components/upb/translations/en.json +++ b/homeassistant/components/upb/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "address_already_configured": "An UPB PIM with this address is already configured.", "already_configured": "Device is already configured" }, "error": { diff --git a/homeassistant/components/upb/translations/es.json b/homeassistant/components/upb/translations/es.json index 46d957c1750..7cbf3446c6a 100644 --- a/homeassistant/components/upb/translations/es.json +++ b/homeassistant/components/upb/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "address_already_configured": "Un PIM UPB con esta direcci\u00f3n ya est\u00e1 configurado.", "already_configured": "El dispositivo ya est\u00e1 configurado" }, "error": { diff --git a/homeassistant/components/upb/translations/et.json b/homeassistant/components/upb/translations/et.json index 78594b0ef00..f0a7def124e 100644 --- a/homeassistant/components/upb/translations/et.json +++ b/homeassistant/components/upb/translations/et.json @@ -1,12 +1,23 @@ { "config": { "abort": { - "address_already_configured": "UPB PIM selle aadressiga on juba m\u00e4\u00e4ratud", "already_configured": "Seade on juba h\u00e4\u00e4lestatud" }, "error": { "cannot_connect": "\u00dchendamine nurjus", + "invalid_upb_file": "Puuduv v\u00f5i kehtetu UPB UPStart ekspordifail, kontrolli faili nime ja rada.", "unknown": "Ootamatu t\u00f5rge." + }, + "step": { + "user": { + "data": { + "address": "Aadress (vt \u00fclaltoodud kirjeldust)", + "file_path": "UPStart UPB ekspordifaili tee ja nimi.", + "protocol": "Protokoll" + }, + "description": "\u00dchenda Universal PowerLine Bus liidese moodul (UPB PIM). Aadressistring peab tcp puhul olema kujul \"aadress[:port]\" \"tcp\". Port on valikuline ja vaikimisi 2101. N\u00e4ide: \"192.168.1.42\". Jadaprotokolli puhul peab aadress olema kujul \"tty[:baud]\". Bood on valikuline ja vaikimisi 4800. N\u00e4ide: \"/dev/ttyS1\".", + "title": "\u00dchendu UPB PIM-iga" + } } } } \ No newline at end of file diff --git a/homeassistant/components/upb/translations/fr.json b/homeassistant/components/upb/translations/fr.json index ae90d4b9f55..f4d3279c284 100644 --- a/homeassistant/components/upb/translations/fr.json +++ b/homeassistant/components/upb/translations/fr.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "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/upb/translations/it.json b/homeassistant/components/upb/translations/it.json index b80f934d721..8811ebadc18 100644 --- a/homeassistant/components/upb/translations/it.json +++ b/homeassistant/components/upb/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "address_already_configured": "Un UPB PIM con questo indirizzo \u00e8 gi\u00e0 configurato.", "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato" }, "error": { diff --git a/homeassistant/components/upb/translations/ko.json b/homeassistant/components/upb/translations/ko.json index b1890ead5ed..48cc545d87b 100644 --- a/homeassistant/components/upb/translations/ko.json +++ b/homeassistant/components/upb/translations/ko.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "address_already_configured": "\uc774 \uc8fc\uc18c\ub85c UPB PIM \uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "error": { "cannot_connect": "UPB PIM \uc5d0 \uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694.", "invalid_upb_file": "UPB UPStart \ub0b4\ubcf4\ub0b4\uae30 \ud30c\uc77c\uc774 \uc5c6\uac70\ub098 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ud30c\uc77c \uc774\ub984\uacfc \uacbd\ub85c\ub97c \ud655\uc778\ud574\uc8fc\uc138\uc694.", diff --git a/homeassistant/components/upb/translations/lb.json b/homeassistant/components/upb/translations/lb.json index 71f05f72581..7d57566c190 100644 --- a/homeassistant/components/upb/translations/lb.json +++ b/homeassistant/components/upb/translations/lb.json @@ -1,12 +1,12 @@ { "config": { "abort": { - "address_already_configured": "een UPB PIM mat d\u00ebser Adress ass scho konfigur\u00e9iert." + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { - "cannot_connect": "Feeler beim verbannen mat UPB PIM, prob\u00e9iert w.e.g. nach emol.", + "cannot_connect": "Feeler beim verbannen", "invalid_upb_file": "UPB UPStart export fichier feelt oder ong\u00eblteg, iwwerpr\u00e9if den numm a pad vum fichier.", - "unknown": "Onerwaarte Feeler." + "unknown": "Onerwaarte Feeler" }, "step": { "user": { diff --git a/homeassistant/components/upb/translations/nl.json b/homeassistant/components/upb/translations/nl.json index 8b2702b6708..56ba7eae754 100644 --- a/homeassistant/components/upb/translations/nl.json +++ b/homeassistant/components/upb/translations/nl.json @@ -2,6 +2,22 @@ "config": { "abort": { "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "cannot_connect": "Kon niet verbinden", + "invalid_upb_file": "Ontbrekend of ongeldig UPB UPStart-exportbestand, controleer de naam en het pad van het bestand.", + "unknown": "Onverwachte fout" + }, + "step": { + "user": { + "data": { + "address": "Adres (zie beschrijving hierboven)", + "file_path": "Pad en naam van het UPStart UPB-exportbestand.", + "protocol": "Protocol" + }, + "description": "Sluit een Universal Powerline Bus Powerline Interface Module (UPB PIM) aan. De adrestekenreeks moet de vorm 'adres [: poort]' hebben voor 'tcp'. De poort is optioneel en is standaard 2101. Voorbeeld: '192.168.1.42'. Voor het seri\u00eble protocol moet het adres de vorm 'tty [: baud]' hebben. De baud is optioneel en standaard 4800. Voorbeeld: '/ dev / ttyS1'.", + "title": "Maak verbinding met UPB PIM" + } } } } \ No newline at end of file diff --git a/homeassistant/components/upb/translations/no.json b/homeassistant/components/upb/translations/no.json index 6768b277838..34295b718ca 100644 --- a/homeassistant/components/upb/translations/no.json +++ b/homeassistant/components/upb/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "address_already_configured": "En UPB PIM med denne adressen er allerede konfigurert.", "already_configured": "Enheten er allerede konfigurert" }, "error": { diff --git a/homeassistant/components/upb/translations/pl.json b/homeassistant/components/upb/translations/pl.json index b54942d3e7e..b45f8a87b46 100644 --- a/homeassistant/components/upb/translations/pl.json +++ b/homeassistant/components/upb/translations/pl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "address_already_configured": "UPB PIM z takim adresem jest ju\u017c skonfigurowany", "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" }, "error": { diff --git a/homeassistant/components/upb/translations/ru.json b/homeassistant/components/upb/translations/ru.json index 5d78c994279..0306f2b7e23 100644 --- a/homeassistant/components/upb/translations/ru.json +++ b/homeassistant/components/upb/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "address_already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441 \u044d\u0442\u0438\u043c \u0430\u0434\u0440\u0435\u0441\u043e\u043c \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." }, "error": { diff --git a/homeassistant/components/upb/translations/sv.json b/homeassistant/components/upb/translations/sv.json index 0120bd8fe08..aae50ea5105 100644 --- a/homeassistant/components/upb/translations/sv.json +++ b/homeassistant/components/upb/translations/sv.json @@ -1,8 +1,5 @@ { "config": { - "abort": { - "address_already_configured": "En UPB PIM med denna adress \u00e4r redan konfigurerad." - }, "error": { "cannot_connect": "Det gick inte att ansluta till UPB PIM, f\u00f6rs\u00f6k igen.", "invalid_upb_file": "Saknar eller ogiltig UPB UPStart-exportfil, kontrollera filens namn och s\u00f6kv\u00e4g.", diff --git a/homeassistant/components/upb/translations/zh-Hant.json b/homeassistant/components/upb/translations/zh-Hant.json index fb41d81efc4..e4809c9b63a 100644 --- a/homeassistant/components/upb/translations/zh-Hant.json +++ b/homeassistant/components/upb/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "address_already_configured": "\u4f7f\u7528\u6b64\u4f4d\u5740\u7684\u4e00\u7d44 UPB PIM \u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210\u3002", "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { diff --git a/homeassistant/components/upcloud/translations/fr.json b/homeassistant/components/upcloud/translations/fr.json new file mode 100644 index 00000000000..e4fe2301f6a --- /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/upcloud/translations/it.json b/homeassistant/components/upcloud/translations/it.json new file mode 100644 index 00000000000..766963fb198 --- /dev/null +++ b/homeassistant/components/upcloud/translations/it.json @@ -0,0 +1,25 @@ +{ + "config": { + "error": { + "cannot_connect": "Impossibile connettersi", + "invalid_auth": "Autenticazione non valida" + }, + "step": { + "user": { + "data": { + "password": "Password", + "username": "Nome utente" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "scan_interval": "Intervallo di aggiornamento in secondi, minimo 30" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/upcloud/translations/lb.json b/homeassistant/components/upcloud/translations/lb.json new file mode 100644 index 00000000000..4fcc2971025 --- /dev/null +++ b/homeassistant/components/upcloud/translations/lb.json @@ -0,0 +1,25 @@ +{ + "config": { + "error": { + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun" + }, + "step": { + "user": { + "data": { + "password": "Passwuert", + "username": "Benotzernumm" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "scan_interval": "Aktualis\u00e9ierungs Intervall a Sekonnen, minimum 30" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/upcloud/translations/nl.json b/homeassistant/components/upcloud/translations/nl.json new file mode 100644 index 00000000000..783032a1da0 --- /dev/null +++ b/homeassistant/components/upcloud/translations/nl.json @@ -0,0 +1,14 @@ +{ + "config": { + "error": { + "invalid_auth": "Ongeldige authenticatie" + }, + "step": { + "user": { + "data": { + "password": "Wachtwoord" + } + } + } + } +} \ 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 83be90bc292..bcdb3665eea 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/updater/translations/sl.json b/homeassistant/components/updater/translations/sl.json index ac2a2cab3f8..7972844cb69 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 diff --git a/homeassistant/components/upnp/manifest.json b/homeassistant/components/upnp/manifest.json index e3b30cec9a4..fe3a7b169dc 100644 --- a/homeassistant/components/upnp/manifest.json +++ b/homeassistant/components/upnp/manifest.json @@ -4,7 +4,6 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/upnp", "requirements": ["async-upnp-client==0.14.13"], - "dependencies": [], "codeowners": ["@StevenLooman"], "ssdp": [ { diff --git a/homeassistant/components/upnp/sensor.py b/homeassistant/components/upnp/sensor.py index 80a5ce7021c..a9906e535b9 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/upnp/translations/bg.json b/homeassistant/components/upnp/translations/bg.json index 892d193dd6b..6d0427f9164 100644 --- a/homeassistant/components/upnp/translations/bg.json +++ b/homeassistant/components/upnp/translations/bg.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "UPnP/IGD \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d", - "no_devices_discovered": "\u041d\u044f\u043c\u0430 \u043e\u0442\u043a\u0440\u0438\u0442\u0438 UPnP/IGD", "no_devices_found": "\u041d\u0435 \u0441\u0430 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438 UPnP/IGD \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u043c\u0440\u0435\u0436\u0430\u0442\u0430." }, "error": { diff --git a/homeassistant/components/upnp/translations/ca.json b/homeassistant/components/upnp/translations/ca.json index 76e1933d44d..5a3ed99a616 100644 --- a/homeassistant/components/upnp/translations/ca.json +++ b/homeassistant/components/upnp/translations/ca.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", "incomplete_discovery": "Descoberta incompleta", - "no_devices_discovered": "No s'ha trobat cap UPnP/IGD", "no_devices_found": "No s'han trobat dispositius a la xarxa" }, "error": { diff --git a/homeassistant/components/upnp/translations/cs.json b/homeassistant/components/upnp/translations/cs.json index 597be2a5492..319dd28c11e 100644 --- a/homeassistant/components/upnp/translations/cs.json +++ b/homeassistant/components/upnp/translations/cs.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", "incomplete_discovery": "Ne\u00fapln\u00e9 objevov\u00e1n\u00ed", - "no_devices_discovered": "Nebyly zji\u0161t\u011bny \u017e\u00e1dn\u00e9 UPnP/IGD", "no_devices_found": "V s\u00edti nebyla nalezena \u017e\u00e1dn\u00e1 za\u0159\u00edzen\u00ed" }, "flow_title": "UPnP/IGD: {name}", diff --git a/homeassistant/components/upnp/translations/da.json b/homeassistant/components/upnp/translations/da.json index f1880412006..74e24810e5a 100644 --- a/homeassistant/components/upnp/translations/da.json +++ b/homeassistant/components/upnp/translations/da.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "UPnP/IGD er allerede konfigureret", - "no_devices_discovered": "Ingen UPnP/IGD-enheder fundet.", "no_devices_found": "Ingen UPnP/IGD enheder kunne findes p\u00e5 netv\u00e6rket." }, "error": { diff --git a/homeassistant/components/upnp/translations/de.json b/homeassistant/components/upnp/translations/de.json index c2defe875a3..972f8da4075 100644 --- a/homeassistant/components/upnp/translations/de.json +++ b/homeassistant/components/upnp/translations/de.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "UPnP/IGD ist bereits konfiguriert", "incomplete_discovery": "Unvollst\u00e4ndige Suche", - "no_devices_discovered": "Keine UPnP/IGDs entdeckt", "no_devices_found": "Keine UPnP/IGD-Ger\u00e4te im Netzwerk gefunden." }, "error": { diff --git a/homeassistant/components/upnp/translations/en.json b/homeassistant/components/upnp/translations/en.json index 1dd0550c991..1476c87e51f 100644 --- a/homeassistant/components/upnp/translations/en.json +++ b/homeassistant/components/upnp/translations/en.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Device is already configured", "incomplete_discovery": "Incomplete discovery", - "no_devices_discovered": "No UPnP/IGDs discovered", "no_devices_found": "No devices found on the network" }, "flow_title": "UPnP/IGD: {name}", diff --git a/homeassistant/components/upnp/translations/es-419.json b/homeassistant/components/upnp/translations/es-419.json index 8522ad16805..1c42921cd85 100644 --- a/homeassistant/components/upnp/translations/es-419.json +++ b/homeassistant/components/upnp/translations/es-419.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "UPnP/IGD ya est\u00e1 configurado", - "no_devices_discovered": "No se han descubierto UPnP/IGDs", "no_devices_found": "No se encuentran dispositivos UPnP/IGD en la red." } } diff --git a/homeassistant/components/upnp/translations/es.json b/homeassistant/components/upnp/translations/es.json index 91a169fd839..2165979a75d 100644 --- a/homeassistant/components/upnp/translations/es.json +++ b/homeassistant/components/upnp/translations/es.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "UPnP / IGD ya est\u00e1 configurado", "incomplete_discovery": "Descubrimiento incompleto", - "no_devices_discovered": "No se descubrieron UPnP / IGDs", "no_devices_found": "No se encontraron dispositivos en la red" }, "error": { diff --git a/homeassistant/components/upnp/translations/et.json b/homeassistant/components/upnp/translations/et.json index 76145d6e6e1..d5ee1897f98 100644 --- a/homeassistant/components/upnp/translations/et.json +++ b/homeassistant/components/upnp/translations/et.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "UPnP / IGD on juba seadistatud", "incomplete_discovery": "Mittet\u00e4ielik avastamine", - "no_devices_discovered": "\u00dchtegi UPnP / IGD-d ei avastatud", "no_devices_found": "V\u00f5rgust ei leitud \u00fchtegi UPnP / IGD-seadet." }, "error": { diff --git a/homeassistant/components/upnp/translations/fr.json b/homeassistant/components/upnp/translations/fr.json index ca9258a92ec..7ef9ae20c82 100644 --- a/homeassistant/components/upnp/translations/fr.json +++ b/homeassistant/components/upnp/translations/fr.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "UPnP / IGD est d\u00e9j\u00e0 configur\u00e9", "incomplete_discovery": "D\u00e9couverte incompl\u00e8te", - "no_devices_discovered": "Aucun UPnP / IGD d\u00e9couvert", "no_devices_found": "Aucun p\u00e9riph\u00e9rique UPnP / IGD trouv\u00e9 sur le r\u00e9seau." }, "error": { diff --git a/homeassistant/components/upnp/translations/hu.json b/homeassistant/components/upnp/translations/hu.json index 1baf3f0c11a..66320386a89 100644 --- a/homeassistant/components/upnp/translations/hu.json +++ b/homeassistant/components/upnp/translations/hu.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Az UPnP / IGD m\u00e1r konfigur\u00e1l\u00e1sra ker\u00fclt", - "no_devices_discovered": "Nem tal\u00e1ltam UPnP / IGD-ket", "no_devices_found": "Nincsenek UPnPIGD eszk\u00f6z\u00f6k a h\u00e1l\u00f3zaton." }, "error": { diff --git a/homeassistant/components/upnp/translations/it.json b/homeassistant/components/upnp/translations/it.json index fab94b35e73..4955ffaa52e 100644 --- a/homeassistant/components/upnp/translations/it.json +++ b/homeassistant/components/upnp/translations/it.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", "incomplete_discovery": "Individuazione incompleta", - "no_devices_discovered": "Nessun UPnP/IGD trovato", "no_devices_found": "Nessun dispositivo trovato sulla rete" }, "error": { diff --git a/homeassistant/components/upnp/translations/ko.json b/homeassistant/components/upnp/translations/ko.json index 279d9f7f7ce..1a7b5204930 100644 --- a/homeassistant/components/upnp/translations/ko.json +++ b/homeassistant/components/upnp/translations/ko.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "UPnP/IGD \uac00 \uc774\ubbf8 \uc124\uc815\ub41c \uc0c1\ud0dc\uc785\ub2c8\ub2e4", "incomplete_discovery": "\uae30\uae30 \uac80\uc0c9\uc774 \uc644\uc804\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4", - "no_devices_discovered": "\ubc1c\uacac\ub41c UPnP/IGD \uac00 \uc5c6\uc2b5\ub2c8\ub2e4", "no_devices_found": "UPnP/IGD \uae30\uae30\uac00 \ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ubc1c\uacac\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4." }, "flow_title": "UPnP/IGD: {name}", diff --git a/homeassistant/components/upnp/translations/lb.json b/homeassistant/components/upnp/translations/lb.json index 710b788ae32..ac1eecebf99 100644 --- a/homeassistant/components/upnp/translations/lb.json +++ b/homeassistant/components/upnp/translations/lb.json @@ -1,10 +1,9 @@ { "config": { "abort": { - "already_configured": "UPnP/IGD ass scho konfigur\u00e9iert", + "already_configured": "Apparat ass scho konfigur\u00e9iert", "incomplete_discovery": "Entdeckung net komplett", - "no_devices_discovered": "Keng UPnP/IGDs entdeckt", - "no_devices_found": "Keng UPnP/IGD Apparater am Netzwierk fonnt." + "no_devices_found": "Keng Apparater am Netzwierk fonnt." }, "error": { "one": "Een", diff --git a/homeassistant/components/upnp/translations/nl.json b/homeassistant/components/upnp/translations/nl.json index cfa845f1b07..3d2c628fcbb 100644 --- a/homeassistant/components/upnp/translations/nl.json +++ b/homeassistant/components/upnp/translations/nl.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "UPnP/IGD is al geconfigureerd", "incomplete_discovery": "Onvolledige ontdekking", - "no_devices_discovered": "Geen UPnP'/IGD's ontdekt", "no_devices_found": "Geen UPnP/IGD apparaten gevonden op het netwerk." }, "error": { @@ -17,6 +16,7 @@ }, "user": { "data": { + "scan_interval": "Update-interval (seconden, minimaal 30)", "usn": "Apparaat" } } diff --git a/homeassistant/components/upnp/translations/no.json b/homeassistant/components/upnp/translations/no.json index e154db981b7..606fb8b6853 100644 --- a/homeassistant/components/upnp/translations/no.json +++ b/homeassistant/components/upnp/translations/no.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Enheten er allerede konfigurert", "incomplete_discovery": "Ufullstendig oppdagelse", - "no_devices_discovered": "Ingen UPnP / IGDs oppdaget", "no_devices_found": "Ingen enheter funnet p\u00e5 nettverket" }, "error": { diff --git a/homeassistant/components/upnp/translations/pl.json b/homeassistant/components/upnp/translations/pl.json index dafbbb0ddd1..4f519323fd0 100644 --- a/homeassistant/components/upnp/translations/pl.json +++ b/homeassistant/components/upnp/translations/pl.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", "incomplete_discovery": "Wykrywanie niekompletne", - "no_devices_discovered": "Nie wykryto urz\u0105dze\u0144 UPnP/IGD", "no_devices_found": "Nie znaleziono urz\u0105dze\u0144 w sieci" }, "error": { diff --git a/homeassistant/components/upnp/translations/pt-BR.json b/homeassistant/components/upnp/translations/pt-BR.json index f9c75ffec25..325865ba87e 100644 --- a/homeassistant/components/upnp/translations/pt-BR.json +++ b/homeassistant/components/upnp/translations/pt-BR.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "UPnP / IGD j\u00e1 est\u00e1 configurado", "incomplete_discovery": "Descoberta incompleta", - "no_devices_discovered": "Nenhum UPnP/IGD descoberto", "no_devices_found": "Nenhum dispositivo UPnP/IGD encontrado na rede." }, "step": { diff --git a/homeassistant/components/upnp/translations/pt.json b/homeassistant/components/upnp/translations/pt.json index 1a80149483d..8985d608033 100644 --- a/homeassistant/components/upnp/translations/pt.json +++ b/homeassistant/components/upnp/translations/pt.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "UPnP/IGD j\u00e1 est\u00e1 configurado", - "no_devices_discovered": "Nenhum UPnP/IGDs descoberto", "no_devices_found": "Nenhum dispositivo UPnP / IGD encontrado na rede." }, "error": { diff --git a/homeassistant/components/upnp/translations/ro.json b/homeassistant/components/upnp/translations/ro.json index 230e285cfa4..ceb1c19131a 100644 --- a/homeassistant/components/upnp/translations/ro.json +++ b/homeassistant/components/upnp/translations/ro.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "UPnP/IGD este deja configurat", - "no_devices_discovered": "Nu au fost descoperite UPnP/IGD-uri" + "already_configured": "UPnP/IGD este deja configurat" }, "error": { "few": "", diff --git a/homeassistant/components/upnp/translations/ru.json b/homeassistant/components/upnp/translations/ru.json index 799ce24c208..518cd182339 100644 --- a/homeassistant/components/upnp/translations/ru.json +++ b/homeassistant/components/upnp/translations/ru.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", "incomplete_discovery": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441.", - "no_devices_discovered": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 UPnP / IGD \u043d\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u044b.", "no_devices_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u0441\u0435\u0442\u0438." }, "error": { diff --git a/homeassistant/components/upnp/translations/sl.json b/homeassistant/components/upnp/translations/sl.json index 88b339b7372..ee25689fd51 100644 --- a/homeassistant/components/upnp/translations/sl.json +++ b/homeassistant/components/upnp/translations/sl.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "UPnP/IGD je \u017ee konfiguriran", - "no_devices_discovered": "Ni odkritih UPnP/IGD naprav", "no_devices_found": "Naprav UPnP/IGD ni mogo\u010de najti v omre\u017eju." }, "error": { diff --git a/homeassistant/components/upnp/translations/sv.json b/homeassistant/components/upnp/translations/sv.json index a7c95b6fc08..b6702d976d0 100644 --- a/homeassistant/components/upnp/translations/sv.json +++ b/homeassistant/components/upnp/translations/sv.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "UPnP/IGD \u00e4r redan konfigurerad", - "no_devices_discovered": "Inga UPnP/IGDs uppt\u00e4cktes", "no_devices_found": "Inga UPnP/IGD-enheter hittades p\u00e5 n\u00e4tverket." }, "error": { diff --git a/homeassistant/components/upnp/translations/uk.json b/homeassistant/components/upnp/translations/uk.json index c1a9f1fadcf..0b8747f902e 100644 --- a/homeassistant/components/upnp/translations/uk.json +++ b/homeassistant/components/upnp/translations/uk.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "UPnP/IGD \u0432\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0454\u043d\u043e", - "no_devices_discovered": "\u041d\u0435 \u0432\u0438\u044f\u0432\u043b\u0435\u043d\u043e UPnP/IGD" + "already_configured": "UPnP/IGD \u0432\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0454\u043d\u043e" } } } \ No newline at end of file diff --git a/homeassistant/components/upnp/translations/zh-Hans.json b/homeassistant/components/upnp/translations/zh-Hans.json index 7919d0f4591..035514237e9 100644 --- a/homeassistant/components/upnp/translations/zh-Hans.json +++ b/homeassistant/components/upnp/translations/zh-Hans.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "UPnP/IGD \u5df2\u914d\u7f6e\u5b8c\u6210", - "no_devices_discovered": "\u672a\u53d1\u73b0 UPnP/IGD", "no_devices_found": "\u6ca1\u6709\u5728\u7f51\u7edc\u4e0a\u627e\u5230 UPnP/IGD \u8bbe\u5907\u3002" }, "step": { diff --git a/homeassistant/components/upnp/translations/zh-Hant.json b/homeassistant/components/upnp/translations/zh-Hant.json index 15b3ea3a19f..008b007e2fe 100644 --- a/homeassistant/components/upnp/translations/zh-Hant.json +++ b/homeassistant/components/upnp/translations/zh-Hant.json @@ -3,7 +3,6 @@ "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "incomplete_discovery": "\u672a\u5b8c\u6210\u63a2\u7d22", - "no_devices_discovered": "\u672a\u641c\u5c0b\u5230 UPnP/IGD", "no_devices_found": "\u7db2\u8def\u4e0a\u627e\u4e0d\u5230\u8a2d\u5099" }, "flow_title": "UPnP/IGD\uff1a{name}", diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index 54f93422abd..e365e77071c 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -264,7 +264,9 @@ class UtilityMeterSensor(RestoreEntity): self._state = Decimal(state.state) self._unit_of_measurement = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) self._last_period = state.attributes.get(ATTR_LAST_PERIOD) - self._last_reset = state.attributes.get(ATTR_LAST_RESET) + self._last_reset = dt_util.parse_datetime( + state.attributes.get(ATTR_LAST_RESET) + ) self.async_write_ha_state() if state.attributes.get(ATTR_STATUS) == PAUSED: # Fake cancellation function to init the meter paused diff --git a/homeassistant/components/vacuum/translations/pl.json b/homeassistant/components/vacuum/translations/pl.json index 27a1dfb1505..92d3f274cca 100644 --- a/homeassistant/components/vacuum/translations/pl.json +++ b/homeassistant/components/vacuum/translations/pl.json @@ -1,16 +1,16 @@ { "device_automation": { "action_type": { - "clean": "niech {entity_name} sprz\u0105ta", - "dock": "niech {entity_name} wr\u00f3ci do bazy" + "clean": "niech odkurzacz {entity_name} sprz\u0105ta", + "dock": "niech odkurzacz {entity_name} wr\u00f3ci do bazy" }, "condition_type": { - "is_cleaning": "{entity_name} sprz\u0105ta", - "is_docked": "{entity_name} jest w bazie" + "is_cleaning": "odkurzacz {entity_name} sprz\u0105ta", + "is_docked": "odkurzacz {entity_name} jest w bazie" }, "trigger_type": { - "cleaning": "{entity_name} zacznie sprz\u0105ta\u0107", - "docked": "{entity_name} wr\u00f3ci do bazy" + "cleaning": "odkurzacz {entity_name} zacznie sprz\u0105ta\u0107", + "docked": "odkurzacz {entity_name} wr\u00f3ci do bazy" } }, "state": { diff --git a/homeassistant/components/vasttrafik/sensor.py b/homeassistant/components/vasttrafik/sensor.py index 54fd0a5503e..d76fc3b5e3d 100644 --- a/homeassistant/components/vasttrafik/sensor.py +++ b/homeassistant/components/vasttrafik/sensor.py @@ -133,10 +133,10 @@ class VasttrafikDepartureSensor(Entity): for departure in self._departureboard: line = departure.get("sname") if not self._lines or line in self._lines: - if "rtTime" in self._departureboard[0]: - self._state = self._departureboard[0]["rtTime"] + if "rtTime" in departure: + self._state = departure["rtTime"] else: - self._state = self._departureboard[0]["time"] + self._state = departure["time"] params = { ATTR_ACCESSIBILITY: departure.get("accessibility"), diff --git a/homeassistant/components/velbus/manifest.json b/homeassistant/components/velbus/manifest.json index 368c4865bab..b804c34c792 100644 --- a/homeassistant/components/velbus/manifest.json +++ b/homeassistant/components/velbus/manifest.json @@ -2,7 +2,7 @@ "domain": "velbus", "name": "Velbus", "documentation": "https://www.home-assistant.io/integrations/velbus", - "requirements": ["python-velbus==2.0.46"], + "requirements": ["python-velbus==2.1.1"], "config_flow": true, "codeowners": ["@Cereal2nd", "@brefra"] } diff --git a/homeassistant/components/velbus/translations/bg.json b/homeassistant/components/velbus/translations/bg.json index b22803cfb27..f354b271215 100644 --- a/homeassistant/components/velbus/translations/bg.json +++ b/homeassistant/components/velbus/translations/bg.json @@ -1,12 +1,5 @@ { "config": { - "abort": { - "port_exists": "\u0422\u043e\u0437\u0438 \u043f\u043e\u0440\u0442 \u0435 \u0432\u0435\u0447\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d" - }, - "error": { - "connection_failed": "\u0412\u0440\u044a\u0437\u043a\u0430\u0442\u0430 \u0441 velbus \u043d\u0435 \u0431\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u0430", - "port_exists": "\u0422\u043e\u0437\u0438 \u043f\u043e\u0440\u0442 \u0435 \u0432\u0435\u0447\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/velbus/translations/ca.json b/homeassistant/components/velbus/translations/ca.json index b6680ace1d6..14d99e72150 100644 --- a/homeassistant/components/velbus/translations/ca.json +++ b/homeassistant/components/velbus/translations/ca.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "El dispositiu ja est\u00e0 configurat", - "port_exists": "El port ja est\u00e0 configurat" + "already_configured": "El dispositiu ja est\u00e0 configurat" }, "error": { "already_configured": "El dispositiu ja est\u00e0 configurat", - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_failed": "Ha fallat la connexi\u00f3 Velbus", - "port_exists": "El port ja est\u00e0 configurat" + "cannot_connect": "Ha fallat la connexi\u00f3" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/cs.json b/homeassistant/components/velbus/translations/cs.json index 0e564545238..bdddbd45d47 100644 --- a/homeassistant/components/velbus/translations/cs.json +++ b/homeassistant/components/velbus/translations/cs.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "port_exists": "Tento port je ji\u017e nastaven" + "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno" }, "error": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_failed": "P\u0159ipojen\u00ed velbus selhalo", - "port_exists": "Tento port je ji\u017e nastaven" + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/da.json b/homeassistant/components/velbus/translations/da.json index 6bb58f5871a..ebadf2c5c36 100644 --- a/homeassistant/components/velbus/translations/da.json +++ b/homeassistant/components/velbus/translations/da.json @@ -1,12 +1,5 @@ { "config": { - "abort": { - "port_exists": "Denne port er allerede konfigureret" - }, - "error": { - "connection_failed": "Velbus forbindelsen mislykkedes", - "port_exists": "Denne port er allerede konfigureret" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/velbus/translations/de.json b/homeassistant/components/velbus/translations/de.json index 8b0a2ab6c9e..d9013bea391 100644 --- a/homeassistant/components/velbus/translations/de.json +++ b/homeassistant/components/velbus/translations/de.json @@ -1,12 +1,5 @@ { "config": { - "abort": { - "port_exists": "Dieser Port ist bereits konfiguriert" - }, - "error": { - "connection_failed": "Die Velbus-Verbindung ist fehlgeschlagen", - "port_exists": "Dieser Port ist bereits konfiguriert" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/velbus/translations/en.json b/homeassistant/components/velbus/translations/en.json index f0b6d16c7be..598b073a793 100644 --- a/homeassistant/components/velbus/translations/en.json +++ b/homeassistant/components/velbus/translations/en.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "Device is already configured", - "port_exists": "This port is already configured" + "already_configured": "Device is already configured" }, "error": { "already_configured": "Device is already configured", - "cannot_connect": "Failed to connect", - "connection_failed": "The velbus connection failed", - "port_exists": "This port is already configured" + "cannot_connect": "Failed to connect" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/es-419.json b/homeassistant/components/velbus/translations/es-419.json index 1bde7176eaf..91cf9cea5fc 100644 --- a/homeassistant/components/velbus/translations/es-419.json +++ b/homeassistant/components/velbus/translations/es-419.json @@ -1,12 +1,5 @@ { "config": { - "abort": { - "port_exists": "Este puerto ya est\u00e1 configurado" - }, - "error": { - "connection_failed": "La conexi\u00f3n velbus fall\u00f3", - "port_exists": "Este puerto ya est\u00e1 configurado" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/velbus/translations/es.json b/homeassistant/components/velbus/translations/es.json index 0c29e2d8505..cb600d577e7 100644 --- a/homeassistant/components/velbus/translations/es.json +++ b/homeassistant/components/velbus/translations/es.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "El dispositivo ya est\u00e1 configurado", - "port_exists": "Este puerto ya est\u00e1 configurado" + "already_configured": "El dispositivo ya est\u00e1 configurado" }, "error": { "already_configured": "El dispositivo ya est\u00e1 configurado", - "cannot_connect": "No se pudo conectar", - "connection_failed": "La conexi\u00f3n velbus fall\u00f3", - "port_exists": "Este puerto ya est\u00e1 configurado" + "cannot_connect": "No se pudo conectar" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/et.json b/homeassistant/components/velbus/translations/et.json index 9bcd15028ba..33a6a0792d8 100644 --- a/homeassistant/components/velbus/translations/et.json +++ b/homeassistant/components/velbus/translations/et.json @@ -1,12 +1,20 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "port_exists": "See port on juba h\u00e4\u00e4lestatud" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud" }, "error": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", "cannot_connect": "\u00dchendamine nurjus" + }, + "step": { + "user": { + "data": { + "name": "Selle velbus-\u00fchenduse nimi", + "port": "\u00dchendusstring" + }, + "title": "M\u00e4\u00e4ra velbus-\u00fchenduse t\u00fc\u00fcp" + } } } } \ No newline at end of file diff --git a/homeassistant/components/velbus/translations/fr.json b/homeassistant/components/velbus/translations/fr.json index 1c771b9d7a2..5f48a6bf9a7 100644 --- a/homeassistant/components/velbus/translations/fr.json +++ b/homeassistant/components/velbus/translations/fr.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", - "port_exists": "Ce port est d\u00e9j\u00e0 configur\u00e9" + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" }, "error": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", - "connection_failed": "La connexion velbus a \u00e9chou\u00e9", - "port_exists": "Ce port est d\u00e9j\u00e0 configur\u00e9" + "cannot_connect": "\u00c9chec de connexion" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/hu.json b/homeassistant/components/velbus/translations/hu.json deleted file mode 100644 index c836b414746..00000000000 --- a/homeassistant/components/velbus/translations/hu.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "config": { - "abort": { - "port_exists": "Ez a port m\u00e1r konfigur\u00e1lva van" - }, - "error": { - "port_exists": "Ez a port m\u00e1r konfigur\u00e1lva van" - } - } -} \ No newline at end of file diff --git a/homeassistant/components/velbus/translations/it.json b/homeassistant/components/velbus/translations/it.json index 3ee9a0c02de..323161b150d 100644 --- a/homeassistant/components/velbus/translations/it.json +++ b/homeassistant/components/velbus/translations/it.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "port_exists": "Questa porta \u00e8 gi\u00e0 configurata" + "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato" }, "error": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "cannot_connect": "Impossibile connettersi", - "connection_failed": "La connessione Velbus non \u00e8 riuscita", - "port_exists": "Questa porta \u00e8 gi\u00e0 configurata" + "cannot_connect": "Impossibile connettersi" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/ko.json b/homeassistant/components/velbus/translations/ko.json index 98829920bc7..3d23ff3727d 100644 --- a/homeassistant/components/velbus/translations/ko.json +++ b/homeassistant/components/velbus/translations/ko.json @@ -1,12 +1,5 @@ { "config": { - "abort": { - "port_exists": "\ud3ec\ud2b8\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, - "error": { - "connection_failed": "Velbus \uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", - "port_exists": "\ud3ec\ud2b8\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/velbus/translations/lb.json b/homeassistant/components/velbus/translations/lb.json index a791e4ce046..fcf792e61f8 100644 --- a/homeassistant/components/velbus/translations/lb.json +++ b/homeassistant/components/velbus/translations/lb.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "Apparat ass scho konfigur\u00e9iert", - "port_exists": "D\u00ebse Port ass scho konfigur\u00e9iert" + "already_configured": "Apparat ass scho konfigur\u00e9iert" }, "error": { "already_configured": "Apparat ass scho konfigur\u00e9iert", - "cannot_connect": "Feeler beim verbannen", - "connection_failed": "Feeler bei der velbus Verbindung", - "port_exists": "D\u00ebse Port ass scho konfigur\u00e9iert" + "cannot_connect": "Feeler beim verbannen" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/nl.json b/homeassistant/components/velbus/translations/nl.json index 03bbe8c2e58..0f428460f92 100644 --- a/homeassistant/components/velbus/translations/nl.json +++ b/homeassistant/components/velbus/translations/nl.json @@ -1,12 +1,11 @@ { "config": { "abort": { - "port_exists": "Deze poort is al geconfigureerd" + "already_configured": "Apparaat is al geconfigureerd" }, "error": { - "cannot_connect": "Kan geen verbinding maken", - "connection_failed": "De velbus verbinding is mislukt.", - "port_exists": "Deze poort is al geconfigureerd" + "already_configured": "Apparaat is al geconfigureerd", + "cannot_connect": "Kan geen verbinding maken" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/no.json b/homeassistant/components/velbus/translations/no.json index 24f30b0c37c..0e04928b41b 100644 --- a/homeassistant/components/velbus/translations/no.json +++ b/homeassistant/components/velbus/translations/no.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "Enheten er allerede konfigurert", - "port_exists": "Denne porten er allerede konfigurert" + "already_configured": "Enheten er allerede konfigurert" }, "error": { "already_configured": "Enheten er allerede konfigurert", - "cannot_connect": "Tilkobling mislyktes", - "connection_failed": "Velbus-tilkoblingen mislyktes", - "port_exists": "Denne porten er allerede konfigurert" + "cannot_connect": "Tilkobling mislyktes" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/pl.json b/homeassistant/components/velbus/translations/pl.json index adbd368280f..8bcaefa4936 100644 --- a/homeassistant/components/velbus/translations/pl.json +++ b/homeassistant/components/velbus/translations/pl.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "port_exists": "Ten port jest ju\u017c skonfigurowany" + "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane" }, "error": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_failed": "Po\u0142\u0105czenie Velbus nie powiod\u0142o si\u0119", - "port_exists": "Ten port jest ju\u017c skonfigurowany" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/pt-BR.json b/homeassistant/components/velbus/translations/pt-BR.json deleted file mode 100644 index cb2031dc7e5..00000000000 --- a/homeassistant/components/velbus/translations/pt-BR.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "config": { - "abort": { - "port_exists": "Esta porta j\u00e1 est\u00e1 configurada" - }, - "error": { - "connection_failed": "A conex\u00e3o velbus falhou", - "port_exists": "Esta porta j\u00e1 est\u00e1 configurada" - } - } -} \ No newline at end of file diff --git a/homeassistant/components/velbus/translations/ru.json b/homeassistant/components/velbus/translations/ru.json index 7a80b18f03e..3372496b2c3 100644 --- a/homeassistant/components/velbus/translations/ru.json +++ b/homeassistant/components/velbus/translations/ru.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "port_exists": "\u042d\u0442\u043e\u0442 \u043f\u043e\u0440\u0442 \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d." + "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant." }, "error": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 Velbus.", - "port_exists": "\u042d\u0442\u043e\u0442 \u043f\u043e\u0440\u0442 \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "step": { "user": { diff --git a/homeassistant/components/velbus/translations/sl.json b/homeassistant/components/velbus/translations/sl.json index 311919186e9..957fb368f55 100644 --- a/homeassistant/components/velbus/translations/sl.json +++ b/homeassistant/components/velbus/translations/sl.json @@ -1,12 +1,5 @@ { "config": { - "abort": { - "port_exists": "Ta vrata so \u017ee nastavljena" - }, - "error": { - "connection_failed": "Povezava z velbusom ni uspela", - "port_exists": "Ta vrata so \u017ee nastavljena" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/velbus/translations/sv.json b/homeassistant/components/velbus/translations/sv.json index e7a56c52cd6..6850c445703 100644 --- a/homeassistant/components/velbus/translations/sv.json +++ b/homeassistant/components/velbus/translations/sv.json @@ -1,12 +1,5 @@ { "config": { - "abort": { - "port_exists": "Den h\u00e4r porten \u00e4r redan konfigurerad" - }, - "error": { - "connection_failed": "Velbus-anslutningen misslyckades", - "port_exists": "Den h\u00e4r porten \u00e4r redan konfigurerad" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/velbus/translations/zh-Hans.json b/homeassistant/components/velbus/translations/zh-Hans.json index 7b2bc3b028b..f2646ab5051 100644 --- a/homeassistant/components/velbus/translations/zh-Hans.json +++ b/homeassistant/components/velbus/translations/zh-Hans.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "port_exists": "\u6b64\u7aef\u53e3\u5df2\u914d\u7f6e\u5b8c\u6210" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/velbus/translations/zh-Hant.json b/homeassistant/components/velbus/translations/zh-Hant.json index 6a9aeec0bd0..28469cd1d93 100644 --- a/homeassistant/components/velbus/translations/zh-Hant.json +++ b/homeassistant/components/velbus/translations/zh-Hant.json @@ -1,14 +1,11 @@ { "config": { "abort": { - "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "port_exists": "\u6b64\u901a\u8a0a\u57e0\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_failed": "Velbus \u9023\u7dda\u5931\u6557", - "port_exists": "\u6b64\u901a\u8a0a\u57e0\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "step": { "user": { diff --git a/homeassistant/components/velux/manifest.json b/homeassistant/components/velux/manifest.json index 0fdbfb64999..a0893b49e44 100644 --- a/homeassistant/components/velux/manifest.json +++ b/homeassistant/components/velux/manifest.json @@ -2,6 +2,6 @@ "domain": "velux", "name": "Velux", "documentation": "https://www.home-assistant.io/integrations/velux", - "requirements": ["pyvlx==0.2.17"], + "requirements": ["pyvlx==0.2.18"], "codeowners": ["@Julius2342"] } diff --git a/homeassistant/components/vera/manifest.json b/homeassistant/components/vera/manifest.json index b41d289e6b3..264f44782f5 100644 --- a/homeassistant/components/vera/manifest.json +++ b/homeassistant/components/vera/manifest.json @@ -3,6 +3,6 @@ "name": "Vera", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/vera", - "requirements": ["pyvera==0.3.10"], + "requirements": ["pyvera==0.3.11"], "codeowners": ["@vangorra"] } diff --git a/homeassistant/components/vera/translations/ca.json b/homeassistant/components/vera/translations/ca.json index ff972c70530..63ec236ef89 100644 --- a/homeassistant/components/vera/translations/ca.json +++ b/homeassistant/components/vera/translations/ca.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Ja hi ha un controlador configurat.", "cannot_connect": "No s'ha pogut connectar amb el controlador amb l'URL {base_url}" }, "step": { diff --git a/homeassistant/components/vera/translations/cs.json b/homeassistant/components/vera/translations/cs.json index 221fb6be442..df93575a945 100644 --- a/homeassistant/components/vera/translations/cs.json +++ b/homeassistant/components/vera/translations/cs.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Ovlada\u010d je ji\u017e nastaven.", "cannot_connect": "Nelze se p\u0159ipojit k ovlada\u010di pomoc\u00ed URL adresy {base_url}" }, "step": { @@ -23,6 +22,7 @@ "exclude": "ID za\u0159\u00edzen\u00ed Vera, kter\u00e1 chcete vylou\u010dit z Home Assistant.", "lights": "ID za\u0159\u00edzen\u00ed Vera, se kter\u00fdmi m\u00e1 Home Assistant zach\u00e1zet jako se sv\u011btly." }, + "description": "Podrobnosti o voliteln\u00fdch parametrech najdete v dokumentaci vera: https://www.home-assistant.io/integrations/vera/. Pozn\u00e1mka: Jak\u00e9koli zm\u011bny zde budou vy\u017eadovat restart serveru Home Assistant. Chcete-li vymazat hodnoty, zadejte mezeru.", "title": "Mo\u017enosti ovlada\u010de Vera" } } diff --git a/homeassistant/components/vera/translations/de.json b/homeassistant/components/vera/translations/de.json index f754ed737a1..f0a680e7c2d 100644 --- a/homeassistant/components/vera/translations/de.json +++ b/homeassistant/components/vera/translations/de.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Ein Controller ist bereits konfiguriert.", "cannot_connect": "Konnte keine Verbindung zum Controller mit url {base_url} herstellen" }, "step": { diff --git a/homeassistant/components/vera/translations/en.json b/homeassistant/components/vera/translations/en.json index 18b8c64f52a..5503d6b1034 100644 --- a/homeassistant/components/vera/translations/en.json +++ b/homeassistant/components/vera/translations/en.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "A controller is already configured.", "cannot_connect": "Could not connect to controller with url {base_url}" }, "step": { diff --git a/homeassistant/components/vera/translations/es-419.json b/homeassistant/components/vera/translations/es-419.json index 243050b1544..834c74b7ed3 100644 --- a/homeassistant/components/vera/translations/es-419.json +++ b/homeassistant/components/vera/translations/es-419.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Un controlador ya est\u00e1 configurado.", "cannot_connect": "No se pudo conectar al controlador con la URL {base_url}" }, "step": { diff --git a/homeassistant/components/vera/translations/es.json b/homeassistant/components/vera/translations/es.json index 8acd0d0f611..d34e106e9eb 100644 --- a/homeassistant/components/vera/translations/es.json +++ b/homeassistant/components/vera/translations/es.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Un controlador ya est\u00e1 configurado.", "cannot_connect": "No se pudo conectar con el controlador con url {base_url}" }, "step": { diff --git a/homeassistant/components/vera/translations/et.json b/homeassistant/components/vera/translations/et.json index 5c79a04737b..96950484588 100644 --- a/homeassistant/components/vera/translations/et.json +++ b/homeassistant/components/vera/translations/et.json @@ -1,15 +1,30 @@ { "config": { "abort": { - "already_configured": "Kontroller on juba seadistatud" + "cannot_connect": "Ei saanud \u00fchendust URL-il {base_url} asuva kontrolleriga" }, "step": { "user": { "data": { + "exclude": "Vera seadme ID-d mida Home Assistant'ist v\u00e4lja j\u00e4tta.", + "lights": "Vera l\u00fclitite ID'd mida neid k\u00e4sitleda Home Assistantis tuledena.", "vera_controller_url": "Kontrolleri URL" }, + "description": "Esita allpool Vera kontrolleri URL. See peaks v\u00e4lja n\u00e4gema selline: http://192.168.1.161:3480.", "title": "Seadista Vera kontroller" } } + }, + "options": { + "step": { + "init": { + "data": { + "exclude": "Vera seadme ID-d mida Home Assistant'ist v\u00e4lja j\u00e4tta.", + "lights": "Vera l\u00fclitite ID'd mida neid k\u00e4sitleda Home Assistantis tuledena." + }, + "description": "Valikuliste parameetrite kohta leiad lisateavet Vera dokumentatsioonist: https://www.home-assistant.io/integrations/vera/. M\u00e4rkus: K\u00f5ikide muudatuste puhul on vaja taask\u00e4ivitada Home Assistant'i server. V\u00e4\u00e4rtuste kustutamiseks sisestage t\u00fchik.", + "title": "Vera kontrolleri valikud" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/vera/translations/fr.json b/homeassistant/components/vera/translations/fr.json index e54613cdb78..133319c552d 100644 --- a/homeassistant/components/vera/translations/fr.json +++ b/homeassistant/components/vera/translations/fr.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Un contr\u00f4leur est d\u00e9j\u00e0 configur\u00e9.", "cannot_connect": "Impossible de se connecter au contr\u00f4leur avec l'url {base_url}" }, "step": { diff --git a/homeassistant/components/vera/translations/it.json b/homeassistant/components/vera/translations/it.json index 875e32fbb0c..e144bf251cd 100644 --- a/homeassistant/components/vera/translations/it.json +++ b/homeassistant/components/vera/translations/it.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Un controller \u00e8 gi\u00e0 configurato.", "cannot_connect": "Impossibile connettersi al controllore con l'url {base_url}" }, "step": { diff --git a/homeassistant/components/vera/translations/ko.json b/homeassistant/components/vera/translations/ko.json index 56aee4bd767..1556b9fe0d2 100644 --- a/homeassistant/components/vera/translations/ko.json +++ b/homeassistant/components/vera/translations/ko.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "\ucee8\ud2b8\ub864\ub7ec\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "cannot_connect": "URL {base_url} \uc5d0 \ucee8\ud2b8\ub864\ub7ec\ub97c \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4" }, "step": { diff --git a/homeassistant/components/vera/translations/lb.json b/homeassistant/components/vera/translations/lb.json index c78ab909b96..0f3c8acc028 100644 --- a/homeassistant/components/vera/translations/lb.json +++ b/homeassistant/components/vera/translations/lb.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Ee Kontroller ass scho konfigur\u00e9iert", "cannot_connect": "Et konnt keng Verbindung mam Kontroller mat der URL {base_url} hiergestallt ginn" }, "step": { diff --git a/homeassistant/components/vera/translations/nl.json b/homeassistant/components/vera/translations/nl.json index 358905bd50f..b4aa4a1d7a3 100644 --- a/homeassistant/components/vera/translations/nl.json +++ b/homeassistant/components/vera/translations/nl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Er is al een controller geconfigureerd.", "cannot_connect": "Kan geen verbinding maken met controller met url {base_url}" }, "step": { @@ -23,6 +22,7 @@ "exclude": "Vera-apparaat-ID's om uit te sluiten van Home Assistant.", "lights": "Vera-schakelapparaat id's behandelen als lichten in Home Assistant." }, + "description": "Zie de vera-documentatie voor details over optionele parameters: https://www.home-assistant.io/integrations/vera/. Opmerking: alle wijzigingen hier moeten opnieuw worden opgestart naar de Home Assistant-server. Druk op spatie om de waarden te wissen.", "title": "Vera controller opties" } } diff --git a/homeassistant/components/vera/translations/no.json b/homeassistant/components/vera/translations/no.json index 503f9d22547..ae1a601d550 100644 --- a/homeassistant/components/vera/translations/no.json +++ b/homeassistant/components/vera/translations/no.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "En kontroller er allerede konfigurert.", "cannot_connect": "Kunne ikke koble til kontrolleren med url {base_url}" }, "step": { diff --git a/homeassistant/components/vera/translations/pl.json b/homeassistant/components/vera/translations/pl.json index 1d993b01c0b..e7a6696c867 100644 --- a/homeassistant/components/vera/translations/pl.json +++ b/homeassistant/components/vera/translations/pl.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Kontroler jest ju\u017c skonfigurowany", - "cannot_connect": "Nie mo\u017cna po\u0142\u0105czy\u0107 z kontrolerem za pomoc\u0105 adresu {base_url}" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z kontrolerem za pomoc\u0105 adresu {base_url}" }, "step": { "user": { @@ -12,7 +11,7 @@ "vera_controller_url": "Adres URL kontrolera" }, "description": "Podaj adres URL kontrolera Vera. Powinien on wygl\u0105da\u0107 tak: http://192.168.1.161:3480.", - "title": "Skonfiguruj kontroler Vera" + "title": "Konfiguracja kontrolera Vera" } } }, diff --git a/homeassistant/components/vera/translations/ru.json b/homeassistant/components/vera/translations/ru.json index f4280cb1c1b..4f050ef3880 100644 --- a/homeassistant/components/vera/translations/ru.json +++ b/homeassistant/components/vera/translations/ru.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 {base_url}." }, "step": { diff --git a/homeassistant/components/vera/translations/sl.json b/homeassistant/components/vera/translations/sl.json index 01e5234bc78..355c6353388 100644 --- a/homeassistant/components/vera/translations/sl.json +++ b/homeassistant/components/vera/translations/sl.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "Krmilnik je \u017ee konfiguriran.", "cannot_connect": "Ni mogo\u010de vzpostaviti povezave s krmilnikom z URL-jem {base_url}" }, "step": { diff --git a/homeassistant/components/vera/translations/zh-Hant.json b/homeassistant/components/vera/translations/zh-Hant.json index 0d4b067c5ae..7293ce97611 100644 --- a/homeassistant/components/vera/translations/zh-Hant.json +++ b/homeassistant/components/vera/translations/zh-Hant.json @@ -1,7 +1,6 @@ { "config": { "abort": { - "already_configured": "\u6b64\u63a7\u5236\u5668\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210\u3002", "cannot_connect": "\u7121\u6cd5\u9023\u7dda\u81f3\u63a7\u5236\u5668 URL {base_url}" }, "step": { diff --git a/homeassistant/components/verisure/alarm_control_panel.py b/homeassistant/components/verisure/alarm_control_panel.py index 1ef3eb442cd..239396b2d0c 100644 --- a/homeassistant/components/verisure/alarm_control_panel.py +++ b/homeassistant/components/verisure/alarm_control_panel.py @@ -55,7 +55,7 @@ class VerisureAlarm(alarm.AlarmControlPanelEntity): giid = hub.config.get(CONF_GIID) if giid is not None: aliass = {i["giid"]: i["alias"] for i in hub.session.installations} - if giid in aliass.keys(): + if giid in aliass: return "{} alarm".format(aliass[giid]) _LOGGER.error("Verisure installation giid not found: %s", giid) diff --git a/homeassistant/components/vesync/translations/bg.json b/homeassistant/components/vesync/translations/bg.json index 612b2028b38..bb496b3422a 100644 --- a/homeassistant/components/vesync/translations/bg.json +++ b/homeassistant/components/vesync/translations/bg.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430 Vesync" - }, - "error": { - "invalid_login": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435 \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u0430" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/ca.json b/homeassistant/components/vesync/translations/ca.json index 63c39de62ba..076890536e8 100644 --- a/homeassistant/components/vesync/translations/ca.json +++ b/homeassistant/components/vesync/translations/ca.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Nom\u00e9s es permet una \u00fanica inst\u00e0ncia de VeSync", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "error": { - "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", - "invalid_login": "Nom d'usuari o contrasenya incorrectes" + "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/cs.json b/homeassistant/components/vesync/translations/cs.json index c6922b0b96a..6834b79a586 100644 --- a/homeassistant/components/vesync/translations/cs.json +++ b/homeassistant/components/vesync/translations/cs.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Je povolena pouze jedna instance Vesync", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "error": { - "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", - "invalid_login": "Neplatn\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no nebo heslo" + "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/da.json b/homeassistant/components/vesync/translations/da.json index 2fe09c51860..4803995a585 100644 --- a/homeassistant/components/vesync/translations/da.json +++ b/homeassistant/components/vesync/translations/da.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Kun en Vesync-forekomst er tilladt" - }, - "error": { - "invalid_login": "Ugyldigt brugernavn eller adgangskode" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/de.json b/homeassistant/components/vesync/translations/de.json index 3db70384d8b..c52b10c3293 100644 --- a/homeassistant/components/vesync/translations/de.json +++ b/homeassistant/components/vesync/translations/de.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Nur eine Vesync-Instanz ist zul\u00e4ssig" - }, - "error": { - "invalid_login": "Ung\u00fcltiger Benutzername oder Kennwort" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/en.json b/homeassistant/components/vesync/translations/en.json index 211f4fa64e0..91e220e51a9 100644 --- a/homeassistant/components/vesync/translations/en.json +++ b/homeassistant/components/vesync/translations/en.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Only one Vesync instance is allowed", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "error": { - "invalid_auth": "Invalid authentication", - "invalid_login": "Invalid username or password" + "invalid_auth": "Invalid authentication" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/es-419.json b/homeassistant/components/vesync/translations/es-419.json index 7c6f344104a..ec0fcaf3883 100644 --- a/homeassistant/components/vesync/translations/es-419.json +++ b/homeassistant/components/vesync/translations/es-419.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Solo se permite una instancia de Vesync" - }, - "error": { - "invalid_login": "Nombre de usuario o contrase\u00f1a inv\u00e1lidos" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/es.json b/homeassistant/components/vesync/translations/es.json index 5af7e2551bf..dd5f95a2e13 100644 --- a/homeassistant/components/vesync/translations/es.json +++ b/homeassistant/components/vesync/translations/es.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Solo se permite una instancia de Vesync", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "error": { - "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida", - "invalid_login": "Nombre de usuario o contrase\u00f1a no v\u00e1lidos" + "invalid_auth": "Autenticaci\u00f3n no v\u00e1lida" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/et.json b/homeassistant/components/vesync/translations/et.json index b160ddacd77..50cd017e37f 100644 --- a/homeassistant/components/vesync/translations/et.json +++ b/homeassistant/components/vesync/translations/et.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Lubatud on ainult \u00fcks Vesync sidumine.", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "error": { - "invalid_auth": "Tuvastamise viga", - "invalid_login": "Vale kasutajanimi v\u00f5i salas\u00f5na" + "invalid_auth": "Tuvastamise viga" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/fr.json b/homeassistant/components/vesync/translations/fr.json index 0d00100ae05..80bb38b615d 100644 --- a/homeassistant/components/vesync/translations/fr.json +++ b/homeassistant/components/vesync/translations/fr.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "already_setup": "Une seule instance de Vesync est autoris\u00e9e" + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { - "invalid_login": "Nom d'utilisateur ou mot de passe invalide" + "invalid_auth": "Authentification invalide" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/hu.json b/homeassistant/components/vesync/translations/hu.json index ac1da8b714d..10607c5a136 100644 --- a/homeassistant/components/vesync/translations/hu.json +++ b/homeassistant/components/vesync/translations/hu.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_login": "\u00c9rv\u00e9nytelen felhaszn\u00e1l\u00f3n\u00e9v vagy jelsz\u00f3" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/it.json b/homeassistant/components/vesync/translations/it.json index b3c15c4c4d3..f4addae1e1f 100644 --- a/homeassistant/components/vesync/translations/it.json +++ b/homeassistant/components/vesync/translations/it.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u00c8 consentita una sola istanza di Vesync", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "error": { - "invalid_auth": "Autenticazione non valida", - "invalid_login": "Nome utente o password non validi" + "invalid_auth": "Autenticazione non valida" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/ko.json b/homeassistant/components/vesync/translations/ko.json index 7fbadde9c96..888bcd66231 100644 --- a/homeassistant/components/vesync/translations/ko.json +++ b/homeassistant/components/vesync/translations/ko.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "\ud558\ub098\uc758 Vesync \uc778\uc2a4\ud134\uc2a4\ub9cc \ud5c8\uc6a9\ub429\ub2c8\ub2e4" - }, - "error": { - "invalid_login": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ub610\ub294 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/lb.json b/homeassistant/components/vesync/translations/lb.json index 6757bc82146..5aab1d77efc 100644 --- a/homeassistant/components/vesync/translations/lb.json +++ b/homeassistant/components/vesync/translations/lb.json @@ -1,11 +1,10 @@ { "config": { "abort": { - "already_setup": "N\u00ebmmen eng eenzeg Instanz vu Vesync ass erlaabt." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { - "invalid_auth": "Ong\u00eblteg Authentifikatioun", - "invalid_login": "Ong\u00ebltege Benotzernumm oder Passwuert" + "invalid_auth": "Ong\u00eblteg Authentifikatioun" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/nl.json b/homeassistant/components/vesync/translations/nl.json index cbc6ad38695..0dc21373c14 100644 --- a/homeassistant/components/vesync/translations/nl.json +++ b/homeassistant/components/vesync/translations/nl.json @@ -1,12 +1,8 @@ { "config": { "abort": { - "already_setup": "Er is slechts \u00e9\u00e9n Vesync instantie toegestaan.", "single_instance_allowed": "Al geconfigureerd. Slecht \u00e9\u00e9n configuratie mogelijk." }, - "error": { - "invalid_login": "Ongeldige gebruikersnaam of wachtwoord" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/no.json b/homeassistant/components/vesync/translations/no.json index 060b93fb7b4..4eaa522edce 100644 --- a/homeassistant/components/vesync/translations/no.json +++ b/homeassistant/components/vesync/translations/no.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Bare en Vesync-forekomst er tillatt", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "error": { - "invalid_auth": "Ugyldig godkjenning", - "invalid_login": "Ugyldig brukernavn eller passord" + "invalid_auth": "Ugyldig godkjenning" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/pl.json b/homeassistant/components/vesync/translations/pl.json index 8f7837db8ff..ebd17f69fbb 100644 --- a/homeassistant/components/vesync/translations/pl.json +++ b/homeassistant/components/vesync/translations/pl.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "Dozwolona jest tylko jedna instancja Vesync", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "error": { - "invalid_auth": "Niepoprawne uwierzytelnienie", - "invalid_login": "Nieprawid\u0142owa nazwa u\u017cytkownika lub has\u0142o" + "invalid_auth": "Niepoprawne uwierzytelnienie" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/pt-BR.json b/homeassistant/components/vesync/translations/pt-BR.json index e4beb645736..c65686007b5 100644 --- a/homeassistant/components/vesync/translations/pt-BR.json +++ b/homeassistant/components/vesync/translations/pt-BR.json @@ -1,8 +1,7 @@ { "config": { "error": { - "invalid_auth": "Autentica\u00e7\u00e3o invalida", - "invalid_login": "Usu\u00e1rio ou senha inv\u00e1lidos" + "invalid_auth": "Autentica\u00e7\u00e3o invalida" }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/pt.json b/homeassistant/components/vesync/translations/pt.json index 4df94dd3231..5cf1a0dcd00 100644 --- a/homeassistant/components/vesync/translations/pt.json +++ b/homeassistant/components/vesync/translations/pt.json @@ -1,8 +1,5 @@ { "config": { - "error": { - "invalid_login": "Nome de utilizador ou palavra passe incorretos" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/ru.json b/homeassistant/components/vesync/translations/ru.json index c1af7ed08ad..fd6132565f6 100644 --- a/homeassistant/components/vesync/translations/ru.json +++ b/homeassistant/components/vesync/translations/ru.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "error": { - "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_login": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c." + "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f." }, "step": { "user": { diff --git a/homeassistant/components/vesync/translations/sl.json b/homeassistant/components/vesync/translations/sl.json index f766224af1e..c1069e088c5 100644 --- a/homeassistant/components/vesync/translations/sl.json +++ b/homeassistant/components/vesync/translations/sl.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Dovoljen je samo ena instanca Vesync" - }, - "error": { - "invalid_login": "Neveljavno uporabni\u0161ko ime ali geslo" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/sv.json b/homeassistant/components/vesync/translations/sv.json index 3845e194bf3..b9eedc2f747 100644 --- a/homeassistant/components/vesync/translations/sv.json +++ b/homeassistant/components/vesync/translations/sv.json @@ -1,11 +1,5 @@ { "config": { - "abort": { - "already_setup": "Endast en Vesync-instans \u00e4r till\u00e5ten" - }, - "error": { - "invalid_login": "Ogiltigt anv\u00e4ndarnamn eller l\u00f6senord" - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vesync/translations/zh-Hans.json b/homeassistant/components/vesync/translations/zh-Hans.json index e256110ffa7..41478467e19 100644 --- a/homeassistant/components/vesync/translations/zh-Hans.json +++ b/homeassistant/components/vesync/translations/zh-Hans.json @@ -1,13 +1,14 @@ { "config": { - "abort": { - "already_setup": "\u53ea\u5141\u8bb8\u4e00\u4e2aVesync\u5b9e\u4f8b" - }, "error": { - "invalid_login": "\u7528\u6237\u540d\u6216\u5bc6\u7801\u65e0\u6548" + "invalid_auth": "\u9a8c\u8bc1\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/vesync/translations/zh-Hant.json b/homeassistant/components/vesync/translations/zh-Hant.json index 5265fa3fb9c..02cffeefc44 100644 --- a/homeassistant/components/vesync/translations/zh-Hant.json +++ b/homeassistant/components/vesync/translations/zh-Hant.json @@ -1,12 +1,10 @@ { "config": { "abort": { - "already_setup": "\u50c5\u5141\u8a31\u8a2d\u5b9a\u4e00\u7d44 Vesync \u8a2d\u5099", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "error": { - "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", - "invalid_login": "\u4f7f\u7528\u8005\u540d\u7a31\u6216\u5bc6\u78bc\u7121\u6548" + "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548" }, "step": { "user": { diff --git a/homeassistant/components/vilfo/translations/cs.json b/homeassistant/components/vilfo/translations/cs.json index 8b423a73518..b6735bd64cb 100644 --- a/homeassistant/components/vilfo/translations/cs.json +++ b/homeassistant/components/vilfo/translations/cs.json @@ -14,6 +14,7 @@ "access_token": "P\u0159\u00edstupov\u00fd token", "host": "Hostitel" }, + "description": "Nastaven\u00ed integrace routeru Vilfo. Pot\u0159ebujete n\u00e1zev hostitele/IP adresu routeru Vilfo a p\u0159\u00edstupov\u00fd API token. Dal\u0161\u00ed informace o t\u00e9to integraci a o tom, jak tyto podrobnosti z\u00edskat, najdete na adrese: https://www.home-assistant.io/integrations/vilfo", "title": "P\u0159ipojen\u00ed k routeru Vilfo" } } diff --git a/homeassistant/components/vilfo/translations/et.json b/homeassistant/components/vilfo/translations/et.json index 2274221a6bb..8ed6aa9e14c 100644 --- a/homeassistant/components/vilfo/translations/et.json +++ b/homeassistant/components/vilfo/translations/et.json @@ -13,7 +13,9 @@ "data": { "access_token": "Juurdep\u00e4\u00e4sut\u00f5end", "host": "" - } + }, + "description": "Seadista Vilfo ruuteri sidumine. Vaja on oma Vilfo ruuteri hosti nime / IP-d ja API juurdep\u00e4\u00e4suluba. Lisateavet selle integreerimise ja selle kohta, kuidas neid \u00fcksikasju saada, leiad aadressilt https://www.home-assistant.io/integrations/vilfo", + "title": "\u00dchenda Vilfo ruuteriga" } } } diff --git a/homeassistant/components/vilfo/translations/lb.json b/homeassistant/components/vilfo/translations/lb.json index 68a501bd5e5..cdf16438469 100644 --- a/homeassistant/components/vilfo/translations/lb.json +++ b/homeassistant/components/vilfo/translations/lb.json @@ -1,12 +1,12 @@ { "config": { "abort": { - "already_configured": "D\u00ebse Vilfo Router ass scho konfigur\u00e9iert." + "already_configured": "Apparat ass scho konfigur\u00e9iert." }, "error": { - "cannot_connect": "Feeler beim verbannen. Iwwerpr\u00e9ift \u00e4r Informatiounen an prob\u00e9iert nach emol.", - "invalid_auth": "Ong\u00eblteg Authentifikatioun. Iwwerpr\u00e9ift den Acc\u00e8s jeton an prob\u00e9iert nach emol.", - "unknown": "Onerwaarte Feeler beim ariichten vun der Integratioun." + "cannot_connect": "Feeler beim verbannen", + "invalid_auth": "Ong\u00eblteg Authentifikatioun", + "unknown": "Onerwaarte Feeler" }, "step": { "user": { diff --git a/homeassistant/components/vilfo/translations/nl.json b/homeassistant/components/vilfo/translations/nl.json index 1901be6fd1a..d4b117e2b70 100644 --- a/homeassistant/components/vilfo/translations/nl.json +++ b/homeassistant/components/vilfo/translations/nl.json @@ -5,6 +5,7 @@ }, "error": { "cannot_connect": "Kon niet verbinden. Controleer de door u verstrekte informatie en probeer het opnieuw.", + "invalid_auth": "Ongeldige authenticatie", "unknown": "Er is een onverwachte fout opgetreden tijdens het instellen van de integratie." }, "step": { @@ -13,6 +14,7 @@ "access_token": "Toegangstoken voor de Vilfo Router API", "host": "Router hostnaam of IP-adres" }, + "description": "Stel de Vilfo Router-integratie in. U heeft de hostnaam/IP van uw Vilfo Router en een API-toegangstoken nodig. Voor meer informatie over deze integratie en hoe u die details kunt verkrijgen, gaat u naar: https://www.home-assistant.io/integrations/vilfo", "title": "Maak verbinding met de Vilfo Router" } } diff --git a/homeassistant/components/vizio/config_flow.py b/homeassistant/components/vizio/config_flow.py index b6d6d9bfb05..40f71adda12 100644 --- a/homeassistant/components/vizio/config_flow.py +++ b/homeassistant/components/vizio/config_flow.py @@ -369,6 +369,10 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): discovery_info[CONF_DEVICE_CLASS], session=async_get_clientsession(self.hass, False), ) + + if not unique_id: + return self.async_abort(reason="cannot_connect") + await self.async_set_unique_id(unique_id=unique_id, raise_on_progress=True) self._abort_if_unique_id_configured() diff --git a/homeassistant/components/vizio/strings.json b/homeassistant/components/vizio/strings.json index da039b6a89e..adad8406da0 100644 --- a/homeassistant/components/vizio/strings.json +++ b/homeassistant/components/vizio/strings.json @@ -34,6 +34,7 @@ }, "abort": { "already_configured_device": "[%key:common::config_flow::abort::already_configured_device%]", + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "updated_entry": "This entry has already been setup but the name, apps, and/or options defined in the configuration do not match the previously imported configuration, so the configuration entry has been updated accordingly." } }, diff --git a/homeassistant/components/vizio/translations/ca.json b/homeassistant/components/vizio/translations/ca.json index 9182264dddf..02bfb857d76 100644 --- a/homeassistant/components/vizio/translations/ca.json +++ b/homeassistant/components/vizio/translations/ca.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "Ha fallat la connexi\u00f3", "complete_pairing_failed": "No s'ha pogut completar la vinculaci\u00f3. Verifica que el PIN proporcionat sigui el correcte i que el televisor segueix connectat a la xarxa abans de provar-ho de nou.", - "existing_config_entry_found": "Ja s'ha configurat una entrada de configuraci\u00f3 del Dispositiu VIZIO SmartCast amb el mateix n\u00famero de s\u00e8rie. Per poder configurar aquesta, has de suprimir l'entrada existent.", - "host_exists": "Dispositiu VIZIO SmartCast amb aquest nom d'amfitri\u00f3 ja configurat.", - "name_exists": "Dispositiu VIZIO SmartCast amb aquest nom ja configurat." + "existing_config_entry_found": "Ja s'ha configurat una entrada de configuraci\u00f3 del Dispositiu VIZIO SmartCast amb el mateix n\u00famero de s\u00e8rie. Per poder configurar aquesta, has de suprimir l'entrada existent." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/cs.json b/homeassistant/components/vizio/translations/cs.json index e0df8526604..23fec08499b 100644 --- a/homeassistant/components/vizio/translations/cs.json +++ b/homeassistant/components/vizio/translations/cs.json @@ -6,8 +6,7 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "host_exists": "Za\u0159\u00edzen\u00ed VIZIO SmartCast se zadan\u00fdm hostitelem je ji\u017e nastaveno.", - "name_exists": "Za\u0159\u00edzen\u00ed VIZIO SmartCast se zadan\u00fdm hostitelem je ji\u017e nastaveno." + "existing_config_entry_found": "Za\u0159\u00edzen\u00ed VIZIO SmartCast se stejn\u00fdm s\u00e9riov\u00fdm \u010d\u00edslem ji\u017e bylo nastaveno. Chcete-li nastavit tuto polo\u017eku, mus\u00edte odstranit st\u00e1vaj\u00edc\u00ed polo\u017eku." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/da.json b/homeassistant/components/vizio/translations/da.json index 71f9648cf0f..cad35d42e46 100644 --- a/homeassistant/components/vizio/translations/da.json +++ b/homeassistant/components/vizio/translations/da.json @@ -3,10 +3,6 @@ "abort": { "updated_entry": "Denne post er allerede konfigureret, men navnet og/eller indstillingerne, der er defineret i konfigurationen, stemmer ikke overens med den tidligere importerede konfiguration, s\u00e5 konfigurationsposten er blevet opdateret i overensstemmelse hermed." }, - "error": { - "host_exists": "Vizio-enhed med den specificerede v\u00e6rt er allerede konfigureret.", - "name_exists": "Vizio-enhed med det specificerede navn er allerede konfigureret." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vizio/translations/de.json b/homeassistant/components/vizio/translations/de.json index 1d723cb9482..f2b24b2c553 100644 --- a/homeassistant/components/vizio/translations/de.json +++ b/homeassistant/components/vizio/translations/de.json @@ -4,9 +4,7 @@ "updated_entry": "Dieser Eintrag wurde bereits eingerichtet, aber der Name, die Apps und / oder die in der Konfiguration definierten Optionen stimmen nicht mit der zuvor importierten Konfiguration \u00fcberein, sodass der Konfigurationseintrag entsprechend aktualisiert wurde." }, "error": { - "cannot_connect": "Verbindung fehlgeschlagen", - "host_exists": "VIZIO-Ger\u00e4t mit angegebenem Host bereits konfiguriert.", - "name_exists": "VIZIO-Ger\u00e4t mit angegebenem Namen bereits konfiguriert." + "cannot_connect": "Verbindung fehlgeschlagen" }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/en.json b/homeassistant/components/vizio/translations/en.json index 2bda9864bed..41dc47150f9 100644 --- a/homeassistant/components/vizio/translations/en.json +++ b/homeassistant/components/vizio/translations/en.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "Failed to connect", "complete_pairing_failed": "Unable to complete pairing. Ensure the PIN you provided is correct and the TV is still powered and connected to the network before resubmitting.", - "existing_config_entry_found": "An existing VIZIO SmartCast Device config entry with the same serial number has already been configured. You must delete the existing entry in order to configure this one.", - "host_exists": "VIZIO SmartCast Device with specified host already configured.", - "name_exists": "VIZIO SmartCast Device with specified name already configured." + "existing_config_entry_found": "An existing VIZIO SmartCast Device config entry with the same serial number has already been configured. You must delete the existing entry in order to configure this one." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/es-419.json b/homeassistant/components/vizio/translations/es-419.json index 0ee2dcaaf86..b4980e9544e 100644 --- a/homeassistant/components/vizio/translations/es-419.json +++ b/homeassistant/components/vizio/translations/es-419.json @@ -3,10 +3,6 @@ "abort": { "updated_entry": "Esta entrada ya se configur\u00f3, pero el nombre, las aplicaciones o las opciones definidas en la configuraci\u00f3n no coinciden con la configuraci\u00f3n importada anteriormente, por lo que la entrada de configuraci\u00f3n se actualiz\u00f3 en consecuencia." }, - "error": { - "host_exists": "Dispositivo VIZIO con el host especificado ya configurado.", - "name_exists": "Dispositivo VIZIO con el nombre especificado ya configurado." - }, "step": { "pair_tv": { "data": { diff --git a/homeassistant/components/vizio/translations/es.json b/homeassistant/components/vizio/translations/es.json index cc7f61c371f..244b9958360 100644 --- a/homeassistant/components/vizio/translations/es.json +++ b/homeassistant/components/vizio/translations/es.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "No se pudo conectar", "complete_pairing_failed": "No se pudo completar el emparejamiento. Aseg\u00farate de que el PIN que has proporcionado es correcto y que el televisor sigue encendido y conectado a la red antes de volver a enviarlo.", - "existing_config_entry_found": "Ya se ha configurado una entrada VIZIO SmartCast Device con el mismo n\u00famero de serie. Debes borrar la entrada existente para configurar \u00e9sta.", - "host_exists": "Ya existe un VIZIO SmartCast Device configurado con ese host.", - "name_exists": "Ya existe un VIZIO SmartCast Device configurado con ese nombre." + "existing_config_entry_found": "Ya se ha configurado una entrada VIZIO SmartCast Device con el mismo n\u00famero de serie. Debes borrar la entrada existente para configurar \u00e9sta." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/et.json b/homeassistant/components/vizio/translations/et.json index 4c33f9cb6bb..c4db3bdce26 100644 --- a/homeassistant/components/vizio/translations/et.json +++ b/homeassistant/components/vizio/translations/et.json @@ -1,23 +1,34 @@ { "config": { "abort": { - "already_configured_device": "Seade on juba h\u00e4\u00e4lestatud" + "already_configured_device": "Seade on juba h\u00e4\u00e4lestatud", + "updated_entry": "See kirje on juba seadistatud, kuid konfiguratsioonis m\u00e4\u00e4ratletud nimi, rakendused ja / v\u00f5i suvandid ei \u00fchti varem imporditud konfiguratsiooniga, seega on konfiguratsioonikirjet vastavalt v\u00e4rskendatud." }, "error": { - "cannot_connect": "\u00dchendamine nurjus" + "cannot_connect": "\u00dchendamine nurjus", + "complete_pairing_failed": "Sidumist ei saa l\u00f5pule viia. Veendu, et esitatud PIN-kood on \u00f5ige ning teler on enne uuesti esitamist endiselt v\u00f5rku \u00fchendatud.", + "existing_config_entry_found": "Olemasolev sama seerianumbriga konfiguratsioonikirje [VOID] on juba seadistatud. Selle seadistamiseks pead olemasoleva kirje kustutama." }, "step": { "pair_tv": { "data": { "pin": "PIN kood" - } + }, + "description": "Teler peaks kuvama koodi. Sisest see kood vormile ja j\u00e4tka sidumise l\u00f5petamiseks j\u00e4rgmise sammuga.", + "title": "Sidumise l\u00f5puleviimine" + }, + "pairing_complete": { + "description": "[VOID] on n\u00fc\u00fcd Home Assistant'iga \u00fchendatud.", + "title": "Sidumine on l\u00f5pule viidud" }, "pairing_complete_import": { - "description": "[VOID] on n\u00fc\u00fcd \u00fchendatud Home Assistantiga.\n\nJuurdep\u00e4\u00e4sut\u00f5end on '** {access_token} **'." + "description": "[VOID] on n\u00fc\u00fcd \u00fchendatud Home Assistantiga.\n\nJuurdep\u00e4\u00e4sut\u00f5end on '** {access_token} **'.", + "title": "Sidumine on l\u00f5pule viidud" }, "user": { "data": { "access_token": "Juurdep\u00e4\u00e4sut\u00f5end", + "device_class": "Seadme t\u00fc\u00fcp", "host": "", "name": "Nimi" }, @@ -30,8 +41,12 @@ "step": { "init": { "data": { - "include_or_exclude": "Kas kaasata v\u00f5i v\u00e4listada rakendused?" - } + "apps_to_include_or_exclude": "Rakendused mida kaasata v\u00f5i eirata", + "include_or_exclude": "Kas kaasata v\u00f5i v\u00e4listada rakendused?", + "volume_step": "Helitugevuse samm" + }, + "description": "Kui Teil on nutiteler, saate oma sisendiloendit valikuliselt filtreerida, valides rakendused, mida oma sisendiloendisse lisada v\u00f5i v\u00e4listada.", + "title": "Uuenda [%key:component::vizio::config::step::user:title%] s\u00e4tteid" } } } diff --git a/homeassistant/components/vizio/translations/fr.json b/homeassistant/components/vizio/translations/fr.json index 9f4f55080bc..89c46fd5959 100644 --- a/homeassistant/components/vizio/translations/fr.json +++ b/homeassistant/components/vizio/translations/fr.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "\u00c9chec de connexion", "complete_pairing_failed": "Impossible de terminer l'appairage. Assurez-vous que le code PIN que vous avez fourni est correct, que le t\u00e9l\u00e9viseur est toujours aliment\u00e9 et connect\u00e9 au r\u00e9seau avant de tenter \u00e0 nouveau.", - "existing_config_entry_found": "Une entr\u00e9e de configuration existante Appareil VIZIO Smartcast avec le m\u00eame num\u00e9ro de s\u00e9rie a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9e. Vous devez supprimer l'entr\u00e9e existante pour configurer celle-ci.", - "host_exists": "Appareil VIZIO Smartcast d\u00e9j\u00e0 configur\u00e9 avec l'h\u00f4te sp\u00e9cifi\u00e9", - "name_exists": "L'appareil VIZIO SmartCast avec le nom sp\u00e9cifi\u00e9 est d\u00e9j\u00e0 configur\u00e9." + "existing_config_entry_found": "Une entr\u00e9e de configuration existante Appareil VIZIO Smartcast avec le m\u00eame num\u00e9ro de s\u00e9rie a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9e. Vous devez supprimer l'entr\u00e9e existante pour configurer celle-ci." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/hu.json b/homeassistant/components/vizio/translations/hu.json index 9c0b31ca427..7401b751d27 100644 --- a/homeassistant/components/vizio/translations/hu.json +++ b/homeassistant/components/vizio/translations/hu.json @@ -4,10 +4,6 @@ "already_configured_device": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van", "updated_entry": "Ez a bejegyz\u00e9s m\u00e1r be van \u00e1ll\u00edtva, de a konfigur\u00e1ci\u00f3ban defini\u00e1lt n\u00e9v, appok \u00e9s/vagy be\u00e1ll\u00edt\u00e1sok nem egyeznek meg a kor\u00e1bban import\u00e1lt konfigur\u00e1ci\u00f3val, \u00edgy a konfigur\u00e1ci\u00f3s bejegyz\u00e9s ennek megfelel\u0151en friss\u00fclt." }, - "error": { - "host_exists": "A megadott kiszolg\u00e1l\u00f3n\u00e9vvel rendelkez\u0151 Vizio-eszk\u00f6z m\u00e1r konfigur\u00e1lva van.", - "name_exists": "A megadott n\u00e9vvel rendelkez\u0151 Vizio-eszk\u00f6z m\u00e1r konfigur\u00e1lva van." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vizio/translations/it.json b/homeassistant/components/vizio/translations/it.json index 0a8e1b10f61..66d4b2fb914 100644 --- a/homeassistant/components/vizio/translations/it.json +++ b/homeassistant/components/vizio/translations/it.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "Impossibile connettersi", "complete_pairing_failed": "Impossibile completare l'associazione. Assicurarsi che il PIN fornito sia corretto e che la TV sia ancora accesa e collegata alla rete prima di inviare nuovamente.", - "existing_config_entry_found": "\u00c8 gi\u00e0 stata configurata una voce di configurazione esistente Dispositivo SmartCast VIZIO con lo stesso numero di serie. \u00c8 necessario eliminare la voce esistente per configurare questa.", - "host_exists": "Il Dispositivo SmartCast VIZIO con host specificato \u00e8 gi\u00e0 configurato.", - "name_exists": "Il Dispositivo SmartCast VIZIO con il nome specificato \u00e8 gi\u00e0 configurato." + "existing_config_entry_found": "\u00c8 gi\u00e0 stata configurata una voce di configurazione esistente Dispositivo SmartCast VIZIO con lo stesso numero di serie. \u00c8 necessario eliminare la voce esistente per configurare questa." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/ko.json b/homeassistant/components/vizio/translations/ko.json index 310fd765026..ef10cb1f4fc 100644 --- a/homeassistant/components/vizio/translations/ko.json +++ b/homeassistant/components/vizio/translations/ko.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4", "complete_pairing_failed": "\ud398\uc5b4\ub9c1\uc744 \uc644\ub8cc\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc81c\ucd9c\ud558\uae30 \uc804\uc5d0 \uc785\ub825\ud55c PIN \uc774 \uc62c\ubc14\ub978\uc9c0, TV \uc758 \uc804\uc6d0\uc774 \ucf1c\uc838 \uc788\uace0 \ub124\ud2b8\uc6cc\ud06c\uc5d0 \uc5f0\uacb0\ub418\uc5b4 \uc788\ub294\uc9c0 \ud655\uc778\ud574\uc8fc\uc138\uc694.", - "existing_config_entry_found": "\uc77c\ub828 \ubc88\ud638\uac00 \ub3d9\uc77c\ud55c \uae30\uc874 VIZIO SmartCast \uae30\uae30 \uad6c\uc131 \ud56d\ubaa9\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uc774 \ud56d\ubaa9\uc744 \uad6c\uc131\ud558\ub824\uba74 \uae30\uc874 \ud56d\ubaa9\uc744 \uc0ad\uc81c\ud574\uc57c\ud569\ub2c8\ub2e4.", - "host_exists": "\uc124\uc815\ub41c \ud638\uc2a4\ud2b8\uc758 VIZIO SmartCast \uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "name_exists": "\uc124\uc815\ub41c \uc774\ub984\uc758 VIZIO SmartCast \uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." + "existing_config_entry_found": "\uc77c\ub828 \ubc88\ud638\uac00 \ub3d9\uc77c\ud55c \uae30\uc874 VIZIO SmartCast \uae30\uae30 \uad6c\uc131 \ud56d\ubaa9\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uc774 \ud56d\ubaa9\uc744 \uad6c\uc131\ud558\ub824\uba74 \uae30\uc874 \ud56d\ubaa9\uc744 \uc0ad\uc81c\ud574\uc57c\ud569\ub2c8\ub2e4." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/lb.json b/homeassistant/components/vizio/translations/lb.json index 2aa1db3afa6..4eeb9ecbef6 100644 --- a/homeassistant/components/vizio/translations/lb.json +++ b/homeassistant/components/vizio/translations/lb.json @@ -7,14 +7,12 @@ "error": { "cannot_connect": "Feeler beim verbannen", "complete_pairing_failed": "Feeler beim ofschl\u00e9isse vun der Kopplung. Iwwerpr\u00e9if dass de PIN korrekt an da de Fernsee nach \u00ebmmer ugeschalt a mam Netzwierk verbonnen ass ier de n\u00e4chste Versuch gestart g\u00ebtt.", - "existing_config_entry_found": "Eng bestoend VIZIO SmartCast Konfiguratioun Entr\u00e9e mat der selwechter Seriennummer ass scho konfigur\u00e9iert. Du musst d\u00e9i existent Entr\u00e9e l\u00e4sche fir d\u00ebs k\u00ebnnen ze konfigur\u00e9ieren.", - "host_exists": "VIZIO Apparat mat d\u00ebsem Host ass scho konfigur\u00e9iert.", - "name_exists": "VIZIO Apparat mat d\u00ebsen Numm ass scho konfigur\u00e9iert." + "existing_config_entry_found": "Eng bestoend VIZIO SmartCast Konfiguratioun Entr\u00e9e mat der selwechter Seriennummer ass scho konfigur\u00e9iert. Du musst d\u00e9i existent Entr\u00e9e l\u00e4sche fir d\u00ebs k\u00ebnnen ze konfigur\u00e9ieren." }, "step": { "pair_tv": { "data": { - "pin": "PIN" + "pin": "PIN Code" }, "description": "Um TV sollt e Code ugewisen ginn. G\u00ebff d\u00ebse Code an d'Form a fuer weider mam n\u00e4chste Schr\u00ebtt fir d'Kopplung ofzeschl\u00e9issen.", "title": "Kopplungs Prozess ofschl\u00e9issen" diff --git a/homeassistant/components/vizio/translations/nl.json b/homeassistant/components/vizio/translations/nl.json index f8f5f2a42c2..9841eaa7f50 100644 --- a/homeassistant/components/vizio/translations/nl.json +++ b/homeassistant/components/vizio/translations/nl.json @@ -6,8 +6,7 @@ }, "error": { "cannot_connect": "Verbinding mislukt", - "host_exists": "Vizio apparaat met opgegeven host al geconfigureerd.", - "name_exists": "Vizio apparaat met opgegeven naam al geconfigureerd." + "complete_pairing_failed": "Kan het koppelen niet voltooien. Zorg ervoor dat de door u opgegeven pincode correct is en dat de tv nog steeds van stroom wordt voorzien en is verbonden met het netwerk voordat u opnieuw verzendt." }, "step": { "pair_tv": { @@ -18,9 +17,11 @@ "title": "Voltooi het koppelingsproces" }, "pairing_complete": { + "description": "Uw VIZIO SmartCast-apparaat is nu verbonden met Home Assistant.", "title": "Koppelen voltooid" }, "pairing_complete_import": { + "description": "Uw VIZIO SmartCast-apparaat is nu verbonden met Home Assistant.\n\nUw toegangstoken is '** {access_token} **'.", "title": "Koppelen voltooid" }, "user": { diff --git a/homeassistant/components/vizio/translations/no.json b/homeassistant/components/vizio/translations/no.json index e10275fd95f..3836bc784d5 100644 --- a/homeassistant/components/vizio/translations/no.json +++ b/homeassistant/components/vizio/translations/no.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "Tilkobling mislyktes", "complete_pairing_failed": "Kan ikke fullf\u00f8re sammenkoblingen. Forsikre deg om at PIN-koden du oppga er riktig, og at TV-en fortsatt er p\u00e5 og tilkoblet nettverket f\u00f8r du sender inn p\u00e5 nytt.", - "existing_config_entry_found": "En eksisterende VIZIO SmartCast-enhet konfigurasjonsinngang med samme serienummer er allerede konfigurert. Du m\u00e5 slette den eksisterende oppf\u00f8ringen for \u00e5 konfigurere denne.", - "host_exists": "VIZIO SmartCast-enhet med spesifisert vert allerede konfigurert.", - "name_exists": "VIZIO SmartCast-enhet med spesifisert navn allerede konfigurert." + "existing_config_entry_found": "En eksisterende VIZIO SmartCast-enhet konfigurasjonsinngang med samme serienummer er allerede konfigurert. Du m\u00e5 slette den eksisterende oppf\u00f8ringen for \u00e5 konfigurere denne." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/pl.json b/homeassistant/components/vizio/translations/pl.json index 8784c30c9a0..420a10c59bd 100644 --- a/homeassistant/components/vizio/translations/pl.json +++ b/homeassistant/components/vizio/translations/pl.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "complete_pairing_failed": "Nie mo\u017cna uko\u0144czy\u0107 parowania. Upewnij si\u0119, \u017ce podany kod PIN jest prawid\u0142owy, a telewizor jest zasilany i pod\u0142\u0105czony do sieci przed ponownym przes\u0142aniem.", - "existing_config_entry_found": "Istnieje ju\u017c wpis konfiguracyjny VIZIO SmartCast z tym samym numerem seryjnym. W celu skonfigurowania tego wpisu nale\u017cy usun\u0105\u0107 istniej\u0105cy.", - "host_exists": "Urz\u0105dzenie VIZIO SmartCast z okre\u015blonym hostem jest ju\u017c skonfigurowane", - "name_exists": "Urz\u0105dzenie VIZIO SmartCast o okre\u015blonej nazwie jest ju\u017c skonfigurowane" + "existing_config_entry_found": "Istnieje ju\u017c wpis konfiguracyjny VIZIO SmartCast z tym samym numerem seryjnym. W celu skonfigurowania tego wpisu nale\u017cy usun\u0105\u0107 istniej\u0105cy." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/ru.json b/homeassistant/components/vizio/translations/ru.json index 8211e39959e..4ae162c0a6e 100644 --- a/homeassistant/components/vizio/translations/ru.json +++ b/homeassistant/components/vizio/translations/ru.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "complete_pairing_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435. \u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u043e\u043f\u044b\u0442\u043a\u0443, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 \u0412\u0430\u043c\u0438 PIN-\u043a\u043e\u0434 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439, \u0430 \u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440 \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d \u043a \u0441\u0435\u0442\u0438.", - "existing_config_entry_found": "\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c VIZIO SmartCast \u0441 \u0442\u0435\u043c \u0436\u0435 \u0441\u0430\u043c\u044b\u043c \u0441\u0435\u0440\u0438\u0439\u043d\u044b\u043c \u043d\u043e\u043c\u0435\u0440\u043e\u043c \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430. \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0451.", - "host_exists": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u044d\u0442\u043e\u0433\u043e \u0445\u043e\u0441\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430.", - "name_exists": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." + "existing_config_entry_found": "\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c VIZIO SmartCast \u0441 \u0442\u0435\u043c \u0436\u0435 \u0441\u0430\u043c\u044b\u043c \u0441\u0435\u0440\u0438\u0439\u043d\u044b\u043c \u043d\u043e\u043c\u0435\u0440\u043e\u043c \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430. \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0451." }, "step": { "pair_tv": { diff --git a/homeassistant/components/vizio/translations/sl.json b/homeassistant/components/vizio/translations/sl.json index e1f11c9a13e..766218db79c 100644 --- a/homeassistant/components/vizio/translations/sl.json +++ b/homeassistant/components/vizio/translations/sl.json @@ -3,10 +3,6 @@ "abort": { "updated_entry": "Ta vnos je bil \u017ee nastavljen, vendar se ime, aplikacije in/ali mo\u017enosti, dolo\u010dene v konfiguraciji, ne ujemajo s predhodno uvo\u017eeno konfiguracijo, zato je bil konfiguracijski vnos ustrezno posodobljen." }, - "error": { - "host_exists": "Naprava Vizio z dolo\u010denim gostiteljem je \u017ee konfigurirana.", - "name_exists": "Naprava Vizio z navedenim imenom je \u017ee konfigurirana." - }, "step": { "pair_tv": { "data": { diff --git a/homeassistant/components/vizio/translations/sv.json b/homeassistant/components/vizio/translations/sv.json index 1ade90683e1..8e5ebe47c43 100644 --- a/homeassistant/components/vizio/translations/sv.json +++ b/homeassistant/components/vizio/translations/sv.json @@ -3,10 +3,6 @@ "abort": { "updated_entry": "Den h\u00e4r posten har redan konfigurerats, men namnet och/eller alternativen som definierats i konfigurationen matchar inte den tidigare importerade konfigurationen och d\u00e4rf\u00f6r har konfigureringsposten uppdaterats i enlighet med detta." }, - "error": { - "host_exists": "Vizio-enheten med angivet v\u00e4rdnamn \u00e4r redan konfigurerad.", - "name_exists": "Vizio-enheten med angivet namn \u00e4r redan konfigurerad." - }, "step": { "user": { "data": { diff --git a/homeassistant/components/vizio/translations/zh-Hant.json b/homeassistant/components/vizio/translations/zh-Hant.json index bc12095371f..af72d1e964c 100644 --- a/homeassistant/components/vizio/translations/zh-Hant.json +++ b/homeassistant/components/vizio/translations/zh-Hant.json @@ -7,9 +7,7 @@ "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", "complete_pairing_failed": "\u7121\u6cd5\u5b8c\u6210\u914d\u5c0d\uff0c\u50b3\u9001\u524d\u3001\u8acb\u78ba\u5b9a\u6240\u8f38\u5165\u7684 PIN \u78bc\u3001\u540c\u6642\u96fb\u8996\u5df2\u7d93\u958b\u555f\u4e26\u9023\u7dda\u81f3\u7db2\u8def\u3002", - "existing_config_entry_found": "\u5df2\u6709\u4e00\u7d44\u4f7f\u7528\u76f8\u540c\u5e8f\u865f\u7684 VIZIO SmartCast \u8a2d\u5099 \u5df2\u8a2d\u5b9a\u3002\u5fc5\u9808\u5148\u9032\u884c\u522a\u9664\u5f8c\u624d\u80fd\u91cd\u65b0\u8a2d\u5b9a\u3002", - "host_exists": "\u4f9d\u4e3b\u6a5f\u7aef\u4e4b VIZIO SmartCast \u8a2d\u5099 \u8a2d\u5b9a\u5df2\u8a2d\u5b9a\u5b8c\u6210\u3002", - "name_exists": "\u4f9d\u540d\u7a31\u4e4b VIZIO SmartCast \u8a2d\u5099 \u8a2d\u5b9a\u5df2\u8a2d\u5b9a\u5b8c\u6210\u3002" + "existing_config_entry_found": "\u5df2\u6709\u4e00\u7d44\u4f7f\u7528\u76f8\u540c\u5e8f\u865f\u7684 VIZIO SmartCast \u8a2d\u5099 \u5df2\u8a2d\u5b9a\u3002\u5fc5\u9808\u5148\u9032\u884c\u522a\u9664\u5f8c\u624d\u80fd\u91cd\u65b0\u8a2d\u5b9a\u3002" }, "step": { "pair_tv": { diff --git a/homeassistant/components/volumio/translations/et.json b/homeassistant/components/volumio/translations/et.json index a8a93cef5c0..48a64d8ffad 100644 --- a/homeassistant/components/volumio/translations/et.json +++ b/homeassistant/components/volumio/translations/et.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud", + "cannot_connect": "Avastatud Volumioga ei saa \u00fchendust luua" }, "error": { "cannot_connect": "\u00dchendamine nurjus", @@ -9,7 +10,8 @@ }, "step": { "discovery_confirm": { - "description": "Kas soovid lisada Volumio ('{name}') Home Assistanti?" + "description": "Kas soovid lisada Volumio ('{name}') Home Assistanti?", + "title": "Avastatud Volumio seade" }, "user": { "data": { diff --git a/homeassistant/components/volumio/translations/nl.json b/homeassistant/components/volumio/translations/nl.json index c1909b19508..9179418def9 100644 --- a/homeassistant/components/volumio/translations/nl.json +++ b/homeassistant/components/volumio/translations/nl.json @@ -1,8 +1,15 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "host": "Host", "port": "Poort" } } diff --git a/homeassistant/components/volumio/translations/pl.json b/homeassistant/components/volumio/translations/pl.json index 431788c2c52..2a99bec962d 100644 --- a/homeassistant/components/volumio/translations/pl.json +++ b/homeassistant/components/volumio/translations/pl.json @@ -2,7 +2,7 @@ "config": { "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "cannot_connect": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z odnalezionym Volumio" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z odnalezionym Volumio" }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", diff --git a/homeassistant/components/water_heater/translations/fr.json b/homeassistant/components/water_heater/translations/fr.json new file mode 100644 index 00000000000..ac72ffab883 --- /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/water_heater/translations/it.json b/homeassistant/components/water_heater/translations/it.json new file mode 100644 index 00000000000..86458a54272 --- /dev/null +++ b/homeassistant/components/water_heater/translations/it.json @@ -0,0 +1,8 @@ +{ + "device_automation": { + "action_type": { + "turn_off": "Disattiva {entity_name}", + "turn_on": "Attiva {entity_name}" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/water_heater/translations/lb.json b/homeassistant/components/water_heater/translations/lb.json new file mode 100644 index 00000000000..cd1c89c84eb --- /dev/null +++ b/homeassistant/components/water_heater/translations/lb.json @@ -0,0 +1,8 @@ +{ + "device_automation": { + "action_type": { + "turn_off": "{entity_name} ausschalten", + "turn_on": "{entity_name} uschalten" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/water_heater/translations/nl.json b/homeassistant/components/water_heater/translations/nl.json new file mode 100644 index 00000000000..8b832b52c1c --- /dev/null +++ b/homeassistant/components/water_heater/translations/nl.json @@ -0,0 +1,8 @@ +{ + "device_automation": { + "action_type": { + "turn_off": "Schakel {entity_name} uit", + "turn_on": "Schakel {entity_name} in" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/weather/translations/fr.json b/homeassistant/components/weather/translations/fr.json index 7975b1f396d..316a990570f 100644 --- a/homeassistant/components/weather/translations/fr.json +++ b/homeassistant/components/weather/translations/fr.json @@ -8,7 +8,7 @@ "hail": "Gr\u00eale", "lightning": "Orage", "lightning-rainy": "Orage / Pluie", - "partlycloudy": "Partiellement nuageux", + "partlycloudy": "\u00c9claircies", "pouring": "Averses", "rainy": "Pluie", "snowy": "Neigeux", diff --git a/homeassistant/components/weather/translations/tr.json b/homeassistant/components/weather/translations/tr.json index d3a2e2c051a..1af9682e151 100644 --- a/homeassistant/components/weather/translations/tr.json +++ b/homeassistant/components/weather/translations/tr.json @@ -5,11 +5,11 @@ "cloudy": "Bulutlu", "exceptional": "Ola\u011fan\u00fcst\u00fc", "fog": "Sis", - "hail": "Selam", + "hail": "Dolu", "lightning": "Y\u0131ld\u0131r\u0131m", "lightning-rainy": "Y\u0131ld\u0131r\u0131m, ya\u011fmurlu", "partlycloudy": "Par\u00e7al\u0131 bulutlu", - "pouring": "D\u00f6kme", + "pouring": "Sa\u011fanak Ya\u011fmurlu", "rainy": "Ya\u011fmurlu", "snowy": "Karl\u0131", "snowy-rainy": "Karl\u0131, ya\u011fmurlu", diff --git a/homeassistant/components/webostv/media_player.py b/homeassistant/components/webostv/media_player.py index 82950e4f7f8..4807d780a48 100644 --- a/homeassistant/components/webostv/media_player.py +++ b/homeassistant/components/webostv/media_player.py @@ -271,7 +271,7 @@ class LgWebOSMediaPlayerEntity(MediaPlayerEntity): @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/websocket_api/__init__.py b/homeassistant/components/websocket_api/__init__.py index bfcfc796bad..2d591455eaf 100644 --- a/homeassistant/components/websocket_api/__init__.py +++ b/homeassistant/components/websocket_api/__init__.py @@ -6,7 +6,31 @@ import voluptuous as vol from homeassistant.core import HomeAssistant, callback from homeassistant.loader import bind_hass -from . import commands, connection, const, decorators, http, messages +from . import commands, connection, const, decorators, http, messages # noqa +from .connection import ActiveConnection # noqa +from .const import ( # noqa + ERR_HOME_ASSISTANT_ERROR, + ERR_INVALID_FORMAT, + ERR_NOT_FOUND, + ERR_NOT_SUPPORTED, + ERR_TEMPLATE_ERROR, + ERR_TIMEOUT, + ERR_UNAUTHORIZED, + ERR_UNKNOWN_COMMAND, + ERR_UNKNOWN_ERROR, +) +from .decorators import ( # noqa + async_response, + require_admin, + websocket_command, + ws_require_user, +) +from .messages import ( # noqa + BASE_COMMAND_MESSAGE_SCHEMA, + error_message, + event_message, + result_message, +) # mypy: allow-untyped-calls, allow-untyped-defs @@ -14,17 +38,6 @@ DOMAIN = const.DOMAIN DEPENDENCIES = ("http",) -# Backwards compat / Make it easier to integrate -ActiveConnection = connection.ActiveConnection -BASE_COMMAND_MESSAGE_SCHEMA = messages.BASE_COMMAND_MESSAGE_SCHEMA -error_message = messages.error_message -result_message = messages.result_message -event_message = messages.event_message -async_response = decorators.async_response -require_admin = decorators.require_admin -ws_require_user = decorators.ws_require_user -websocket_command = decorators.websocket_command - @bind_hass @callback diff --git a/homeassistant/components/websocket_api/connection.py b/homeassistant/components/websocket_api/connection.py index ae2bb16c6d2..108d4de5ada 100644 --- a/homeassistant/components/websocket_api/connection.py +++ b/homeassistant/components/websocket_api/connection.py @@ -5,7 +5,7 @@ from typing import Any, Callable, Dict, Hashable, Optional import voluptuous as vol from homeassistant.core import Context, callback -from homeassistant.exceptions import Unauthorized +from homeassistant.exceptions import HomeAssistantError, Unauthorized from . import const, messages @@ -118,6 +118,9 @@ class ActiveConnection: elif isinstance(err, asyncio.TimeoutError): code = const.ERR_TIMEOUT err_message = "Timeout" + elif isinstance(err, HomeAssistantError): + code = const.ERR_UNKNOWN_ERROR + err_message = str(err) else: code = const.ERR_UNKNOWN_ERROR err_message = "Unknown error" diff --git a/homeassistant/components/websocket_api/http.py b/homeassistant/components/websocket_api/http.py index b71b19d5181..daa8529e8bd 100644 --- a/homeassistant/components/websocket_api/http.py +++ b/homeassistant/components/websocket_api/http.py @@ -27,6 +27,7 @@ from .error import Disconnect from .messages import message_to_json # mypy: allow-untyped-calls, allow-untyped-defs, no-check-untyped-defs +_WS_LOGGER = logging.getLogger(f"{__name__}.connection") class WebsocketAPIView(HomeAssistantView): @@ -41,6 +42,14 @@ class WebsocketAPIView(HomeAssistantView): return await WebSocketHandler(request.app["hass"], request).async_handle() +class WebSocketAdapter(logging.LoggerAdapter): + """Add connection id to websocket messages.""" + + def process(self, msg, kwargs): + """Add connid to websocket log messages.""" + return f'[{self.extra["connid"]}] {msg}', kwargs + + class WebSocketHandler: """Handle an active websocket client connection.""" @@ -52,7 +61,7 @@ class WebSocketHandler: self._to_write: asyncio.Queue = asyncio.Queue(maxsize=MAX_PENDING_MSG) self._handle_task = None self._writer_task = None - self._logger = logging.getLogger("{}.connection.{}".format(__name__, id(self))) + self._logger = WebSocketAdapter(_WS_LOGGER, {"connid": id(self)}) self._peak_checker_unsub = None async def _writer(self): @@ -222,20 +231,20 @@ class WebSocketHandler: self._to_write.put_nowait(None) # Make sure all error messages are written before closing await self._writer_task - except asyncio.QueueFull: + await wsock.close() + except asyncio.QueueFull: # can be raised by put_nowait self._writer_task.cancel() - await wsock.close() + finally: + if disconnect_warn is None: + self._logger.debug("Disconnected") + else: + self._logger.warning("Disconnected: %s", disconnect_warn) - if disconnect_warn is None: - self._logger.debug("Disconnected") - else: - self._logger.warning("Disconnected: %s", disconnect_warn) - - if connection is not None: - self.hass.data[DATA_CONNECTIONS] -= 1 - self.hass.helpers.dispatcher.async_dispatcher_send( - SIGNAL_WEBSOCKET_DISCONNECTED - ) + if connection is not None: + self.hass.data[DATA_CONNECTIONS] -= 1 + self.hass.helpers.dispatcher.async_dispatcher_send( + SIGNAL_WEBSOCKET_DISCONNECTED + ) return wsock diff --git a/homeassistant/components/wemo/__init__.py b/homeassistant/components/wemo/__init__.py index 0594747d0b2..c656926ecff 100644 --- a/homeassistant/components/wemo/__init__.py +++ b/homeassistant/components/wemo/__init__.py @@ -164,7 +164,7 @@ async def async_setup_entry(hass, entry): def validate_static_config(host, port): """Handle a static config.""" - url = setup_url_for_address(host, port) + url = pywemo.setup_url_for_address(host, port) if not url: _LOGGER.error( @@ -183,14 +183,3 @@ def validate_static_config(host, port): return None return device - - -def setup_url_for_address(host, port): - """Determine setup.xml url for given host and port pair.""" - if not port: - port = pywemo.ouimeaux_device.probe_wemo(host) - - if not port: - return None - - return f"http://{host}:{port}/setup.xml" diff --git a/homeassistant/components/wemo/manifest.json b/homeassistant/components/wemo/manifest.json index 357d9d95483..a7d2ca585a5 100644 --- a/homeassistant/components/wemo/manifest.json +++ b/homeassistant/components/wemo/manifest.json @@ -3,7 +3,7 @@ "name": "Belkin WeMo", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/wemo", - "requirements": ["pywemo==0.5.0"], + "requirements": ["pywemo==0.5.2"], "ssdp": [ { "manufacturer": "Belkin International Inc." diff --git a/homeassistant/components/wemo/translations/lb.json b/homeassistant/components/wemo/translations/lb.json index 9ec38088d1b..f718754665c 100644 --- a/homeassistant/components/wemo/translations/lb.json +++ b/homeassistant/components/wemo/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "no_devices_found": "Keng Wemo Apparater am Netzwierk fonnt.", - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun Wemo ass erlaabt." + "no_devices_found": "Keng Apparater am Netzwierk fonnt.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "step": { "confirm": { diff --git a/homeassistant/components/wemo/translations/pl.json b/homeassistant/components/wemo/translations/pl.json index 406856aac8e..a8ee3fa57ac 100644 --- a/homeassistant/components/wemo/translations/pl.json +++ b/homeassistant/components/wemo/translations/pl.json @@ -6,7 +6,7 @@ }, "step": { "confirm": { - "description": "Czy chcesz skonfigurowa\u0107 Wemo?" + "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } } diff --git a/homeassistant/components/wiffi/manifest.json b/homeassistant/components/wiffi/manifest.json index fa06699ac08..2259b1a620e 100644 --- a/homeassistant/components/wiffi/manifest.json +++ b/homeassistant/components/wiffi/manifest.json @@ -4,7 +4,6 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/wiffi", "requirements": ["wiffi==1.0.1"], - "dependencies": [], "codeowners": [ "@mampfes" ] diff --git a/homeassistant/components/wiffi/translations/et.json b/homeassistant/components/wiffi/translations/et.json index ea0b813d0ee..d15b8d895f0 100644 --- a/homeassistant/components/wiffi/translations/et.json +++ b/homeassistant/components/wiffi/translations/et.json @@ -1,9 +1,23 @@ { "config": { + "abort": { + "addr_in_use": "Serveri port on juba kasutusel.", + "start_server_failed": "Serveri k\u00e4ivitamine nurjus." + }, "step": { "user": { "data": { "port": "" + }, + "title": "WIFFI seadmete TCP serveri seadistamine" + } + } + }, + "options": { + "step": { + "init": { + "data": { + "timeout": "Ajal\u00f5pp (minutites)" } } } diff --git a/homeassistant/components/wilight/translations/et.json b/homeassistant/components/wilight/translations/et.json index 87557468d2f..9f3236ded62 100644 --- a/homeassistant/components/wilight/translations/et.json +++ b/homeassistant/components/wilight/translations/et.json @@ -1,8 +1,11 @@ { "config": { "abort": { - "already_configured": "Seade on juba h\u00e4\u00e4lestatud" + "already_configured": "Seade on juba h\u00e4\u00e4lestatud", + "not_supported_device": "Seda WiLight'i sidumist ei toetata", + "not_wilight_device": "See seade ei ole WiLight" }, + "flow_title": "", "step": { "confirm": { "description": "Kas soovid seadistada WiLight'i {name} ?\n\n See toetab: {components}", diff --git a/homeassistant/components/wirelesstag/switch.py b/homeassistant/components/wirelesstag/switch.py index 11a5308d8d9..5866893888f 100644 --- a/homeassistant/components/wirelesstag/switch.py +++ b/homeassistant/components/wirelesstag/switch.py @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): switches = [] tags = platform.load_tags() for switch_type in config.get(CONF_MONITORED_CONDITIONS): - for _, tag in tags.items(): + for tag in tags.values(): if switch_type in tag.allowed_monitoring_types: switches.append(WirelessTagSwitch(platform, tag, switch_type)) diff --git a/homeassistant/components/withings/translations/ca.json b/homeassistant/components/withings/translations/ca.json index 18814d45d47..2d299c659ef 100644 --- a/homeassistant/components/withings/translations/ca.json +++ b/homeassistant/components/withings/translations/ca.json @@ -10,9 +10,7 @@ "default": "Autenticaci\u00f3 exitosa amb Withings." }, "error": { - "already_configured": "El compte ja ha estat configurat", - "already_configured_account": "El compte ja ha estat configurat", - "profile_exists": "El perfil ja est\u00e0 configurat. Proporciona un nom de perfil \u00fanic." + "already_configured": "El compte ja ha estat configurat" }, "flow_title": "Withings: {profile}", "step": { diff --git a/homeassistant/components/withings/translations/cs.json b/homeassistant/components/withings/translations/cs.json index cc4d14c210b..c6a84f3a296 100644 --- a/homeassistant/components/withings/translations/cs.json +++ b/homeassistant/components/withings/translations/cs.json @@ -9,8 +9,7 @@ "default": "\u00dasp\u011b\u0161n\u011b ov\u011b\u0159eno pomoc\u00ed Withings." }, "error": { - "already_configured": "\u00da\u010det je ji\u017e nastaven", - "already_configured_account": "\u00da\u010det je ji\u017e nastaven" + "already_configured": "\u00da\u010det je ji\u017e nastaven" }, "flow_title": "Withings: {profile}", "step": { diff --git a/homeassistant/components/withings/translations/en.json b/homeassistant/components/withings/translations/en.json index 616851bb503..45d1a642da3 100644 --- a/homeassistant/components/withings/translations/en.json +++ b/homeassistant/components/withings/translations/en.json @@ -10,9 +10,7 @@ "default": "Successfully authenticated with Withings." }, "error": { - "already_configured": "Account is already configured", - "already_configured_account": "Account is already configured", - "profile_exists": "User profile is already configured. Please provide a unique profile name." + "already_configured": "Account is already configured" }, "flow_title": "Withings: {profile}", "step": { diff --git a/homeassistant/components/withings/translations/es.json b/homeassistant/components/withings/translations/es.json index b554b0a78da..7f83e45c8c9 100644 --- a/homeassistant/components/withings/translations/es.json +++ b/homeassistant/components/withings/translations/es.json @@ -10,9 +10,7 @@ "default": "Autenticado correctamente con Withings." }, "error": { - "already_configured": "La cuenta ya ha sido configurada", - "already_configured_account": "La cuenta ya ha sido configurada", - "profile_exists": "El perfil de usuario ya est\u00e1 configurado. Por favor, proporciona un nombre de perfil \u00fanico." + "already_configured": "La cuenta ya ha sido configurada" }, "flow_title": "Withings: {profile}", "step": { diff --git a/homeassistant/components/withings/translations/et.json b/homeassistant/components/withings/translations/et.json index 79212f168e7..3cb42f8cf7e 100644 --- a/homeassistant/components/withings/translations/et.json +++ b/homeassistant/components/withings/translations/et.json @@ -6,17 +6,27 @@ "missing_configuration": "Osis pole seadistatud. Palun vaata dokumentatsiooni.", "no_url_available": "URL pole saadaval. Rohkem teavet [check the help section]({docs_url})" }, - "error": { - "already_configured": "Konto on juba seadistatud", - "already_configured_account": "Konto on juba h\u00e4\u00e4lestatud" + "create_entry": { + "default": "Edukalt Withing'siga autenditud." }, + "error": { + "already_configured": "Konto on juba seadistatud" + }, + "flow_title": "", "step": { "pick_implementation": { "title": "Vali tuvastusmeetod" }, + "profile": { + "data": { + "profile": "Profiili nimi" + }, + "description": "Anna neile andmetele ainulaadne profiilinimi. Tavaliselt on see eelmises etapis valitud profiili nimi.", + "title": "Kasutaja profiil." + }, "reauth": { "description": "Withingi andmete jsaamiseks tuleb kasutaja {profile} taastuvastada.", - "title": "Taastuvasta profiil" + "title": "Taastuvasta sidumine" } } } diff --git a/homeassistant/components/withings/translations/fr.json b/homeassistant/components/withings/translations/fr.json index a51efff7276..017a9e63078 100644 --- a/homeassistant/components/withings/translations/fr.json +++ b/homeassistant/components/withings/translations/fr.json @@ -10,7 +10,7 @@ "default": "Authentifi\u00e9 avec succ\u00e8s \u00e0 Withings pour le profil s\u00e9lectionn\u00e9." }, "error": { - "profile_exists": "Le profil utilisateur est d\u00e9j\u00e0 configur\u00e9. Veuillez fournir un nom de profil unique." + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9" }, "flow_title": "Withings: {profile}", "step": { diff --git a/homeassistant/components/withings/translations/it.json b/homeassistant/components/withings/translations/it.json index bceeffc70d2..85baeb1f0e0 100644 --- a/homeassistant/components/withings/translations/it.json +++ b/homeassistant/components/withings/translations/it.json @@ -10,9 +10,7 @@ "default": "Autenticazione riuscita con Withings." }, "error": { - "already_configured": "L'account \u00e8 gi\u00e0 configurato", - "already_configured_account": "L'account \u00e8 gi\u00e0 configurato", - "profile_exists": "Il profilo utente \u00e8 gi\u00e0 configurato. Si prega di fornire un nome di profilo univoco." + "already_configured": "L'account \u00e8 gi\u00e0 configurato" }, "flow_title": "Withings: {profile}", "step": { @@ -28,7 +26,7 @@ }, "reauth": { "description": "Il profilo \"{profile}\" deve essere autenticato nuovamente per continuare a ricevere i dati Withings.", - "title": "Riautenticare il profilo" + "title": "Reautenticare l'integrazione" } } } diff --git a/homeassistant/components/withings/translations/ko.json b/homeassistant/components/withings/translations/ko.json index a01672f2227..902f3c77e68 100644 --- a/homeassistant/components/withings/translations/ko.json +++ b/homeassistant/components/withings/translations/ko.json @@ -9,9 +9,6 @@ "create_entry": { "default": "Withings \ub85c \uc131\uacf5\uc801\uc73c\ub85c \uc778\uc99d\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, - "error": { - "profile_exists": "\uc0ac\uc6a9\uc790 \ud504\ub85c\ud544\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uace0\uc720\ud55c \ud504\ub85c\ud544 \uc774\ub984\uc744 \uc785\ub825\ud574\uc8fc\uc138\uc694." - }, "flow_title": "Withings: {profile}", "step": { "pick_implementation": { diff --git a/homeassistant/components/withings/translations/lb.json b/homeassistant/components/withings/translations/lb.json index 4f3efddc094..7169517eb09 100644 --- a/homeassistant/components/withings/translations/lb.json +++ b/homeassistant/components/withings/translations/lb.json @@ -3,30 +3,30 @@ "abort": { "already_configured": "Konfiguratioun aktualis\u00e9iert fir de Profil.", "authorize_url_timeout": "Z\u00e4it Iwwerschreidung beim gener\u00e9ieren vun der Autorisatiouns URL.", - "missing_configuration": "Withings Integratioun ass nach net konfigur\u00e9iert. Follegt w.e.g der Dokumentatioun.", + "missing_configuration": "Komponent ass nach net konfigur\u00e9iert. Follegt w.e.g der Dokumentatioun.", "no_url_available": "Keng URL disponibel. Fir Informatiounen iwwert d\u00ebse Feeler, [kuck H\u00ebllef Sektioun]({docs_url})" }, "create_entry": { "default": "Erfollegr\u00e4ich mat Withings authentifiz\u00e9iert." }, "error": { - "profile_exists": "Benotzer Profil ass scho konfigur\u00e9iert. G\u00ebff eem eenzegartege Profil Numm un" + "already_configured": "Kont ass scho konfigur\u00e9iert" }, "flow_title": "Withing: {profile}", "step": { "pick_implementation": { - "title": "Wielt Authentifikatiouns Method aus" + "title": "Wiel Authentifikatiouns Method aus" }, "profile": { "data": { - "profile": "Profil" + "profile": "Profil Numm" }, - "description": "W\u00e9ie Profil hutt dir op der Withings Webs\u00e4it ausgewielt? Et ass wichteg dass Profiller passen, soss ginn Donn\u00e9e\u00eb falsch gekennzeechent.", + "description": "G\u00ebff een eenzegartegen Profil Numm un. Typescherweise ass dat den Numm vum Profil deens du am viirechte Schr\u00ebtt ausgewielt hues.", "title": "Benotzer Profil." }, "reauth": { "description": "De Profil \"{profile}\" muss fr\u00ebsch authentifi\u00e9iert ginn fir weiderhinn Donn\u00e9e\u00eb vun Withing z'empf\u00e4nken.", - "title": "Profil fr\u00ebsch authentifiz\u00e9ieren" + "title": "Integratioun re-authentifiz\u00e9ieren" } } } diff --git a/homeassistant/components/withings/translations/nl.json b/homeassistant/components/withings/translations/nl.json index 94d62dbb5dd..21b2d6b11e9 100644 --- a/homeassistant/components/withings/translations/nl.json +++ b/homeassistant/components/withings/translations/nl.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "Configuratie bijgewerkt voor profiel.", "authorize_url_timeout": "Time-out tijdens genereren autorisatie url.", "missing_configuration": "De Withings integratie is niet geconfigureerd. Gelieve de documentatie te volgen.", "no_url_available": "Geen URL beschikbaar. Voor informatie over deze fout, [check de helpsectie]({docs_url})" @@ -9,7 +10,7 @@ "default": "Succesvol geverifieerd met Withings voor het geselecteerde profiel." }, "error": { - "already_configured_account": "Account is al geconfigureerd" + "already_configured": "Account is al geconfigureerd" }, "step": { "pick_implementation": { diff --git a/homeassistant/components/withings/translations/no.json b/homeassistant/components/withings/translations/no.json index 3d40dde3bbf..5fc7e1050ae 100644 --- a/homeassistant/components/withings/translations/no.json +++ b/homeassistant/components/withings/translations/no.json @@ -10,9 +10,7 @@ "default": "Vellykket godkjenning med Withings." }, "error": { - "already_configured": "Kontoen er allerede konfigurert", - "already_configured_account": "Kontoen er allerede konfigurert", - "profile_exists": "Brukerprofilen er allerede konfigurert. Oppgi et unikt profilnavn." + "already_configured": "Kontoen er allerede konfigurert" }, "flow_title": "", "step": { diff --git a/homeassistant/components/withings/translations/pl.json b/homeassistant/components/withings/translations/pl.json index 08442d5c35f..0eeac7899ae 100644 --- a/homeassistant/components/withings/translations/pl.json +++ b/homeassistant/components/withings/translations/pl.json @@ -7,12 +7,10 @@ "no_url_available": "Brak dost\u0119pnego adresu URL. Aby uzyska\u0107 informacje na temat tego b\u0142\u0119du, [sprawd\u017a sekcj\u0119 pomocy] ({docs_url})" }, "create_entry": { - "default": "Pomy\u015blnie uwierzytelniono z Withings dla wybranego profilu" + "default": "Pomy\u015blnie uwierzytelniono" }, "error": { - "already_configured": "Konto jest ju\u017c skonfigurowane", - "already_configured_account": "Konto jest ju\u017c skonfigurowane", - "profile_exists": "Profil u\u017cytkownika jest ju\u017c skonfigurowany. Podaj unikaln\u0105 nazw\u0119 profilu." + "already_configured": "Konto jest ju\u017c skonfigurowane" }, "flow_title": "Withings: {profile}", "step": { diff --git a/homeassistant/components/withings/translations/pt-BR.json b/homeassistant/components/withings/translations/pt-BR.json index 01556b760ad..f87b8b64576 100644 --- a/homeassistant/components/withings/translations/pt-BR.json +++ b/homeassistant/components/withings/translations/pt-BR.json @@ -2,9 +2,6 @@ "config": { "create_entry": { "default": "Autenticado com sucesso no Withings." - }, - "error": { - "already_configured_account": "Conta j\u00e1 configurada" } } } \ No newline at end of file diff --git a/homeassistant/components/withings/translations/ru.json b/homeassistant/components/withings/translations/ru.json index ff7b6c83bb9..f493fa4594f 100644 --- a/homeassistant/components/withings/translations/ru.json +++ b/homeassistant/components/withings/translations/ru.json @@ -10,9 +10,7 @@ "default": "\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e." }, "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.", - "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.", - "profile_exists": "\u041f\u0440\u043e\u0444\u0438\u043b\u044c \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d. \u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u043c\u044f \u043f\u0440\u043e\u0444\u0438\u043b\u044f." + "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." }, "flow_title": "Withings: {profile}", "step": { diff --git a/homeassistant/components/withings/translations/zh-Hant.json b/homeassistant/components/withings/translations/zh-Hant.json index a7214b0f250..394a42c5fd6 100644 --- a/homeassistant/components/withings/translations/zh-Hant.json +++ b/homeassistant/components/withings/translations/zh-Hant.json @@ -10,9 +10,7 @@ "default": "\u5df2\u6210\u529f\u8a8d\u8b49 Withings \u8a2d\u5099\u3002" }, "error": { - "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "already_configured_account": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "profile_exists": "\u4f7f\u7528\u8005\u500b\u4eba\u8a2d\u7f6e\u5df2\u7d93\u8a2d\u5b9a\uff0c\u8acb\u63d0\u4f9b\u7368\u4e00\u7684\u540d\u7a31\u3002" + "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "flow_title": "Withings\uff1a{profile}", "step": { diff --git a/homeassistant/components/wled/const.py b/homeassistant/components/wled/const.py index f50e17c01cc..e0880dd40fd 100644 --- a/homeassistant/components/wled/const.py +++ b/homeassistant/components/wled/const.py @@ -29,3 +29,4 @@ CURRENT_MA = "mA" # Services SERVICE_EFFECT = "effect" +SERVICE_PRESET = "preset" diff --git a/homeassistant/components/wled/light.py b/homeassistant/components/wled/light.py index 9c6d027b058..527d985a47b 100644 --- a/homeassistant/components/wled/light.py +++ b/homeassistant/components/wled/light.py @@ -42,6 +42,7 @@ from .const import ( ATTR_SPEED, DOMAIN, SERVICE_EFFECT, + SERVICE_PRESET, ) PARALLEL_UPDATES = 1 @@ -73,6 +74,16 @@ async def async_setup_entry( "async_effect", ) + platform.async_register_entity_service( + SERVICE_PRESET, + { + vol.Required(ATTR_PRESET): vol.All( + vol.Coerce(int), vol.Range(min=-1, max=65535) + ), + }, + "async_preset", + ) + update_segments = partial( async_update_segments, entry, coordinator, {}, async_add_entities ) @@ -372,6 +383,16 @@ class WLEDSegmentLight(LightEntity, WLEDDeviceEntity): await self.coordinator.wled.segment(**data) + @wled_exception_handler + async def async_preset( + self, + preset: int, + ) -> None: + """Set a WLED light to a saved preset.""" + data = {ATTR_PRESET: preset} + + await self.coordinator.wled.preset(**data) + @callback def async_update_segments( diff --git a/homeassistant/components/wled/services.yaml b/homeassistant/components/wled/services.yaml index 7b9a8d01ba1..1f1fa1b809d 100644 --- a/homeassistant/components/wled/services.yaml +++ b/homeassistant/components/wled/services.yaml @@ -8,7 +8,7 @@ effect: description: Name or ID of the WLED light effect. example: "Rainbow" intensity: - description: Intensity of the effect + description: Intensity of the effect. Number between 0 and 255. example: 100 palette: description: Name or ID of the WLED light palette. @@ -19,3 +19,12 @@ effect: reverse: description: Reverse the effect. Either true to reverse or false otherwise. example: false +preset: + description: Calls a preset on the WLED device + fields: + entity_id: + description: Name of the WLED light entity. + example: "light.wled" + preset: + description: ID of the WLED preset + example: 6 diff --git a/homeassistant/components/wled/translations/ca.json b/homeassistant/components/wled/translations/ca.json index 6eee56045b6..512a7de3ca4 100644 --- a/homeassistant/components/wled/translations/ca.json +++ b/homeassistant/components/wled/translations/ca.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar amb el dispositiu WLED." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "error": { - "cannot_connect": "Ha fallat la connexi\u00f3", - "connection_error": "No s'ha pogut connectar amb el dispositiu WLED." + "cannot_connect": "Ha fallat la connexi\u00f3" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/cs.json b/homeassistant/components/wled/translations/cs.json index ef5bca151fe..6f8e3392c0c 100644 --- a/homeassistant/components/wled/translations/cs.json +++ b/homeassistant/components/wled/translations/cs.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed WLED se nezda\u0159ilo." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "error": { - "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connection_error": "P\u0159ipojen\u00ed k za\u0159\u00edzen\u00ed WLED se nezda\u0159ilo." + "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit" }, "flow_title": "WLED: {name}", "step": { @@ -18,7 +16,7 @@ "description": "Nastavte WLED k integraci s Home Assistant." }, "zeroconf_confirm": { - "description": "Chcete p\u0159idat WLED se jm\u00e9nem {name} do Home Assistant?", + "description": "Chcete p\u0159idat WLED se jm\u00e9nem `{name}` do Home Assistant?", "title": "Nalezen\u00e9 za\u0159\u00edzen\u00ed WLED" } } diff --git a/homeassistant/components/wled/translations/de.json b/homeassistant/components/wled/translations/de.json index 8a6aa1af160..ff12e429bd6 100644 --- a/homeassistant/components/wled/translations/de.json +++ b/homeassistant/components/wled/translations/de.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Dieses WLED-Ger\u00e4t ist bereits konfiguriert.", - "connection_error": "Verbindung zum WLED-Ger\u00e4t fehlgeschlagen." - }, - "error": { - "connection_error": "Verbindung zum WLED-Ger\u00e4t fehlgeschlagen." + "already_configured": "Dieses WLED-Ger\u00e4t ist bereits konfiguriert." }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/en.json b/homeassistant/components/wled/translations/en.json index aa448672bf2..073db955f93 100644 --- a/homeassistant/components/wled/translations/en.json +++ b/homeassistant/components/wled/translations/en.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Device is already configured", - "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect to WLED device." + "cannot_connect": "Failed to connect" }, "error": { - "cannot_connect": "Failed to connect", - "connection_error": "Failed to connect to WLED device." + "cannot_connect": "Failed to connect" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/es.json b/homeassistant/components/wled/translations/es.json index ba57fbab904..77c324f46a1 100644 --- a/homeassistant/components/wled/translations/es.json +++ b/homeassistant/components/wled/translations/es.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Este dispositivo WLED ya est\u00e1 configurado.", - "cannot_connect": "No se pudo conectar", - "connection_error": "No se ha podido conectar al dispositivo WLED." + "cannot_connect": "No se pudo conectar" }, "error": { - "cannot_connect": "No se pudo conectar", - "connection_error": "No se ha podido conectar al dispositivo WLED." + "cannot_connect": "No se pudo conectar" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/et.json b/homeassistant/components/wled/translations/et.json index 4c5b7f22a98..e32427a1b7d 100644 --- a/homeassistant/components/wled/translations/et.json +++ b/homeassistant/components/wled/translations/et.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "See WLED seade on juba h\u00e4\u00e4lestatud.", - "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "WLED-seadmega \u00fchenduse loomine nurjus." + "cannot_connect": "\u00dchendamine nurjus" }, "error": { - "cannot_connect": "\u00dchendamine nurjus", - "connection_error": "WLED-seadmega \u00fchenduse loomine nurjus." + "cannot_connect": "\u00dchendamine nurjus" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/fr.json b/homeassistant/components/wled/translations/fr.json index 79ab5ab876b..137decb7f40 100644 --- a/homeassistant/components/wled/translations/fr.json +++ b/homeassistant/components/wled/translations/fr.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Cet appareil WLED est d\u00e9j\u00e0 configur\u00e9.", - "cannot_connect": "\u00c9chec de connexion", - "connection_error": "Impossible de se connecter au p\u00e9riph\u00e9rique WLED." + "cannot_connect": "\u00c9chec de connexion" }, "error": { - "cannot_connect": "\u00c9chec de connexion", - "connection_error": "Impossible de se connecter au p\u00e9riph\u00e9rique WLED." + "cannot_connect": "\u00c9chec de connexion" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/hu.json b/homeassistant/components/wled/translations/hu.json index f86a02da7c9..40f6f151a2d 100644 --- a/homeassistant/components/wled/translations/hu.json +++ b/homeassistant/components/wled/translations/hu.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Ez a WLED eszk\u00f6z m\u00e1r konfigur\u00e1lva van.", - "connection_error": "Nem siker\u00fclt csatlakozni a WLED eszk\u00f6zh\u00f6z." - }, - "error": { - "connection_error": "Nem siker\u00fclt csatlakozni a WLED eszk\u00f6zh\u00f6z." + "already_configured": "Ez a WLED eszk\u00f6z m\u00e1r konfigur\u00e1lva van." }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/it.json b/homeassistant/components/wled/translations/it.json index d6760328db5..d34e1a98301 100644 --- a/homeassistant/components/wled/translations/it.json +++ b/homeassistant/components/wled/translations/it.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi al dispositivo WLED." + "cannot_connect": "Impossibile connettersi" }, "error": { - "cannot_connect": "Impossibile connettersi", - "connection_error": "Impossibile connettersi al dispositivo WLED." + "cannot_connect": "Impossibile connettersi" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/ko.json b/homeassistant/components/wled/translations/ko.json index 684f0879b55..2adb7985fd3 100644 --- a/homeassistant/components/wled/translations/ko.json +++ b/homeassistant/components/wled/translations/ko.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "\uc774 WLED \uae30\uae30\ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", - "connection_error": "WLED \uae30\uae30\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." - }, - "error": { - "connection_error": "WLED \uae30\uae30\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4." + "already_configured": "\uc774 WLED \uae30\uae30\ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/lb.json b/homeassistant/components/wled/translations/lb.json index 6843b74174f..4394176b647 100644 --- a/homeassistant/components/wled/translations/lb.json +++ b/homeassistant/components/wled/translations/lb.json @@ -1,13 +1,11 @@ { "config": { "abort": { - "already_configured": "D\u00ebsen WLED Apparat ass scho konfigur\u00e9iert.", - "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen mam WLED Apparat." + "already_configured": "Apparat ass scho konfigur\u00e9iert.", + "cannot_connect": "Feeler beim verbannen" }, "error": { - "cannot_connect": "Feeler beim verbannen", - "connection_error": "Feeler beim verbannen mam WLED Apparat." + "cannot_connect": "Feeler beim verbannen" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/nl.json b/homeassistant/components/wled/translations/nl.json index 08f420d5042..329716e2cd5 100644 --- a/homeassistant/components/wled/translations/nl.json +++ b/homeassistant/components/wled/translations/nl.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Dit WLED-apparaat is al geconfigureerd.", - "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met WLED-apparaat." + "cannot_connect": "Kan geen verbinding maken" }, "error": { - "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met WLED-apparaat." + "cannot_connect": "Kan geen verbinding maken" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/no.json b/homeassistant/components/wled/translations/no.json index b3a98e3ab4a..a81683ce4c8 100644 --- a/homeassistant/components/wled/translations/no.json +++ b/homeassistant/components/wled/translations/no.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Enheten er allerede konfigurert", - "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kunne ikke koble til WLED-enheten." + "cannot_connect": "Tilkobling mislyktes" }, "error": { - "cannot_connect": "Tilkobling mislyktes", - "connection_error": "Kunne ikke koble til WLED-enheten." + "cannot_connect": "Tilkobling mislyktes" }, "flow_title": "", "step": { diff --git a/homeassistant/components/wled/translations/pl.json b/homeassistant/components/wled/translations/pl.json index 800c190c64c..f73e7d05651 100644 --- a/homeassistant/components/wled/translations/pl.json +++ b/homeassistant/components/wled/translations/pl.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "error": { - "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia" }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/ru.json b/homeassistant/components/wled/translations/ru.json index 3700aa6cc30..deef7e358f1 100644 --- a/homeassistant/components/wled/translations/ru.json +++ b/homeassistant/components/wled/translations/ru.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "error": { - "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connection_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443." + "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f." }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/sl.json b/homeassistant/components/wled/translations/sl.json index 086e8d111ab..60ec56ebb55 100644 --- a/homeassistant/components/wled/translations/sl.json +++ b/homeassistant/components/wled/translations/sl.json @@ -1,11 +1,7 @@ { "config": { "abort": { - "already_configured": "Ta naprava WLED je \u017ee konfigurirana.", - "connection_error": "Povezava z napravo WLED ni uspela." - }, - "error": { - "connection_error": "Povezava z napravo WLED ni uspela." + "already_configured": "Ta naprava WLED je \u017ee konfigurirana." }, "flow_title": "WLED: {name}", "step": { diff --git a/homeassistant/components/wled/translations/zh-Hant.json b/homeassistant/components/wled/translations/zh-Hant.json index 26d49a34688..37c74d07f51 100644 --- a/homeassistant/components/wled/translations/zh-Hant.json +++ b/homeassistant/components/wled/translations/zh-Hant.json @@ -2,12 +2,10 @@ "config": { "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "WLED \u8a2d\u5099\u9023\u7dda\u5931\u6557\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "error": { - "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connection_error": "WLED \u8a2d\u5099\u9023\u7dda\u5931\u6557\u3002" + "cannot_connect": "\u9023\u7dda\u5931\u6557" }, "flow_title": "WLED\uff1a{name}", "step": { diff --git a/homeassistant/components/wolflink/translations/cs.json b/homeassistant/components/wolflink/translations/cs.json index b66ca57cd44..e532b833851 100644 --- a/homeassistant/components/wolflink/translations/cs.json +++ b/homeassistant/components/wolflink/translations/cs.json @@ -12,7 +12,8 @@ "device": { "data": { "device_name": "Za\u0159\u00edzen\u00ed" - } + }, + "title": "Vyberte za\u0159\u00edzen\u00ed WOLF" }, "user": { "data": { diff --git a/homeassistant/components/wolflink/translations/et.json b/homeassistant/components/wolflink/translations/et.json index 04c0ea2a1cf..1c7a7a09b3b 100644 --- a/homeassistant/components/wolflink/translations/et.json +++ b/homeassistant/components/wolflink/translations/et.json @@ -9,11 +9,18 @@ "unknown": "Tundmatu viga" }, "step": { + "device": { + "data": { + "device_name": "Seade" + }, + "title": "Vali WOLF seade" + }, "user": { "data": { "password": "Salas\u00f5na", "username": "Kasutajanimi" - } + }, + "title": "WOLF SmartSeti \u00fchendus" } } } diff --git a/homeassistant/components/wolflink/translations/nl.json b/homeassistant/components/wolflink/translations/nl.json index 4d00f0bfc74..7fb1b867cdd 100644 --- a/homeassistant/components/wolflink/translations/nl.json +++ b/homeassistant/components/wolflink/translations/nl.json @@ -1,8 +1,16 @@ { "config": { + "abort": { + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "invalid_auth": "Ongeldige authenticatie", + "unknown": "Onverwachte fout" + }, "step": { "user": { "data": { + "password": "Wachtwoord", "username": "Gebruikersnaam" } } diff --git a/homeassistant/components/wolflink/translations/sensor.cs.json b/homeassistant/components/wolflink/translations/sensor.cs.json index fded9a5b839..046fc4e6ed9 100644 --- a/homeassistant/components/wolflink/translations/sensor.cs.json +++ b/homeassistant/components/wolflink/translations/sensor.cs.json @@ -1,11 +1,29 @@ { "state": { "wolflink__state": { + "aktiviert": "Aktivov\u00e1no", + "aus": "Zak\u00e1z\u00e1no", "auto": "Automatika", + "automatik_aus": "Automatick\u00e9 vypnut\u00ed", + "automatik_ein": "Automatick\u00e9 zapnut\u00ed", "cooling": "Chlazen\u00ed", + "deaktiviert": "Neaktivn\u00ed", + "eco": "Ekonomick\u00fd re\u017eim", + "ein": "Povoleno", + "externe_deaktivierung": "Extern\u00ed deaktivace", + "frostschutz": "Ochrana proti mrazu", + "gasdruck": "Tlak plynu", "heizbetrieb": "Re\u017eim topen\u00ed", "heizung": "Topen\u00ed", + "initialisierung": "Inicializace", + "kalibration": "Kalibrace", "permanent": "Trval\u00fd", + "schornsteinfeger": "Zkou\u0161ka emis\u00ed", + "smart_grid": "SmartGrid", + "smart_home": "SmartHome", + "softstart": "M\u011bkk\u00fd start", + "sparbetrieb": "Ekonomick\u00fd re\u017eim", + "sparen": "Ekonomick\u00fd re\u017eim", "standby": "Pohotovostn\u00ed re\u017eim", "start": "Start", "storung": "Chyba", diff --git a/homeassistant/components/wolflink/translations/sensor.et.json b/homeassistant/components/wolflink/translations/sensor.et.json index cbbe3647f03..db6e5db23e6 100644 --- a/homeassistant/components/wolflink/translations/sensor.et.json +++ b/homeassistant/components/wolflink/translations/sensor.et.json @@ -1,15 +1,86 @@ { "state": { "wolflink__state": { + "1_x_warmwasser": "", + "abgasklappe": "Suitsugaasi siiber", + "absenkbetrieb": "Tagasil\u00f6\u00f6gi re\u017eiim", + "absenkstop": "Tagasil\u00f6\u00f6gi peatamine", + "aktiviert": "Aktiveeritud", + "antilegionellenfunktion": "Legionella vastane funktsioon", + "at_abschaltung": "OT sulgumine", + "at_frostschutz": "OT k\u00fclmakaitse", + "aus": "Keelatud", + "auto": "Automaatne", + "auto_off_cool": "AutoOffCool", + "auto_on_cool": "AutoOnCool", + "automatik_aus": "Automaatne V\u00c4LJAS", + "automatik_ein": "Automaatne SEES", + "bereit_keine_ladung": "Valmis, ei laadita", + "betrieb_ohne_brenner": "T\u00f6\u00f6tamine ilma p\u00f5letita", + "cooling": "Jahutamine", + "deaktiviert": "Passiivne", + "dhw_prior": "", + "eco": "\u00d6ko", + "ein": "Lubatud", + "estrichtrocknung": "Tasanduskihi kuivatamine", + "externe_deaktivierung": "V\u00e4line deaktiveerimine", + "fernschalter_ein": "Kaugjuhtimine on lubatud", + "frost_heizkreis": "K\u00fcttekontuuri k\u00fclmakaitse", + "frost_warmwasser": "DHW k\u00fclmakaitse", + "frostschutz": "K\u00fclmumiskaitse", + "gasdruck": "Gaasi r\u00f5hk", + "glt_betrieb": "BMS-re\u017eiim", + "gradienten_uberwachung": "Muutuste j\u00e4lgimine", + "heizbetrieb": "K\u00fcttere\u017eiim", + "heizgerat_mit_speicher": "Salvestiga katel", + "heizung": "K\u00fcte", + "initialisierung": "L\u00e4htestamine", + "kalibration": "Kalibreerimine", + "kalibration_heizbetrieb": "K\u00fcttere\u017eiimi kalibreerimine", + "kalibration_kombibetrieb": "Kombire\u017eiimi kalibreerimine", + "kalibration_warmwasserbetrieb": "DHW kalibreerimine", + "kaskadenbetrieb": "J\u00e4rjestikkune toimimine", + "kombibetrieb": "Kombire\u017eiim", + "kombigerat": "Kombineeritud k\u00fcttega katel", + "kombigerat_mit_solareinbindung": "P\u00e4ikeseintegratsiooniga katel", + "mindest_kombizeit": "Minimaalne liitaeg", + "nachlauf_heizkreispumpe": "K\u00fcttekontuuri pumba j\u00e4relt\u00f6\u00f6", + "nachspulen": "J\u00e4relloputus", + "nur_heizgerat": "Ainult katel", + "parallelbetrieb": "Paralleelre\u017eiim", + "partymodus": "Peore\u017eiim", + "perm_cooling": "P\u00fcsijahutus", "permanent": "Alaline", "permanentbetrieb": "P\u00fcsire\u017eiim", + "reduzierter_betrieb": "Piiratud re\u017eiim", + "rt_abschaltung": "RT sulgumine", + "rt_frostschutz": "RT k\u00fclmakaitse", + "ruhekontakt": "Puhkekontakt", + "schornsteinfeger": "Saastetest", + "smart_grid": "", + "smart_home": "", + "softstart": "Pehme k\u00e4ivitus", "solarbetrieb": "P\u00e4ikesek\u00fctte re\u017eiim", "sparbetrieb": "S\u00e4\u00e4sture\u017eiim", + "sparen": "S\u00e4\u00e4sture\u017eiim", + "spreizung_hoch": "temperatuurivahemik liiga suur", + "spreizung_kf": "KF-i hajutamine", "stabilisierung": "Rahunemine", "standby": "Ootel", "start": "K\u00e4ivitus", "storung": "Viga", + "taktsperre": "Ts\u00fcklivastane", + "telefonfernschalter": "Telefoni kaugl\u00fclitus", "test": "Kontroll", + "tpw": "", + "urlaubsmodus": "Puhkusere\u017eiim", + "ventilprufung": "Ventiili test", + "vorspulen": "Eelloputus", + "warmwasser": "", + "warmwasser_schnellstart": "DHW kiirk\u00e4ivitus", + "warmwasserbetrieb": "DHW re\u017eiim", + "warmwassernachlauf": "DHW run-on", + "warmwasservorrang": "DHW prioriteet", "zunden": "S\u00fc\u00fcde" } } diff --git a/homeassistant/components/wolflink/translations/sensor.lb.json b/homeassistant/components/wolflink/translations/sensor.lb.json index b57d2c8747a..f18adf6693e 100644 --- a/homeassistant/components/wolflink/translations/sensor.lb.json +++ b/homeassistant/components/wolflink/translations/sensor.lb.json @@ -19,6 +19,7 @@ "betrieb_ohne_brenner": "Betrib ouni Brenner", "cooling": "Ofkillen", "deaktiviert": "Inaktiv", + "dhw_prior": "DHWPrior", "eco": "Eco", "ein": "Aktiv\u00e9iert", "estrichtrocknung": "Chape dr\u00e9chnen", diff --git a/homeassistant/components/wolflink/translations/sensor.tr.json b/homeassistant/components/wolflink/translations/sensor.tr.json index 91160e3569a..8b2eb0a8c53 100644 --- a/homeassistant/components/wolflink/translations/sensor.tr.json +++ b/homeassistant/components/wolflink/translations/sensor.tr.json @@ -1,7 +1,7 @@ { "state": { "wolflink__state": { - "standby": "Bekleme modu", + "standby": "Bekleme", "start": "Ba\u015flat", "storung": "Hata", "test": "Test" diff --git a/homeassistant/components/workday/binary_sensor.py b/homeassistant/components/workday/binary_sensor.py index 8f8b794515e..44f30cf9538 100644 --- a/homeassistant/components/workday/binary_sensor.py +++ b/homeassistant/components/workday/binary_sensor.py @@ -20,6 +20,7 @@ CONF_WORKDAYS = "workdays" CONF_EXCLUDES = "excludes" CONF_OFFSET = "days_offset" CONF_ADD_HOLIDAYS = "add_holidays" +CONF_REMOVE_HOLIDAYS = "remove_holidays" # By default, Monday - Friday are workdays DEFAULT_WORKDAYS = ["mon", "tue", "wed", "thu", "fri"] @@ -60,6 +61,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( cv.ensure_list, [vol.In(ALLOWED_DAYS)] ), vol.Optional(CONF_ADD_HOLIDAYS): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(CONF_REMOVE_HOLIDAYS): vol.All(cv.ensure_list, [cv.string]), } ) @@ -67,6 +69,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Workday sensor.""" add_holidays = config.get(CONF_ADD_HOLIDAYS) + remove_holidays = config.get(CONF_REMOVE_HOLIDAYS) country = config[CONF_COUNTRY] days_offset = config[CONF_OFFSET] excludes = config[CONF_EXCLUDES] @@ -96,6 +99,13 @@ def setup_platform(hass, config, add_entities, discovery_info=None): except TypeError: _LOGGER.debug("No custom holidays or invalid holidays") + # Remove holidays + try: + for date in remove_holidays: + obj_holidays.pop(date) + except TypeError: + _LOGGER.debug("No holidays to remove or invalid holidays") + _LOGGER.debug("Found the following holidays for your configuration:") for date, name in sorted(obj_holidays.items()): _LOGGER.debug("%s %s", date, name) diff --git a/homeassistant/components/xbox/media_player.py b/homeassistant/components/xbox/media_player.py index 41aaa7eeb9c..19e8a90d48e 100644 --- a/homeassistant/components/xbox/media_player.py +++ b/homeassistant/components/xbox/media_player.py @@ -111,10 +111,9 @@ class XboxMediaPlayer(CoordinatorEntity, MediaPlayerEntity): @property def supported_features(self): """Flag media player features that are supported.""" - active_support = SUPPORT_XBOX if self.state not in [STATE_PLAYING, STATE_PAUSED]: - active_support &= ~SUPPORT_NEXT_TRACK & ~SUPPORT_PREVIOUS_TRACK - return active_support + return SUPPORT_XBOX & ~SUPPORT_NEXT_TRACK & ~SUPPORT_PREVIOUS_TRACK + return SUPPORT_XBOX @property def media_content_type(self): diff --git a/homeassistant/components/xbox/translations/ca.json b/homeassistant/components/xbox/translations/ca.json index 8b85898dfd6..e0fe185973b 100644 --- a/homeassistant/components/xbox/translations/ca.json +++ b/homeassistant/components/xbox/translations/ca.json @@ -13,6 +13,5 @@ "title": "Selecciona el m\u00e8tode d'autenticaci\u00f3" } } - }, - "title": "xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/cs.json b/homeassistant/components/xbox/translations/cs.json index 0bc97c8e002..8085b42642b 100644 --- a/homeassistant/components/xbox/translations/cs.json +++ b/homeassistant/components/xbox/translations/cs.json @@ -13,6 +13,5 @@ "title": "Vyberte metodu ov\u011b\u0159en\u00ed" } } - }, - "title": "Xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/de.json b/homeassistant/components/xbox/translations/de.json index dac1d5644e9..c67f3a49ea4 100644 --- a/homeassistant/components/xbox/translations/de.json +++ b/homeassistant/components/xbox/translations/de.json @@ -8,6 +8,5 @@ "title": "Authentifizierungsmethode w\u00e4hlen" } } - }, - "title": "xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/es.json b/homeassistant/components/xbox/translations/es.json index 3b06bdff853..52fb998dfd3 100644 --- a/homeassistant/components/xbox/translations/es.json +++ b/homeassistant/components/xbox/translations/es.json @@ -13,6 +13,5 @@ "title": "Selecciona el m\u00e9todo de autenticaci\u00f3n" } } - }, - "title": "xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/et.json b/homeassistant/components/xbox/translations/et.json index 2504817b6d6..d7bb66c6cf1 100644 --- a/homeassistant/components/xbox/translations/et.json +++ b/homeassistant/components/xbox/translations/et.json @@ -3,7 +3,7 @@ "abort": { "authorize_url_timeout": "Tuvastamise URL'i loomise ajal\u00f5pp.", "missing_configuration": "Osis pole seadistatud. Palun vaata dokumentatsiooni.", - "single_instance_allowed": "Seade on juba lisatud. Lubatud on ainult \u00fcks seadistamine." + "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "create_entry": { "default": "Edukalt tuvastatud" @@ -13,6 +13,5 @@ "title": "Vali tuvastusmeetod" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/fr.json b/homeassistant/components/xbox/translations/fr.json new file mode 100644 index 00000000000..a0dc75cc214 --- /dev/null +++ b/homeassistant/components/xbox/translations/fr.json @@ -0,0 +1,17 @@ +{ + "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" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/it.json b/homeassistant/components/xbox/translations/it.json index 2b6077b9c70..010baad571e 100644 --- a/homeassistant/components/xbox/translations/it.json +++ b/homeassistant/components/xbox/translations/it.json @@ -13,6 +13,5 @@ "title": "Scegli il metodo di autenticazione" } } - }, - "title": "Xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/lb.json b/homeassistant/components/xbox/translations/lb.json new file mode 100644 index 00000000000..d305909389f --- /dev/null +++ b/homeassistant/components/xbox/translations/lb.json @@ -0,0 +1,8 @@ +{ + "config": { + "abort": { + "missing_configuration": "Komponent net konfigur\u00e9iert. Folleg w.e.g der Dokumentatioun.", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." + } + } +} \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/nl.json b/homeassistant/components/xbox/translations/nl.json deleted file mode 100644 index 5a4bc8da0f6..00000000000 --- a/homeassistant/components/xbox/translations/nl.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "xbox" -} \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/no.json b/homeassistant/components/xbox/translations/no.json index ca7f7ac3d4f..49ccd378c1d 100644 --- a/homeassistant/components/xbox/translations/no.json +++ b/homeassistant/components/xbox/translations/no.json @@ -13,6 +13,5 @@ "title": "Velg godkjenningsmetode" } } - }, - "title": "Xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/pl.json b/homeassistant/components/xbox/translations/pl.json index 7532e8cd529..b4a5c4d8f38 100644 --- a/homeassistant/components/xbox/translations/pl.json +++ b/homeassistant/components/xbox/translations/pl.json @@ -13,6 +13,5 @@ "title": "Wybierz metod\u0119 uwierzytelniania" } } - }, - "title": "Xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/ru.json b/homeassistant/components/xbox/translations/ru.json index 3e6afd408c9..b47907ffb86 100644 --- a/homeassistant/components/xbox/translations/ru.json +++ b/homeassistant/components/xbox/translations/ru.json @@ -13,6 +13,5 @@ "title": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u043f\u043e\u0441\u043e\u0431 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438" } } - }, - "title": "Xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xbox/translations/zh-Hant.json b/homeassistant/components/xbox/translations/zh-Hant.json index c5514515664..477bd13374c 100644 --- a/homeassistant/components/xbox/translations/zh-Hant.json +++ b/homeassistant/components/xbox/translations/zh-Hant.json @@ -13,6 +13,5 @@ "title": "\u9078\u64c7\u9a57\u8b49\u6a21\u5f0f" } } - }, - "title": "xbox" + } } \ No newline at end of file diff --git a/homeassistant/components/xiaomi_aqara/manifest.json b/homeassistant/components/xiaomi_aqara/manifest.json index 4b6cd76985d..eb115b6471d 100644 --- a/homeassistant/components/xiaomi_aqara/manifest.json +++ b/homeassistant/components/xiaomi_aqara/manifest.json @@ -3,7 +3,7 @@ "name": "Xiaomi Gateway (Aqara)", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/xiaomi_aqara", - "requirements": ["PyXiaomiGateway==0.13.3"], + "requirements": ["PyXiaomiGateway==0.13.4"], "after_dependencies": ["discovery"], "codeowners": ["@danielhiversen", "@syssi"], "zeroconf": ["_miio._udp.local."] diff --git a/homeassistant/components/xiaomi_aqara/switch.py b/homeassistant/components/xiaomi_aqara/switch.py index aee66e1a439..6e75ddb487e 100644 --- a/homeassistant/components/xiaomi_aqara/switch.py +++ b/homeassistant/components/xiaomi_aqara/switch.py @@ -37,19 +37,34 @@ async def async_setup_entry(hass, config_entry, async_add_entities): device, "Plug", data_key, True, gateway, config_entry ) ) - elif model in ["ctrl_neutral1", "ctrl_neutral1.aq1", "switch_b1lacn02"]: + elif model in [ + "ctrl_neutral1", + "ctrl_neutral1.aq1", + "switch_b1lacn02", + "switch.b1lacn02", + ]: entities.append( XiaomiGenericSwitch( device, "Wall Switch", "channel_0", False, gateway, config_entry ) ) - elif model in ["ctrl_ln1", "ctrl_ln1.aq1", "switch_b1nacn02"]: + elif model in [ + "ctrl_ln1", + "ctrl_ln1.aq1", + "switch_b1nacn02", + "switch.b1nacn02", + ]: entities.append( XiaomiGenericSwitch( device, "Wall Switch LN", "channel_0", False, gateway, config_entry ) ) - elif model in ["ctrl_neutral2", "ctrl_neutral2.aq1", "switch_b2lacn02"]: + elif model in [ + "ctrl_neutral2", + "ctrl_neutral2.aq1", + "switch_b2lacn02", + "switch.b2lacn02", + ]: entities.append( XiaomiGenericSwitch( device, @@ -70,7 +85,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities): config_entry, ) ) - elif model in ["ctrl_ln2", "ctrl_ln2.aq1", "switch_b2nacn02"]: + elif model in [ + "ctrl_ln2", + "ctrl_ln2.aq1", + "switch_b2nacn02", + "switch.b2nacn02", + ]: entities.append( XiaomiGenericSwitch( device, diff --git a/homeassistant/components/xiaomi_aqara/translations/ca.json b/homeassistant/components/xiaomi_aqara/translations/ca.json index ad8259ceddc..23502d50d9c 100644 --- a/homeassistant/components/xiaomi_aqara/translations/ca.json +++ b/homeassistant/components/xiaomi_aqara/translations/ca.json @@ -10,8 +10,7 @@ "invalid_host": "Nom de l'amfitri\u00f3 o l'adre\u00e7a IP inv\u00e0lids, consulta https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "Interf\u00edcie de xarxa no v\u00e0lida", "invalid_key": "Clau de la passarel\u00b7la no v\u00e0lida", - "invalid_mac": "Adre\u00e7a MAC no v\u00e0lida", - "not_found_error": "No s'ha pogut descobrir cap passarel\u00b7la Zeroconf per obtenir informaci\u00f3 necess\u00e0ria, prova d'utilitzar la IP del dispositiu que executa Home Assistant com a interf\u00edcie" + "invalid_mac": "Adre\u00e7a MAC no v\u00e0lida" }, "flow_title": "Passarel\u00b7la Xiaomi Aqara: {name}", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/cs.json b/homeassistant/components/xiaomi_aqara/translations/cs.json index 36412d13798..b344be8c647 100644 --- a/homeassistant/components/xiaomi_aqara/translations/cs.json +++ b/homeassistant/components/xiaomi_aqara/translations/cs.json @@ -2,9 +2,11 @@ "config": { "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1" + "already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1", + "not_xiaomi_aqara": "Za\u0159\u00edzen\u00ed nen\u00ed br\u00e1na Xiaomi Aqara, objeven\u00e9 za\u0159\u00edzen\u00ed neodpov\u00edd\u00e1 zn\u00e1m\u00fdm bran\u00e1m" }, "error": { + "discovery_error": "Nepoda\u0159ilo se naj\u00edt br\u00e1nu Xiaomi Aqara, zkuste jako rozhran\u00ed pou\u017e\u00edt IP adresu za\u0159\u00edzen\u00ed, na kter\u00e9m je spu\u0161t\u011bn HomeAssistant.", "invalid_host": "Neplatn\u00fd hostitel nebo IP adresa , viz https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "Neplatn\u00e9 s\u00ed\u0165ov\u00e9 rozhran\u00ed", "invalid_key": "Neplatn\u00fd kl\u00ed\u010d br\u00e1ny", @@ -16,13 +18,16 @@ "data": { "select_ip": "IP adresa" }, + "description": "Chcete-li p\u0159ipojit dal\u0161\u00ed br\u00e1ny, spus\u0165te znovu instalaci", "title": "Vyberte br\u00e1nu Xiaomi Aqara, kterou chcete p\u0159ipojit" }, "settings": { "data": { "key": "Kl\u00ed\u010d va\u0161\u00ed br\u00e1ny", "name": "Jm\u00e9no br\u00e1ny" - } + }, + "description": "Kl\u00ed\u010d (heslo) lze z\u00edskat pomoc\u00ed tohoto n\u00e1vodu: https://www.domoticz.com/wiki/Xiaomi_Gateway_(Aqara)#Adding_the_Xiaomi_Gateway_to_Domoticz. Pokud kl\u00ed\u010d nen\u00ed k dispozici, budou p\u0159\u00edstupn\u00e9 pouze senzory", + "title": "Br\u00e1na Xiaomi Aqara, voliteln\u00e1 nastaven\u00ed" }, "user": { "data": { diff --git a/homeassistant/components/xiaomi_aqara/translations/de.json b/homeassistant/components/xiaomi_aqara/translations/de.json index 75aa3d537e8..f86868987a0 100644 --- a/homeassistant/components/xiaomi_aqara/translations/de.json +++ b/homeassistant/components/xiaomi_aqara/translations/de.json @@ -2,7 +2,13 @@ "config": { "flow_title": "Xiaomi Aqara Gateway: {name}", "step": { + "select": { + "data": { + "select_ip": "IP-Adresse" + } + }, "user": { + "description": "Stellen Sie eine Verbindung zu Ihrem Xiaomi Aqara Gateway her. Wenn die IP- und Mac-Adressen leer bleiben, wird die automatische Erkennung verwendet", "title": "Xiaomi Aqara Gateway" } } diff --git a/homeassistant/components/xiaomi_aqara/translations/en.json b/homeassistant/components/xiaomi_aqara/translations/en.json index e2dfdccf438..075c8d4a194 100644 --- a/homeassistant/components/xiaomi_aqara/translations/en.json +++ b/homeassistant/components/xiaomi_aqara/translations/en.json @@ -10,8 +10,7 @@ "invalid_host": "Invalid hostname or IP address, see https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "Invalid network interface", "invalid_key": "Invalid gateway key", - "invalid_mac": "Invalid Mac Address", - "not_found_error": "Zeroconf discovered Gateway could not be located to get the necessary information, try using the IP of the device running HomeAssistant as interface" + "invalid_mac": "Invalid Mac Address" }, "flow_title": "Xiaomi Aqara Gateway: {name}", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/es.json b/homeassistant/components/xiaomi_aqara/translations/es.json index 21742e1099f..1d45b456611 100644 --- a/homeassistant/components/xiaomi_aqara/translations/es.json +++ b/homeassistant/components/xiaomi_aqara/translations/es.json @@ -10,8 +10,7 @@ "invalid_host": "Direcci\u00f3n IP no v\u00e1lida", "invalid_interface": "Interfaz de red inv\u00e1lida", "invalid_key": "Clave del gateway inv\u00e1lida", - "invalid_mac": "Direcci\u00f3n Mac no v\u00e1lida", - "not_found_error": "El Gateway descubierto por Zeroconf no puede localizarse para obtener toda la informaci\u00f3n necesaria, intenta usar la IP del dispositivo que ejecuta HomeAssistant como interfaz" + "invalid_mac": "Direcci\u00f3n Mac no v\u00e1lida" }, "flow_title": "Xiaomi Aqara Gateway: {name}", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/et.json b/homeassistant/components/xiaomi_aqara/translations/et.json index 73aec8cf45a..df00de81790 100644 --- a/homeassistant/components/xiaomi_aqara/translations/et.json +++ b/homeassistant/components/xiaomi_aqara/translations/et.json @@ -2,7 +2,8 @@ "config": { "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "already_in_progress": "Seadistamine on juba k\u00e4imas" + "already_in_progress": "Seadistamine on juba k\u00e4imas", + "not_xiaomi_aqara": "See pole Xiaomi Aqara Gateway, avastatud seade ei sobinud teadaolevate l\u00fc\u00fcsidega" }, "error": { "discovery_error": "Xiaomi Aqara l\u00fc\u00fcsi avastamine nurjus, proovi kasutada HomeAssistanti IP-d liidesena", @@ -15,7 +16,7 @@ "step": { "select": { "data": { - "select_ip": "L\u00fc\u00fcsi IP" + "select_ip": "L\u00fc\u00fcsi IP aadress" }, "description": "K\u00e4ivita seadistamine uuesti kui soovid \u00fchendada t\u00e4iendavaid l\u00fc\u00fcse", "title": "Vali Xiaomi Aqara l\u00fc\u00fcs mida soovid \u00fchendada" diff --git a/homeassistant/components/xiaomi_aqara/translations/fr.json b/homeassistant/components/xiaomi_aqara/translations/fr.json index c5e03cc5c14..f4c16e045b7 100644 --- a/homeassistant/components/xiaomi_aqara/translations/fr.json +++ b/homeassistant/components/xiaomi_aqara/translations/fr.json @@ -10,8 +10,7 @@ "invalid_host": "Adresse IP non valide, voir https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "Interface r\u00e9seau non valide", "invalid_key": "Cl\u00e9 de passerelle non valide", - "invalid_mac": "Adresse MAC non valide", - "not_found_error": "La passerelle d\u00e9couverte par Zeroconf ne permet pas d'obtenir les informations n\u00e9cessaires, essayez d'utiliser l'IP du p\u00e9riph\u00e9rique ex\u00e9cutant HomeAssistant comme interface" + "invalid_mac": "Adresse MAC non valide" }, "flow_title": "Passerelle Xiaomi Aqara: {nom}", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/it.json b/homeassistant/components/xiaomi_aqara/translations/it.json index 1f00bc38d81..3299fa092f8 100644 --- a/homeassistant/components/xiaomi_aqara/translations/it.json +++ b/homeassistant/components/xiaomi_aqara/translations/it.json @@ -10,14 +10,13 @@ "invalid_host": "Nome host o indirizzo IP non valido, vedere https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "Interfaccia di rete non valida", "invalid_key": "Chiave gateway non valida", - "invalid_mac": "Indirizzo Mac non valido", - "not_found_error": "Zeroconf ha scoperto che non \u00e8 stato possibile trovare il gateway per ottenere le informazioni necessarie, provare a utilizzare l'IP del dispositivo che esegue HomeAssistant come interfaccia" + "invalid_mac": "Indirizzo Mac non valido" }, "flow_title": "Xiaomi Aqara Gateway: {name}", "step": { "select": { "data": { - "select_ip": "IP gateway" + "select_ip": "Indirizzo IP" }, "description": "Eseguire nuovamente l'installazione se si desidera connettere gateway adizionali", "title": "Selezionare il Gateway Xiaomi Aqara che si desidera collegare" diff --git a/homeassistant/components/xiaomi_aqara/translations/ko.json b/homeassistant/components/xiaomi_aqara/translations/ko.json index f222ac58bab..1b4e11c6ea3 100644 --- a/homeassistant/components/xiaomi_aqara/translations/ko.json +++ b/homeassistant/components/xiaomi_aqara/translations/ko.json @@ -8,8 +8,7 @@ "error": { "discovery_error": "Xiaomi Aqara \uac8c\uc774\ud2b8\uc6e8\uc774\ub97c \ubc1c\uacac\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. HomeAssistant \ub97c \uc778\ud130\ud398\uc774\uc2a4\ub85c \uc0ac\uc6a9\ud558\ub294 \uae30\uae30\uc758 IP \ub85c \uc2dc\ub3c4\ud574\ubcf4\uc138\uc694.", "invalid_interface": "\ub124\ud2b8\uc6cc\ud06c \uc778\ud130\ud398\uc774\uc2a4\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "invalid_key": "\uac8c\uc774\ud2b8\uc6e8\uc774 \ud0a4\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "not_found_error": "Zeroconf \uc5d0\uc11c \uac8c\uc774\ud2b8\uc6e8\uc774\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc5b4 \ud544\uc694\ud55c \uc815\ubcf4\ub97c \uc5bb\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. HomeAssistant \ub97c \uc778\ud130\ud398\uc774\uc2a4\ub85c \uc0ac\uc6a9\ud558\ub294 \uae30\uae30\uc758 IP \ub85c \uc2dc\ub3c4\ud574\ubcf4\uc138\uc694." + "invalid_key": "\uac8c\uc774\ud2b8\uc6e8\uc774 \ud0a4\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "flow_title": "Xiaomi Aqara \uac8c\uc774\ud2b8\uc6e8\uc774: {name}", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/lb.json b/homeassistant/components/xiaomi_aqara/translations/lb.json index 513c2e050bf..1d3c5f6ed76 100644 --- a/homeassistant/components/xiaomi_aqara/translations/lb.json +++ b/homeassistant/components/xiaomi_aqara/translations/lb.json @@ -10,14 +10,13 @@ "invalid_host": "Ong\u00ebltege Numm oder IP Adress, kuck https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "Ong\u00ebltege Netzwierk Interface", "invalid_key": "Ong\u00ebltegen Gateway Schl\u00ebssel", - "invalid_mac": "Ong\u00eblteg Mac Adresse", - "not_found_error": "D\u00e9i Gateway d\u00e9i duerch de Zeroconf entdeckt gouf konnt net lokalis\u00e9iert ginn, prob\u00e9ier d'IP vum Apparat op deem Home Assistant leeft als Interface ze benotzen" + "invalid_mac": "Ong\u00eblteg Mac Adresse" }, "flow_title": "Xiaomi Aqara Gateway: {name}", "step": { "select": { "data": { - "select_ip": "IP vun der Gateway" + "select_ip": "IP Adresse" }, "description": "Setup nach emol ausf\u00e9ieren fir eng zous\u00e4tzlech Gateway dob\u00e4i ze setzen", "title": "Xiaomi Aqara Gateway auswielen mat der sech soll verbonne ginn" diff --git a/homeassistant/components/xiaomi_aqara/translations/nl.json b/homeassistant/components/xiaomi_aqara/translations/nl.json index a2f3f58abda..e17b3b572d1 100644 --- a/homeassistant/components/xiaomi_aqara/translations/nl.json +++ b/homeassistant/components/xiaomi_aqara/translations/nl.json @@ -5,11 +5,19 @@ }, "flow_title": "Xiaomi Aqara Gateway: {name}", "step": { + "select": { + "description": "Voer de installatie opnieuw uit als u extra gateways wilt aansluiten", + "title": "Selecteer de Xiaomi Aqara Gateway waarmee u verbinding wilt maken" + }, + "settings": { + "description": "De sleutel (wachtwoord) kan worden opgehaald met behulp van deze tutorial: https://www.domoticz.com/wiki/Xiaomi_Gateway_(Aqara)#Adding_the_Xiaomi_Gateway_to_Domoticz. Als de sleutel niet wordt meegeleverd, zijn alleen sensoren toegankelijk" + }, "user": { "data": { "host": "IP-adres (optioneel)", "mac": "MAC-adres (optioneel)" }, + "description": "Maak verbinding met uw Xiaomi Aqara Gateway, als de IP- en mac-adressen leeg worden gelaten, wordt automatische detectie gebruikt", "title": "Xiaomi Aqara Gateway" } } diff --git a/homeassistant/components/xiaomi_aqara/translations/no.json b/homeassistant/components/xiaomi_aqara/translations/no.json index c42958275b3..523e2da898c 100644 --- a/homeassistant/components/xiaomi_aqara/translations/no.json +++ b/homeassistant/components/xiaomi_aqara/translations/no.json @@ -10,8 +10,7 @@ "invalid_host": "Ugyldig vertsnavn eller IP-adresse , se https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "Ugyldig nettverksgrensesnitt", "invalid_key": "Ugyldig gateway-n\u00f8kkel", - "invalid_mac": "Ugyldig MAC-adresse", - "not_found_error": "Zeroconf oppdaget Gateway kunne ikke v\u00e6re plassert for \u00e5 f\u00e5 den n\u00f8dvendige informasjonen, kan du pr\u00f8ve \u00e5 bruke IP-adressen til enheten som kj\u00f8rer HomeAssistant som grensesnitt" + "invalid_mac": "Ugyldig MAC-adresse" }, "flow_title": "", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/pl.json b/homeassistant/components/xiaomi_aqara/translations/pl.json index 8c4e44de762..28df744d8e7 100644 --- a/homeassistant/components/xiaomi_aqara/translations/pl.json +++ b/homeassistant/components/xiaomi_aqara/translations/pl.json @@ -10,8 +10,7 @@ "invalid_host": "Nieprawid\u0142owa nazwa hosta lub adres IP, po pomoc w rozwi\u0105zaniu problemu kliknij [tutaj]({https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem)}", "invalid_interface": "Nieprawid\u0142owy interfejs sieciowy", "invalid_key": "Nieprawid\u0142owy klucz bramki", - "invalid_mac": "Nieprawid\u0142owy adres MAC", - "not_found_error": "Nie mo\u017cna odnale\u017a\u0107 wykrytej bramki, aby uzyska\u0107 niezb\u0119dne informacje, spr\u00f3buj u\u017cy\u0107 adresu IP urz\u0105dzenia, na kt\u00f3rym pracuje Home Assistant jako interfejsu." + "invalid_mac": "Nieprawid\u0142owy adres MAC" }, "flow_title": "Bramka Xiaomi Aqara: {name}", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/ru.json b/homeassistant/components/xiaomi_aqara/translations/ru.json index 751da25d26d..96da0a24074 100644 --- a/homeassistant/components/xiaomi_aqara/translations/ru.json +++ b/homeassistant/components/xiaomi_aqara/translations/ru.json @@ -10,8 +10,7 @@ "invalid_host": "\u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u0438\u043b\u0438 IP-\u0430\u0434\u0440\u0435\u0441.. \u0421\u043f\u043e\u0441\u043e\u0431\u044b \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0437\u0434\u0435\u0441\u044c: https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem.", "invalid_interface": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441.", "invalid_key": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0448\u043b\u044e\u0437\u0430.", - "invalid_mac": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 MAC-\u0430\u0434\u0440\u0435\u0441.", - "not_found_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0442 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u0448\u043b\u044e\u0437\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c IP-\u0430\u0434\u0440\u0435\u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441 HomeAssistant \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430." + "invalid_mac": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 MAC-\u0430\u0434\u0440\u0435\u0441." }, "flow_title": "\u0428\u043b\u044e\u0437 Xiaomi Aqara: {name}", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/zh-Hans.json b/homeassistant/components/xiaomi_aqara/translations/zh-Hans.json index 02e2a01961b..a0d0159e71c 100644 --- a/homeassistant/components/xiaomi_aqara/translations/zh-Hans.json +++ b/homeassistant/components/xiaomi_aqara/translations/zh-Hans.json @@ -10,8 +10,7 @@ "invalid_host": "IP \u5730\u5740\u65e0\u6548\u3002\u8bf7\u53c2\u9605 https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "\u7f51\u7edc\u63a5\u53e3\u65e0\u6548", "invalid_key": "\u7f51\u5173 key \u65e0\u6548", - "invalid_mac": "MAC \u5730\u5740\u65e0\u6548", - "not_found_error": "Zeroconf \u53d1\u73b0\u7684\u7f51\u5173\u65e0\u6cd5\u5b9a\u4f4d\uff0c\u56e0\u6b64\u65e0\u6cd5\u83b7\u5f97\u5fc5\u8981\u4fe1\u606f\u3002\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u8fd0\u884c HomeAssistant \u7684\u8bbe\u5907 IP \u4f5c\u4e3a\u63a5\u53e3" + "invalid_mac": "MAC \u5730\u5740\u65e0\u6548" }, "flow_title": "\u5c0f\u7c73 Aqara \u7f51\u5173\uff1a{name}", "step": { diff --git a/homeassistant/components/xiaomi_aqara/translations/zh-Hant.json b/homeassistant/components/xiaomi_aqara/translations/zh-Hant.json index c71d5e1a89b..cd1059436d1 100644 --- a/homeassistant/components/xiaomi_aqara/translations/zh-Hant.json +++ b/homeassistant/components/xiaomi_aqara/translations/zh-Hant.json @@ -10,8 +10,7 @@ "invalid_host": "\u7121\u6548\u4e3b\u6a5f\u540d\u7a31\u6216 IP \u4f4d\u5740\uff0c\u8acb\u53c3\u95b1 https://www.home-assistant.io/integrations/xiaomi_aqara/#connection-problem", "invalid_interface": "\u7db2\u8def\u4ecb\u9762\u7121\u6548", "invalid_key": "\u7db2\u95dc\u5bc6\u9470\u7121\u6548", - "invalid_mac": "\u7121\u6548\u7684 Mac \u4f4d\u5740", - "not_found_error": "Zeroconf \u6240\u63a2\u7d22\u7684\u7db2\u95dc\u7121\u6cd5\u53d6\u5f97\u5fc5\u8981\u7684\u8cc7\u8a0a\uff0c\u8acb\u5617\u8a66\u4f7f\u7528\u57f7\u884c Home Assistant \u7684\u8a2d\u5099 IP \u4f5c\u70ba\u4ecb\u9762" + "invalid_mac": "\u7121\u6548\u7684 Mac \u4f4d\u5740" }, "flow_title": "\u5c0f\u7c73 Aqara \u7db2\u95dc\uff1a{name}", "step": { diff --git a/homeassistant/components/xiaomi_miio/translations/ca.json b/homeassistant/components/xiaomi_miio/translations/ca.json index 93e0a4859b6..5183157371b 100644 --- a/homeassistant/components/xiaomi_miio/translations/ca.json +++ b/homeassistant/components/xiaomi_miio/translations/ca.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Ha fallat la connexi\u00f3", - "connect_error": "[%key::common::config_flow::error::cannot_connect%]", "no_device_selected": "No hi ha cap dispositiu seleccionat, selecciona'n un." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/cs.json b/homeassistant/components/xiaomi_miio/translations/cs.json index 65e64e4b168..91c30a69e54 100644 --- a/homeassistant/components/xiaomi_miio/translations/cs.json +++ b/homeassistant/components/xiaomi_miio/translations/cs.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit", - "connect_error": "Nepoda\u0159ilo se p\u0159ipojit", "no_device_selected": "Nebylo vybr\u00e1no \u017e\u00e1dn\u00e9 za\u0159\u00edzen\u00ed, vyberte jedno za\u0159\u00edzen\u00ed." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/de.json b/homeassistant/components/xiaomi_miio/translations/de.json index d52715249b9..0b5f593ffcd 100644 --- a/homeassistant/components/xiaomi_miio/translations/de.json +++ b/homeassistant/components/xiaomi_miio/translations/de.json @@ -5,7 +5,6 @@ "already_in_progress": "Der Konfigurationsablauf f\u00fcr dieses Xiaomi Miio-Ger\u00e4t wird bereits ausgef\u00fchrt." }, "error": { - "connect_error": "Verbindung fehlgeschlagen", "no_device_selected": "Kein Ger\u00e4t ausgew\u00e4hlt, bitte w\u00e4hlen Sie ein Ger\u00e4t aus." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/en.json b/homeassistant/components/xiaomi_miio/translations/en.json index 661125b4586..4d39a6d1137 100644 --- a/homeassistant/components/xiaomi_miio/translations/en.json +++ b/homeassistant/components/xiaomi_miio/translations/en.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Failed to connect", - "connect_error": "Failed to connect", "no_device_selected": "No device selected, please select one device." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/es-419.json b/homeassistant/components/xiaomi_miio/translations/es-419.json index ac9e6077ce5..b3bbc25ebba 100644 --- a/homeassistant/components/xiaomi_miio/translations/es-419.json +++ b/homeassistant/components/xiaomi_miio/translations/es-419.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connect_error": "No se pudo conectar, intente nuevamente", "no_device_selected": "Ning\u00fan dispositivo seleccionado, seleccione un dispositivo." }, "step": { diff --git a/homeassistant/components/xiaomi_miio/translations/es.json b/homeassistant/components/xiaomi_miio/translations/es.json index cd529a8ff77..46fb93012ad 100644 --- a/homeassistant/components/xiaomi_miio/translations/es.json +++ b/homeassistant/components/xiaomi_miio/translations/es.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "No se pudo conectar", - "connect_error": "No se ha podido conectar", "no_device_selected": "No se ha seleccionado ning\u00fan dispositivo, por favor, seleccione un dispositivo." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/et.json b/homeassistant/components/xiaomi_miio/translations/et.json index 57451eb7244..f6bd3218e14 100644 --- a/homeassistant/components/xiaomi_miio/translations/et.json +++ b/homeassistant/components/xiaomi_miio/translations/et.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "\u00dchendus nurjus", - "connect_error": "\u00dchendamine nurjus", "no_device_selected": "Seadmeid pole valitud, vali \u00fcks seade." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/fi.json b/homeassistant/components/xiaomi_miio/translations/fi.json index 669f5a34fb9..ab360a82a8f 100644 --- a/homeassistant/components/xiaomi_miio/translations/fi.json +++ b/homeassistant/components/xiaomi_miio/translations/fi.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connect_error": "Yhteyden muodostaminen ep\u00e4onnistui. Yrit\u00e4 uudelleen", "no_device_selected": "Ei valittuja laitteita. Ole hyv\u00e4 ja valitse yksi." }, "step": { diff --git a/homeassistant/components/xiaomi_miio/translations/fr.json b/homeassistant/components/xiaomi_miio/translations/fr.json index e76e5a1ef69..84849041c8c 100644 --- a/homeassistant/components/xiaomi_miio/translations/fr.json +++ b/homeassistant/components/xiaomi_miio/translations/fr.json @@ -5,7 +5,7 @@ "already_in_progress": "Le flux de configuration pour cet appareil Xiaomi Miio est d\u00e9j\u00e0 en cours." }, "error": { - "connect_error": "\u00c9chec de connexion", + "cannot_connect": "\u00c9chec de connexion", "no_device_selected": "Aucun appareil s\u00e9lectionn\u00e9, veuillez s\u00e9lectionner un appareil." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/hu.json b/homeassistant/components/xiaomi_miio/translations/hu.json index 1cb7833427e..ef5ef6c0748 100644 --- a/homeassistant/components/xiaomi_miio/translations/hu.json +++ b/homeassistant/components/xiaomi_miio/translations/hu.json @@ -4,7 +4,6 @@ "already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van" }, "error": { - "connect_error": "Sikertelen csatlakoz\u00e1s", "no_device_selected": "Nincs kiv\u00e1lasztva eszk\u00f6z, k\u00e9rj\u00fck, v\u00e1lasszon egyet." }, "step": { diff --git a/homeassistant/components/xiaomi_miio/translations/it.json b/homeassistant/components/xiaomi_miio/translations/it.json index fc2105fdc50..cbfc2d60621 100644 --- a/homeassistant/components/xiaomi_miio/translations/it.json +++ b/homeassistant/components/xiaomi_miio/translations/it.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Impossibile connettersi", - "connect_error": "Impossibile connettersi", "no_device_selected": "Nessun dispositivo selezionato, selezionare un dispositivo." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/ko.json b/homeassistant/components/xiaomi_miio/translations/ko.json index 3357e5d91d3..52f1ed960d2 100644 --- a/homeassistant/components/xiaomi_miio/translations/ko.json +++ b/homeassistant/components/xiaomi_miio/translations/ko.json @@ -5,7 +5,6 @@ "already_in_progress": "Xiaomi Miio \uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4." }, "error": { - "connect_error": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4", "no_device_selected": "\uc120\ud0dd\ub41c \uae30\uae30\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. \uae30\uae30\ub97c \uc120\ud0dd\ud574\uc8fc\uc138\uc694." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/lb.json b/homeassistant/components/xiaomi_miio/translations/lb.json index 151e70ea914..67e286d4fa1 100644 --- a/homeassistant/components/xiaomi_miio/translations/lb.json +++ b/homeassistant/components/xiaomi_miio/translations/lb.json @@ -5,7 +5,7 @@ "already_in_progress": "Konfiguratioun's Oflaf ass schonn am gaangen." }, "error": { - "connect_error": "Feeler beim verbannen", + "cannot_connect": "Feeler beim verbannen", "no_device_selected": "Keen Apparat ausgewielt, wiel een Apparat aus w.e.g." }, "flow_title": "Xiaomi Miio: {name}", @@ -16,7 +16,7 @@ "name": "Numm vum Gateway", "token": "API Jeton" }, - "description": "Du brauchs den 32 stellegen API Jeton, kuck https://www.home-assistant.io/integrations/vacuum.xiaomi_miio/#retrieving-the-access-token fir Instruktiounen. Remarque, d\u00ebst ass een aaneren jeton w\u00e9i en vun der Xiaomi Aqara Integratioun benotzt g\u00ebtt.", + "description": "Du brauchs den 32 stellegen API Jeton, kuck https://www.home-assistant.io/integrations/vacuum.xiaomi_miio/#retrieving-the-access-token fir Instruktiounen. Remarque, d\u00ebst ass een aaneren API Jeton w\u00e9i en vun der Xiaomi Aqara Integratioun benotzt g\u00ebtt.", "title": "Mat enger Xiaomi Gateway verbannen" }, "user": { diff --git a/homeassistant/components/xiaomi_miio/translations/nl.json b/homeassistant/components/xiaomi_miio/translations/nl.json index 5daf94a5e0d..eea72c1c4c0 100644 --- a/homeassistant/components/xiaomi_miio/translations/nl.json +++ b/homeassistant/components/xiaomi_miio/translations/nl.json @@ -1,10 +1,10 @@ { "config": { "abort": { + "already_configured": "Apparaat is al geconfigureerd", "already_in_progress": "De configuratiestroom voor dit Xiaomi Miio-apparaat is al bezig." }, "error": { - "connect_error": "Verbinding mislukt, probeer het opnieuw", "no_device_selected": "Geen apparaat geselecteerd, selecteer 1 apparaat alstublieft" }, "step": { diff --git a/homeassistant/components/xiaomi_miio/translations/no.json b/homeassistant/components/xiaomi_miio/translations/no.json index 725b9742851..c7128900fc7 100644 --- a/homeassistant/components/xiaomi_miio/translations/no.json +++ b/homeassistant/components/xiaomi_miio/translations/no.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Tilkobling mislyktes", - "connect_error": "Tilkobling mislyktes", "no_device_selected": "Ingen enhet valgt, vennligst velg en enhet." }, "flow_title": "", diff --git a/homeassistant/components/xiaomi_miio/translations/pl.json b/homeassistant/components/xiaomi_miio/translations/pl.json index ba26dc62bdd..82f7f958905 100644 --- a/homeassistant/components/xiaomi_miio/translations/pl.json +++ b/homeassistant/components/xiaomi_miio/translations/pl.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connect_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", "no_device_selected": "Nie wybrano \u017cadnego urz\u0105dzenia, wybierz jedno urz\u0105dzenie" }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/pt-BR.json b/homeassistant/components/xiaomi_miio/translations/pt-BR.json index 4c5e0bf1ccb..beeb45b9880 100644 --- a/homeassistant/components/xiaomi_miio/translations/pt-BR.json +++ b/homeassistant/components/xiaomi_miio/translations/pt-BR.json @@ -3,9 +3,6 @@ "abort": { "already_in_progress": "O fluxo de configura\u00e7\u00e3o para este dispositivo Xiaomi Miio j\u00e1 est\u00e1 em andamento." }, - "error": { - "connect_error": "Falha na conex\u00e3o" - }, "step": { "gateway": { "data": { diff --git a/homeassistant/components/xiaomi_miio/translations/ru.json b/homeassistant/components/xiaomi_miio/translations/ru.json index 598c5a585aa..be02fd14f3e 100644 --- a/homeassistant/components/xiaomi_miio/translations/ru.json +++ b/homeassistant/components/xiaomi_miio/translations/ru.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", - "connect_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.", "no_device_selected": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u0434\u043d\u043e \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432." }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/sl.json b/homeassistant/components/xiaomi_miio/translations/sl.json index d8fc0bf28f7..45aad4ab691 100644 --- a/homeassistant/components/xiaomi_miio/translations/sl.json +++ b/homeassistant/components/xiaomi_miio/translations/sl.json @@ -4,7 +4,6 @@ "already_configured": "Naprava je \u017ee konfigurirana" }, "error": { - "connect_error": "Povezava ni uspela", "no_device_selected": "Izbrana ni nobena naprava, izberite eno napravo." }, "step": { diff --git a/homeassistant/components/xiaomi_miio/translations/sv.json b/homeassistant/components/xiaomi_miio/translations/sv.json index aee988f0a04..fcd6e641091 100644 --- a/homeassistant/components/xiaomi_miio/translations/sv.json +++ b/homeassistant/components/xiaomi_miio/translations/sv.json @@ -1,7 +1,6 @@ { "config": { "error": { - "connect_error": "Det gick inte att ansluta, f\u00f6rs\u00f6k igen", "no_device_selected": "Ingen enhet har valts, v\u00e4lj en enhet." }, "step": { diff --git a/homeassistant/components/xiaomi_miio/translations/zh-Hans.json b/homeassistant/components/xiaomi_miio/translations/zh-Hans.json index 9a54104116a..1f84cd3de5a 100644 --- a/homeassistant/components/xiaomi_miio/translations/zh-Hans.json +++ b/homeassistant/components/xiaomi_miio/translations/zh-Hans.json @@ -5,7 +5,7 @@ "already_in_progress": "\u6b64\u5c0f\u7c73\u8bbe\u5907\u7684\u914d\u7f6e\u6d41\u7a0b\u5df2\u5728\u8fdb\u884c\u4e2d\u3002" }, "error": { - "connect_error": "\u8fde\u63a5\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5", + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", "no_device_selected": "\u672a\u9009\u62e9\u8bbe\u5907\uff0c\u8bf7\u9009\u62e9\u4e00\u4e2a\u8bbe\u5907\u3002" }, "flow_title": "Xiaomi Miio: {name}", diff --git a/homeassistant/components/xiaomi_miio/translations/zh-Hant.json b/homeassistant/components/xiaomi_miio/translations/zh-Hant.json index f622d1184f1..fd77eb4df82 100644 --- a/homeassistant/components/xiaomi_miio/translations/zh-Hant.json +++ b/homeassistant/components/xiaomi_miio/translations/zh-Hant.json @@ -6,7 +6,6 @@ }, "error": { "cannot_connect": "\u9023\u7dda\u5931\u6557", - "connect_error": "\u9023\u7dda\u5931\u6557", "no_device_selected": "\u672a\u9078\u64c7\u8a2d\u5099\uff0c\u8acb\u9078\u64c7\u4e00\u9805\u8a2d\u5099\u3002" }, "flow_title": "Xiaomi Miio\uff1a{name}", diff --git a/homeassistant/components/yeelight/__init__.py b/homeassistant/components/yeelight/__init__.py index f5403062faa..ae9d75de54f 100644 --- a/homeassistant/components/yeelight/__init__.py +++ b/homeassistant/components/yeelight/__init__.py @@ -7,7 +7,7 @@ from typing import Optional import voluptuous as vol from yeelight import Bulb, BulbException, discover_bulbs -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigEntryNotReady +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import ( CONF_DEVICES, CONF_HOST, @@ -180,8 +180,8 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Yeelight from a config entry.""" - async def _initialize(host: str) -> None: - device = await _async_setup_device(hass, host, entry.options) + async def _initialize(host: str, capabilities: Optional[dict] = None) -> None: + device = await _async_setup_device(hass, host, entry, capabilities) hass.data[DOMAIN][DATA_CONFIG_ENTRIES][entry.entry_id][DATA_DEVICE] = device for component in PLATFORMS: hass.async_create_task( @@ -252,20 +252,33 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): async def _async_setup_device( hass: HomeAssistant, host: str, - config: dict, + entry: ConfigEntry, + capabilities: Optional[dict], ) -> None: + # Get model from config and capabilities + model = entry.options.get(CONF_MODEL) + if not model and capabilities is not None: + model = capabilities.get("model") + # Set up device - bulb = Bulb(host, model=config.get(CONF_MODEL) or None) - capabilities = await hass.async_add_executor_job(bulb.get_capabilities) - if capabilities is None: # timeout - _LOGGER.error("Failed to get capabilities from %s", host) - raise ConfigEntryNotReady - device = YeelightDevice(hass, host, config, bulb) + bulb = Bulb(host, model=model or None) + if capabilities is None: + capabilities = await hass.async_add_executor_job(bulb.get_capabilities) + + device = YeelightDevice(hass, host, entry.options, bulb, capabilities) await hass.async_add_executor_job(device.update) await device.async_setup() return device +@callback +def _async_unique_name(capabilities: dict) -> str: + """Generate name from capabilities.""" + model = capabilities["model"] + unique_id = capabilities["id"] + return f"yeelight_{model}_{unique_id}" + + async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry): """Handle options update.""" await hass.config_entries.async_reload(entry.entry_id) @@ -332,7 +345,7 @@ class YeelightScanner: """Register callback function.""" host = self._seen.get(unique_id) if host is not None: - self._hass.async_add_job(callback_func(host)) + self._hass.async_create_task(callback_func(host)) else: self._callbacks[unique_id] = callback_func if len(self._callbacks) == 1: @@ -351,18 +364,25 @@ class YeelightScanner: class YeelightDevice: """Represents single Yeelight device.""" - def __init__(self, hass, host, config, bulb): + def __init__(self, hass, host, config, bulb, capabilities): """Initialize device.""" self._hass = hass self._config = config self._host = host - unique_id = bulb.capabilities.get("id") - self._name = config.get(CONF_NAME) or f"yeelight_{bulb.model}_{unique_id}" self._bulb_device = bulb + self._capabilities = capabilities or {} self._device_type = None self._available = False self._remove_time_tracker = None + self._name = host # Default name is host + if capabilities: + # Generate name from model and id when capabilities is available + self._name = _async_unique_name(capabilities) + if config.get(CONF_NAME): + # Override default name when name is set in config + self._name = config[CONF_NAME] + @property def bulb(self): """Return bulb device.""" @@ -396,7 +416,7 @@ class YeelightDevice: @property def fw_version(self): """Return the firmware version.""" - return self._bulb_device.capabilities.get("fw_ver") + return self._capabilities.get("fw_ver") @property def is_nightlight_supported(self) -> bool: @@ -449,11 +469,6 @@ class YeelightDevice: return self._device_type - @property - def unique_id(self) -> Optional[str]: - """Return a unique ID.""" - return self.bulb.capabilities.get("id") - def turn_on(self, duration=DEFAULT_TRANSITION, light_type=None, power_mode=None): """Turn on device.""" try: @@ -532,15 +547,24 @@ class YeelightDevice: class YeelightEntity(Entity): """Represents single Yeelight entity.""" - def __init__(self, device: YeelightDevice): + def __init__(self, device: YeelightDevice, entry: ConfigEntry): """Initialize the entity.""" self._device = device + self._unique_id = entry.entry_id + if entry.unique_id is not None: + # Use entry unique id (device id) whenever possible + self._unique_id = entry.unique_id + + @property + def unique_id(self) -> str: + """Return the unique ID.""" + return self._unique_id @property def device_info(self) -> dict: """Return the device info.""" return { - "identifiers": {(DOMAIN, self._device.unique_id)}, + "identifiers": {(DOMAIN, self._unique_id)}, "name": self._device.name, "manufacturer": "Yeelight", "model": self._device.model, diff --git a/homeassistant/components/yeelight/binary_sensor.py b/homeassistant/components/yeelight/binary_sensor.py index 6d9de45c837..4fe3709cdd2 100644 --- a/homeassistant/components/yeelight/binary_sensor.py +++ b/homeassistant/components/yeelight/binary_sensor.py @@ -1,6 +1,5 @@ """Sensor platform support for yeelight.""" import logging -from typing import Optional from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.config_entries import ConfigEntry @@ -19,7 +18,7 @@ async def async_setup_entry( device = hass.data[DOMAIN][DATA_CONFIG_ENTRIES][config_entry.entry_id][DATA_DEVICE] if device.is_nightlight_supported: _LOGGER.debug("Adding nightlight mode sensor for %s", device.name) - async_add_entities([YeelightNightlightModeSensor(device)]) + async_add_entities([YeelightNightlightModeSensor(device, config_entry)]) class YeelightNightlightModeSensor(YeelightEntity, BinarySensorEntity): @@ -36,14 +35,9 @@ class YeelightNightlightModeSensor(YeelightEntity, BinarySensorEntity): ) @property - def unique_id(self) -> Optional[str]: + def unique_id(self) -> str: """Return a unique ID.""" - unique = self._device.unique_id - - if unique: - return unique + "-nightlight_sensor" - - return None + return f"{self._unique_id}-nightlight_sensor" @property def name(self): diff --git a/homeassistant/components/yeelight/config_flow.py b/homeassistant/components/yeelight/config_flow.py index 84f1bbdd975..52f27932403 100644 --- a/homeassistant/components/yeelight/config_flow.py +++ b/homeassistant/components/yeelight/config_flow.py @@ -18,6 +18,7 @@ from . import ( CONF_SAVE_ON_CHANGE, CONF_TRANSITION, NIGHTLIGHT_SWITCH_TYPE_LIGHT, + _async_unique_name, ) from . import DOMAIN # pylint:disable=unused-import @@ -38,7 +39,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): def __init__(self): """Initialize the config flow.""" - self._capabilities = None self._discovered_devices = {} async def async_step_user(self, user_input=None): @@ -49,7 +49,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): try: await self._async_try_connect(user_input[CONF_HOST]) return self.async_create_entry( - title=self._async_default_name(), + title=user_input[CONF_HOST], data=user_input, ) except CannotConnect: @@ -59,9 +59,12 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): else: return await self.async_step_pick_device() + user_input = user_input or {} return self.async_show_form( step_id="user", - data_schema=vol.Schema({vol.Optional(CONF_HOST): str}), + data_schema=vol.Schema( + {vol.Optional(CONF_HOST, default=user_input.get(CONF_HOST, "")): str} + ), errors=errors, ) @@ -69,9 +72,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle the step to pick discovered device.""" if user_input is not None: unique_id = user_input[CONF_DEVICE] - self._capabilities = self._discovered_devices[unique_id] + capabilities = self._discovered_devices[unique_id] + await self.async_set_unique_id(unique_id) + self._abort_if_unique_id_configured() return self.async_create_entry( - title=self._async_default_name(), + title=_async_unique_name(capabilities), data={CONF_ID: unique_id}, ) @@ -122,25 +127,32 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): async def _async_try_connect(self, host): """Set up with options.""" + for entry in self._async_current_entries(): + if entry.data.get(CONF_HOST) == host: + raise AlreadyConfigured + bulb = yeelight.Bulb(host) try: capabilities = await self.hass.async_add_executor_job(bulb.get_capabilities) if capabilities is None: # timeout - _LOGGER.error("Failed to get capabilities from %s: timeout", host) - raise CannotConnect + _LOGGER.debug("Failed to get capabilities from %s: timeout", host) + else: + _LOGGER.debug("Get capabilities: %s", capabilities) + await self.async_set_unique_id(capabilities["id"]) + self._abort_if_unique_id_configured() + return except OSError as err: - _LOGGER.error("Failed to get capabilities from %s: %s", host, err) - raise CannotConnect from err - _LOGGER.debug("Get capabilities: %s", capabilities) - self._capabilities = capabilities - await self.async_set_unique_id(capabilities["id"]) - self._abort_if_unique_id_configured() + _LOGGER.debug("Failed to get capabilities from %s: %s", host, err) + # Ignore the error since get_capabilities uses UDP discovery packet + # which does not work in all network environments - @callback - def _async_default_name(self): - model = self._capabilities["model"] - unique_id = self._capabilities["id"] - return f"yeelight_{model}_{unique_id}" + # Fallback to get properties + try: + await self.hass.async_add_executor_job(bulb.get_properties) + except yeelight.BulbException as err: + _LOGGER.error("Failed to get properties from %s: %s", host, err) + raise CannotConnect from err + _LOGGER.debug("Get properties: %s", bulb.last_properties) class OptionsFlowHandler(config_entries.OptionsFlow): @@ -153,11 +165,8 @@ class OptionsFlowHandler(config_entries.OptionsFlow): async def async_step_init(self, user_input=None): """Handle the initial step.""" if user_input is not None: - # keep the name from imported entries - options = { - CONF_NAME: self._config_entry.options.get(CONF_NAME), - **user_input, - } + options = {**self._config_entry.options} + options.update(user_input) return self.async_create_entry(title="", data=options) options = self._config_entry.options diff --git a/homeassistant/components/yeelight/light.py b/homeassistant/components/yeelight/light.py index 93dbc5bcb07..90704a6edfb 100644 --- a/homeassistant/components/yeelight/light.py +++ b/homeassistant/components/yeelight/light.py @@ -1,7 +1,6 @@ """Light platform support for yeelight.""" from functools import partial import logging -from typing import Optional import voluptuous as vol import yeelight @@ -241,7 +240,7 @@ async def async_setup_entry( device_type = device.type def _lights_setup_helper(klass): - lights.append(klass(device, custom_effects=custom_effects)) + lights.append(klass(device, config_entry, custom_effects=custom_effects)) if device_type == BulbType.White: _lights_setup_helper(YeelightGenericLight) @@ -382,9 +381,9 @@ def _async_setup_services(hass: HomeAssistant): class YeelightGenericLight(YeelightEntity, LightEntity): """Representation of a Yeelight generic light.""" - def __init__(self, device, custom_effects=None): + def __init__(self, device, entry, custom_effects=None): """Initialize the Yeelight light.""" - super().__init__(device) + super().__init__(device, entry) self.config = device.config @@ -418,12 +417,6 @@ class YeelightGenericLight(YeelightEntity, LightEntity): ) ) - @property - def unique_id(self) -> Optional[str]: - """Return a unique ID.""" - - return self.device.unique_id - @property def supported_features(self) -> int: """Flag supported features.""" @@ -478,7 +471,7 @@ class YeelightGenericLight(YeelightEntity, LightEntity): @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): @@ -852,14 +845,10 @@ class YeelightNightLightMode(YeelightGenericLight): """Representation of a Yeelight when in nightlight mode.""" @property - def unique_id(self) -> Optional[str]: + def unique_id(self) -> str: """Return a unique ID.""" unique = super().unique_id - - if unique: - return unique + "-nightlight" - - return None + return f"{unique}-nightlight" @property def name(self) -> str: @@ -945,12 +934,10 @@ class YeelightAmbientLight(YeelightColorLightWithoutNightlightSwitch): self._light_type = LightType.Ambient @property - def unique_id(self) -> Optional[str]: + def unique_id(self) -> str: """Return a unique ID.""" unique = super().unique_id - - if unique: - return unique + "-ambilight" + return f"{unique}-ambilight" @property def name(self) -> str: diff --git a/homeassistant/components/yeelight/strings.json b/homeassistant/components/yeelight/strings.json index 7fd3062ef87..52a684bc26f 100644 --- a/homeassistant/components/yeelight/strings.json +++ b/homeassistant/components/yeelight/strings.json @@ -1,5 +1,4 @@ { - "title": "Yeelight", "config": { "step": { "user": { @@ -36,4 +35,4 @@ } } } -} \ No newline at end of file +} diff --git a/homeassistant/components/yeelight/translations/ca.json b/homeassistant/components/yeelight/translations/ca.json index 28c2e796d3c..77fe2b49c71 100644 --- a/homeassistant/components/yeelight/translations/ca.json +++ b/homeassistant/components/yeelight/translations/ca.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "Amfitri\u00f3", - "ip_address": "Adre\u00e7a IP" + "host": "Amfitri\u00f3" }, "description": "Si deixes l'amfitri\u00f3 buit, s'utilitzar\u00e0 el descobriment per cercar dispositius." } @@ -35,6 +34,5 @@ "description": "Si deixes el model buit, es detectar\u00e0 autom\u00e0ticament." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/cs.json b/homeassistant/components/yeelight/translations/cs.json index b1eb849f582..4ede7753310 100644 --- a/homeassistant/components/yeelight/translations/cs.json +++ b/homeassistant/components/yeelight/translations/cs.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "Hostitel", - "ip_address": "IP adresa" + "host": "Hostitel" }, "description": "Pokud z\u016fstane hostitel pr\u00e1zdn\u00fd, k vyhled\u00e1n\u00ed za\u0159\u00edzen\u00ed se pou\u017eije zji\u0161\u0165ov\u00e1n\u00ed." } @@ -29,9 +28,9 @@ "model": "Model (voliteln\u00fd)", "save_on_change": "Ulo\u017eit stav p\u0159i zm\u011bn\u011b", "transition": "\u010cas p\u0159echodu (v ms)" - } + }, + "description": "Pokud ponech\u00e1te model pr\u00e1zdn\u00fd, bude automaticky rozpozn\u00e1n." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/de.json b/homeassistant/components/yeelight/translations/de.json index b282a4d8b84..90c154f882b 100644 --- a/homeassistant/components/yeelight/translations/de.json +++ b/homeassistant/components/yeelight/translations/de.json @@ -8,8 +8,7 @@ }, "user": { "data": { - "host": "Host", - "ip_address": "IP-Addresse" + "host": "Host" } } } @@ -24,6 +23,5 @@ } } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/el.json b/homeassistant/components/yeelight/translations/el.json index 6495e7a489f..611f84a2ba4 100644 --- a/homeassistant/components/yeelight/translations/el.json +++ b/homeassistant/components/yeelight/translations/el.json @@ -10,9 +10,6 @@ } }, "user": { - "data": { - "ip_address": "\u0394\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 IP" - }, "description": "\u0395\u03ac\u03bd \u03b1\u03c6\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf\u03bd \u03ba\u03b5\u03bd\u03c4\u03c1\u03b9\u03ba\u03cc \u03c5\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03c4\u03ae \u03ba\u03b5\u03bd\u03cc, \u03bf \u03b5\u03bd\u03c4\u03bf\u03c0\u03b9\u03c3\u03bc\u03cc\u03c2 \u03b8\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03b5\u03af \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03b5\u03cd\u03c1\u03b5\u03c3\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ce\u03bd." } } @@ -30,6 +27,5 @@ "description": "\u0395\u03ac\u03bd \u03b1\u03c6\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03bc\u03bf\u03bd\u03c4\u03ad\u03bb\u03bf \u03ba\u03b5\u03bd\u03cc, \u03b8\u03b1 \u03b5\u03bd\u03c4\u03bf\u03c0\u03b9\u03c3\u03c4\u03b5\u03af \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/en.json b/homeassistant/components/yeelight/translations/en.json index abb51f13667..218f82f86b7 100644 --- a/homeassistant/components/yeelight/translations/en.json +++ b/homeassistant/components/yeelight/translations/en.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "Host", - "ip_address": "IP Address" + "host": "Host" }, "description": "If you leave the host empty, discovery will be used to find devices." } @@ -35,6 +34,5 @@ "description": "If you leave model empty, it will be automatically detected." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/es.json b/homeassistant/components/yeelight/translations/es.json index fdfbdfc5634..d633a885fda 100644 --- a/homeassistant/components/yeelight/translations/es.json +++ b/homeassistant/components/yeelight/translations/es.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "Host", - "ip_address": "Direcci\u00f3n IP" + "host": "Host" }, "description": "Si dejas la direcci\u00f3n IP vac\u00eda, se usar\u00e1 descubrimiento para encontrar dispositivos." } @@ -35,6 +34,5 @@ "description": "Si dejas el modelo vac\u00edo, se detectar\u00e1 autom\u00e1ticamente." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/et.json b/homeassistant/components/yeelight/translations/et.json index 97ff2d793d4..55cdf2e0b28 100644 --- a/homeassistant/components/yeelight/translations/et.json +++ b/homeassistant/components/yeelight/translations/et.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "", - "ip_address": "IP aadress" + "host": "" }, "description": "Kui j\u00e4tad hosti t\u00fchjaks kasutatakse seadmete leidmiseks avastamist." } @@ -35,6 +34,5 @@ "description": "Kui j\u00e4tad mudeli m\u00e4\u00e4ramata tuvastatakse see automaatselt." } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/fr.json b/homeassistant/components/yeelight/translations/fr.json index 37770c423ca..be55fe57ee0 100644 --- a/homeassistant/components/yeelight/translations/fr.json +++ b/homeassistant/components/yeelight/translations/fr.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "H\u00f4te", - "ip_address": "Adresse IP" + "host": "H\u00f4te" }, "description": "Si vous laissez l'adresse IP vide, la d\u00e9couverte sera utilis\u00e9e pour trouver des appareils." } @@ -35,6 +34,5 @@ "description": "Si vous ne pr\u00e9cisez pas le mod\u00e8le, il sera automatiquement d\u00e9tect\u00e9." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/it.json b/homeassistant/components/yeelight/translations/it.json index 1c887037b8e..a8129f4359d 100644 --- a/homeassistant/components/yeelight/translations/it.json +++ b/homeassistant/components/yeelight/translations/it.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "Host", - "ip_address": "Indirizzo IP" + "host": "Host" }, "description": "Se lasci l'host vuoto, il rilevamento verr\u00e0 utilizzato per trovare i dispositivi." } @@ -35,6 +34,5 @@ "description": "Se lasci il modello vuoto, verr\u00e0 rilevato automaticamente." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/ko.json b/homeassistant/components/yeelight/translations/ko.json index c04006e2c8f..7164e56b595 100644 --- a/homeassistant/components/yeelight/translations/ko.json +++ b/homeassistant/components/yeelight/translations/ko.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "\ud638\uc2a4\ud2b8", - "ip_address": "IP \uc8fc\uc18c" + "host": "\ud638\uc2a4\ud2b8" }, "description": "\ud638\uc2a4\ud2b8\ub97c \ube44\uc6cc\ub450\uba74 \uc7a5\uce58\ub97c \ucc3e\ub294 \ub370 \uac80\uc0c9\uc774 \uc0ac\uc6a9\ub429\ub2c8\ub2e4." } @@ -35,6 +34,5 @@ "description": "\ubaa8\ub378\uc744 \ube44\uc6cc \ub450\uba74 \uc790\ub3d9\uc73c\ub85c \uac80\uc0c9\ub429\ub2c8\ub2e4." } } - }, - "title": "\uc774\ub77c\uc774\ud2b8" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/lb.json b/homeassistant/components/yeelight/translations/lb.json index 6237ef6c5ef..482cbf23e48 100644 --- a/homeassistant/components/yeelight/translations/lb.json +++ b/homeassistant/components/yeelight/translations/lb.json @@ -1,5 +1,9 @@ { "config": { + "abort": { + "already_configured": "Apparat ass scho konfigur\u00e9iert", + "no_devices_found": "Keng Apparater am Netzwierk fonnt" + }, "error": { "cannot_connect": "Feeler beim verbannen" }, @@ -10,6 +14,9 @@ } }, "user": { + "data": { + "host": "Host" + }, "description": "Falls Host eidel gelass g\u00ebtt, g\u00ebtt eng automatesch Sich gestart" } } @@ -21,11 +28,11 @@ "model": "Modell (Optionell)", "nightlight_switch": "Nuechtliicht Schalter benotzen", "save_on_change": "Status sp\u00e4icheren bei \u00c4nnerung", + "transition": "Iwwergangsz\u00e4it (ms)", "use_music_mode": "Musek Modus aktiv\u00e9ieren" }, "description": "Falls Modell eidel gelass g\u00ebtt, g\u00ebtt et automatesch erkannt." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/nl.json b/homeassistant/components/yeelight/translations/nl.json index f9f78ffb6f6..7dd509cca06 100644 --- a/homeassistant/components/yeelight/translations/nl.json +++ b/homeassistant/components/yeelight/translations/nl.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "Host", - "ip_address": "IP adres" + "host": "Host" }, "description": "Als u host leeg laat, wordt detectie gebruikt om apparaten te vinden." } @@ -35,6 +34,5 @@ "description": "Als u model leeg laat, wordt het automatisch gedetecteerd." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/no.json b/homeassistant/components/yeelight/translations/no.json index c6b428c618f..5d3107b779f 100644 --- a/homeassistant/components/yeelight/translations/no.json +++ b/homeassistant/components/yeelight/translations/no.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "Vert", - "ip_address": "IP adresse" + "host": "Vert" }, "description": "Hvis du lar verten st\u00e5 tom, brukes automatisk oppdagelse til \u00e5 finne enheter" } @@ -35,6 +34,5 @@ "description": "Hvis du lar modellen v\u00e6re tom, blir den automatisk oppdaget." } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/pl.json b/homeassistant/components/yeelight/translations/pl.json index 9a477ba52d8..574f8303a4c 100644 --- a/homeassistant/components/yeelight/translations/pl.json +++ b/homeassistant/components/yeelight/translations/pl.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "Nazwa hosta lub adres IP", - "ip_address": "Adres IP" + "host": "Nazwa hosta lub adres IP" }, "description": "Je\u015bli nie podasz IP lub nazwy hosta, wykrywanie zostanie u\u017cyte do odnalezienia urz\u0105dze\u0144." } @@ -35,6 +34,5 @@ "description": "Je\u015bli nie podasz modelu urz\u0105dzenia, zostanie on automatycznie wykryty." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/pt.json b/homeassistant/components/yeelight/translations/pt.json index 7da4aff16ec..e4a8cc8062f 100644 --- a/homeassistant/components/yeelight/translations/pt.json +++ b/homeassistant/components/yeelight/translations/pt.json @@ -14,9 +14,6 @@ } }, "user": { - "data": { - "ip_address": "Endere\u00e7o IP" - }, "description": "Se voc\u00ea deixar o modelo vazio, ele ser\u00e1 detectado automaticamente." } } @@ -34,6 +31,5 @@ "description": "Se voc\u00ea deixar o modelo vazio, ele ser\u00e1 detectado automaticamente." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/ru.json b/homeassistant/components/yeelight/translations/ru.json index c078eae7d93..221fa3b4738 100644 --- a/homeassistant/components/yeelight/translations/ru.json +++ b/homeassistant/components/yeelight/translations/ru.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "\u0425\u043e\u0441\u0442", - "ip_address": "IP-\u0430\u0434\u0440\u0435\u0441" + "host": "\u0425\u043e\u0441\u0442" }, "description": "\u0415\u0441\u043b\u0438 \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u0445\u043e\u0441\u0442\u0430, \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438." } @@ -35,6 +34,5 @@ "description": "\u0415\u0441\u043b\u0438 \u043c\u043e\u0434\u0435\u043b\u044c \u043d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u0430, \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438." } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/yeelight/translations/zh-Hant.json b/homeassistant/components/yeelight/translations/zh-Hant.json index 9c41f3c3be6..b19ebdb40f8 100644 --- a/homeassistant/components/yeelight/translations/zh-Hant.json +++ b/homeassistant/components/yeelight/translations/zh-Hant.json @@ -15,8 +15,7 @@ }, "user": { "data": { - "host": "\u4e3b\u6a5f\u7aef", - "ip_address": "IP \u4f4d\u5740" + "host": "\u4e3b\u6a5f\u7aef" }, "description": "\u5047\u5982\u4e3b\u6a5f\u7aef\u4f4d\u5740\u6b04\u4f4d\u70ba\u7a7a\u767d\uff0c\u5c07\u6703\u63a2\u7d22\u6240\u6709\u53ef\u7528\u8a2d\u5099\u3002" } @@ -35,6 +34,5 @@ "description": "\u5047\u5982\u578b\u865f\u6b04\u4f4d\u70ba\u7a7a\u767d\uff0c\u5c07\u6703\u81ea\u52d5\u5075\u6e2c\u578b\u865f\u3002" } } - }, - "title": "Yeelight" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/light.py b/homeassistant/components/zerproc/light.py index 0fa18197764..2ab4bc127c4 100644 --- a/homeassistant/components/zerproc/light.py +++ b/homeassistant/components/zerproc/light.py @@ -1,7 +1,7 @@ """Zerproc light platform.""" from datetime import timedelta import logging -from typing import Callable, List +from typing import Callable, List, Optional import pyzerproc @@ -142,6 +142,11 @@ class ZerprocLight(LightEntity): "manufacturer": "Zerproc", } + @property + def icon(self) -> Optional[str]: + """Return the icon to use in the frontend.""" + return "mdi:string-lights" + @property def supported_features(self): """Flag supported features.""" diff --git a/homeassistant/components/zerproc/strings.json b/homeassistant/components/zerproc/strings.json index 9662bdc36d8..ad8f0f41ae7 100644 --- a/homeassistant/components/zerproc/strings.json +++ b/homeassistant/components/zerproc/strings.json @@ -1,5 +1,4 @@ { - "title": "Zerproc", "config": { "step": { "confirm": { diff --git a/homeassistant/components/zerproc/translations/ca.json b/homeassistant/components/zerproc/translations/ca.json index ddc9a9298cb..dc21c371e60 100644 --- a/homeassistant/components/zerproc/translations/ca.json +++ b/homeassistant/components/zerproc/translations/ca.json @@ -9,6 +9,5 @@ "description": "Vols comen\u00e7ar la configuraci\u00f3?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/cs.json b/homeassistant/components/zerproc/translations/cs.json index 62305d54d01..d3f0e37a132 100644 --- a/homeassistant/components/zerproc/translations/cs.json +++ b/homeassistant/components/zerproc/translations/cs.json @@ -9,6 +9,5 @@ "description": "Chcete za\u010d\u00edt nastavovat?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/en.json b/homeassistant/components/zerproc/translations/en.json index f88874372c8..f05becffed3 100644 --- a/homeassistant/components/zerproc/translations/en.json +++ b/homeassistant/components/zerproc/translations/en.json @@ -9,6 +9,5 @@ "description": "Do you want to start set up?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/es.json b/homeassistant/components/zerproc/translations/es.json index 56a0be99057..520df7ee4cd 100644 --- a/homeassistant/components/zerproc/translations/es.json +++ b/homeassistant/components/zerproc/translations/es.json @@ -9,6 +9,5 @@ "description": "\u00bfQuieres iniciar la configuraci\u00f3n?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/et.json b/homeassistant/components/zerproc/translations/et.json index bbe8d0cd2f3..a6507436210 100644 --- a/homeassistant/components/zerproc/translations/et.json +++ b/homeassistant/components/zerproc/translations/et.json @@ -9,6 +9,5 @@ "description": "Kas alustan seadistamist?" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/fr.json b/homeassistant/components/zerproc/translations/fr.json index 62dd56a3792..80ae6cb0ec8 100644 --- a/homeassistant/components/zerproc/translations/fr.json +++ b/homeassistant/components/zerproc/translations/fr.json @@ -9,6 +9,5 @@ "description": "Voulez-vous demmarer la configuration ?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/it.json b/homeassistant/components/zerproc/translations/it.json index 91f3a3a984b..0278fe07bfe 100644 --- a/homeassistant/components/zerproc/translations/it.json +++ b/homeassistant/components/zerproc/translations/it.json @@ -9,6 +9,5 @@ "description": "Vuoi iniziare la configurazione?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/ko.json b/homeassistant/components/zerproc/translations/ko.json index 641f498c3b3..7011a61f757 100644 --- a/homeassistant/components/zerproc/translations/ko.json +++ b/homeassistant/components/zerproc/translations/ko.json @@ -9,6 +9,5 @@ "description": "\uc124\uc815\uc744 \uc2dc\uc791\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/lb.json b/homeassistant/components/zerproc/translations/lb.json index d4a2cccba4c..82f36a6f452 100644 --- a/homeassistant/components/zerproc/translations/lb.json +++ b/homeassistant/components/zerproc/translations/lb.json @@ -9,6 +9,5 @@ "description": "Soll d'Konfiguratioun gestart ginn?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/nl.json b/homeassistant/components/zerproc/translations/nl.json deleted file mode 100644 index cdfd3890fb8..00000000000 --- a/homeassistant/components/zerproc/translations/nl.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "Zerproc" -} \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/no.json b/homeassistant/components/zerproc/translations/no.json index 602a81af2f5..b3d6b5d782e 100644 --- a/homeassistant/components/zerproc/translations/no.json +++ b/homeassistant/components/zerproc/translations/no.json @@ -9,6 +9,5 @@ "description": "Vil du starte oppsettet?" } } - }, - "title": "" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/pl.json b/homeassistant/components/zerproc/translations/pl.json index c5c191f22d6..a8ee3fa57ac 100644 --- a/homeassistant/components/zerproc/translations/pl.json +++ b/homeassistant/components/zerproc/translations/pl.json @@ -9,6 +9,5 @@ "description": "Czy chcesz rozpocz\u0105\u0107 konfiguracj\u0119?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/pt-BR.json b/homeassistant/components/zerproc/translations/pt-BR.json index f00723f833b..4cbb697371e 100644 --- a/homeassistant/components/zerproc/translations/pt-BR.json +++ b/homeassistant/components/zerproc/translations/pt-BR.json @@ -9,6 +9,5 @@ "description": "Deseja iniciar a configura\u00e7\u00e3o?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/ru.json b/homeassistant/components/zerproc/translations/ru.json index 438c1f2df58..85a42bf1be5 100644 --- a/homeassistant/components/zerproc/translations/ru.json +++ b/homeassistant/components/zerproc/translations/ru.json @@ -9,6 +9,5 @@ "description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443?" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zerproc/translations/zh-Hant.json b/homeassistant/components/zerproc/translations/zh-Hant.json index 720d3f293ee..91a0dc60be7 100644 --- a/homeassistant/components/zerproc/translations/zh-Hant.json +++ b/homeassistant/components/zerproc/translations/zh-Hant.json @@ -9,6 +9,5 @@ "description": "\u662f\u5426\u8981\u958b\u59cb\u8a2d\u5b9a\uff1f" } } - }, - "title": "Zerproc" + } } \ No newline at end of file diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 82c57abd82b..91fe51f7793 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -807,18 +807,12 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati clusters_to_bind = await get_matched_clusters(source_device, target_device) + zdo = source_device.device.zdo bind_tasks = [] - for cluster_pair in clusters_to_bind: - destination_address = zdo_types.MultiAddress() - destination_address.addrmode = 3 - destination_address.ieee = target_device.ieee - destination_address.endpoint = cluster_pair.target_cluster.endpoint.endpoint_id - - zdo = cluster_pair.source_cluster.endpoint.device.zdo - + for binding_pair in clusters_to_bind: op_msg = "cluster: %s %s --> [%s]" op_params = ( - cluster_pair.source_cluster.cluster_id, + binding_pair.source_cluster.cluster_id, operation.name, target_ieee, ) @@ -829,9 +823,9 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati zdo.request( operation, source_device.ieee, - cluster_pair.source_cluster.endpoint.endpoint_id, - cluster_pair.source_cluster.cluster_id, - destination_address, + binding_pair.source_cluster.endpoint.endpoint_id, + binding_pair.source_cluster.cluster_id, + binding_pair.destination_address, ), op_msg, op_params, diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index dca80e9fcb3..1bd8a52b6e6 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -4,6 +4,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union import zigpy.zcl.clusters.closures +from homeassistant.const import ATTR_DEVICE_ID from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_send @@ -157,6 +158,7 @@ class Channels: { const.ATTR_DEVICE_IEEE: str(self.zha_device.ieee), const.ATTR_UNIQUE_ID: self.unique_id, + ATTR_DEVICE_ID: self.zha_device.device_id, **event_data, }, ) diff --git a/homeassistant/components/zha/core/channels/general.py b/homeassistant/components/zha/core/channels/general.py index 2cb744ec063..f443151de02 100644 --- a/homeassistant/components/zha/core/channels/general.py +++ b/homeassistant/components/zha/core/channels/general.py @@ -167,6 +167,11 @@ class LevelControlChannel(ZigbeeChannel): CURRENT_LEVEL = 0 REPORT_CONFIG = ({"attr": "current_level", "config": REPORT_CONFIG_ASAP},) + @property + def current_level(self) -> Optional[int]: + """Return cached value of the current_level attribute.""" + return self.cluster.get("current_level") + @callback def cluster_command(self, tsn, command_id, args): """Handle commands received to this cluster.""" @@ -248,6 +253,11 @@ class OnOffChannel(ZigbeeChannel): self._state = None self._off_listener = None + @property + def on_off(self) -> Optional[bool]: + """Return cached value of on/off attribute.""" + return self.cluster.get("on_off") + @callback def cluster_command(self, tsn, command_id, args): """Handle commands received to this cluster.""" diff --git a/homeassistant/components/zha/core/channels/lighting.py b/homeassistant/components/zha/core/channels/lighting.py index ac88ba1c2c0..9d52ff12d37 100644 --- a/homeassistant/components/zha/core/channels/lighting.py +++ b/homeassistant/components/zha/core/channels/lighting.py @@ -1,4 +1,6 @@ """Lighting channels module for Zigbee Home Automation.""" +from typing import Optional + import zigpy.zcl.clusters.lighting as lighting from .. import registries, typing as zha_typing @@ -41,14 +43,34 @@ class ColorChannel(ZigbeeChannel): self._max_mireds = 500 @property - def min_mireds(self): - """Return the coldest color_temp that this channel supports.""" - return self._min_mireds + def color_loop_active(self) -> Optional[int]: + """Return cached value of the color_loop_active attribute.""" + return self.cluster.get("color_loop_active") @property - def max_mireds(self): + def color_temperature(self) -> Optional[int]: + """Return cached value of color temperature.""" + return self.cluster.get("color_temperature") + + @property + def current_x(self) -> Optional[int]: + """Return cached value of the current_x attribute.""" + return self.cluster.get("current_x") + + @property + def current_y(self) -> Optional[int]: + """Return cached value of the current_y attribute.""" + return self.cluster.get("current_y") + + @property + def min_mireds(self) -> int: + """Return the coldest color_temp that this channel supports.""" + return self.cluster.get("color_temp_physical_min", self._min_mireds) + + @property + def max_mireds(self) -> int: """Return the warmest color_temp that this channel supports.""" - return self._max_mireds + return self.cluster.get("color_temp_physical_max", self._max_mireds) def get_color_capabilities(self): """Return the color capabilities.""" @@ -74,8 +96,6 @@ class ColorChannel(ZigbeeChannel): ] results = await self.get_attributes(attributes, from_cache=from_cache) capabilities = results.get("color_capabilities") - self._min_mireds = results.get("color_temp_physical_min", 153) - self._max_mireds = results.get("color_temp_physical_max", 500) if capabilities is None: # ZCL Version 4 devices don't support the color_capabilities diff --git a/homeassistant/components/zha/core/channels/security.py b/homeassistant/components/zha/core/channels/security.py index 126dc761572..156ada1e8f1 100644 --- a/homeassistant/components/zha/core/channels/security.py +++ b/homeassistant/components/zha/core/channels/security.py @@ -155,6 +155,15 @@ class IASZoneChannel(ZigbeeChannel): self._cluster.ep_attribute, str(ex), ) + + try: + self.debug("Sending pro-active IAS enroll response") + await self._cluster.enroll_response(0, 0) + except ZigbeeException as ex: + self.debug( + "Failed to send pro-active IAS enroll response: %s", + str(ex), + ) self.debug("finished IASZoneChannel configuration") @callback diff --git a/homeassistant/components/zha/core/channels/smartenergy.py b/homeassistant/components/zha/core/channels/smartenergy.py index d30f891dee1..120d0afdfb6 100644 --- a/homeassistant/components/zha/core/channels/smartenergy.py +++ b/homeassistant/components/zha/core/channels/smartenergy.py @@ -5,8 +5,8 @@ from homeassistant.const import ( POWER_WATT, TIME_HOURS, TIME_SECONDS, - VOLUME_CUBIC_FEET, - VOLUME_CUBIC_METERS, + VOLUME_FLOW_RATE_CUBIC_FEET_PER_MINUTE, + VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, ) from homeassistant.core import callback @@ -63,8 +63,8 @@ class Metering(ZigbeeChannel): unit_of_measure_map = { 0x00: POWER_WATT, - 0x01: f"{VOLUME_CUBIC_METERS}/{TIME_HOURS}", - 0x02: f"{VOLUME_CUBIC_FEET}/{TIME_HOURS}", + 0x01: VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, + 0x02: VOLUME_FLOW_RATE_CUBIC_FEET_PER_MINUTE, 0x03: f"ccf/{TIME_HOURS}", 0x04: f"US gal/{TIME_HOURS}", 0x05: f"IMP gal/{TIME_HOURS}", diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index 2b4f8359e90..81b522308ff 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -30,7 +30,6 @@ from .const import ( ATTR_CLUSTER_ID, ATTR_COMMAND, ATTR_COMMAND_TYPE, - ATTR_DEVICE_IEEE, ATTR_DEVICE_TYPE, ATTR_ENDPOINT_ID, ATTR_ENDPOINT_NAMES, @@ -355,10 +354,8 @@ class ZHADevice(LogMixin): self.hass.async_create_task(self._async_became_available()) return if availability_changed and not available: - self.hass.bus.async_fire( - "zha_event", + self._channels.zha_send_event( { - ATTR_DEVICE_IEEE: str(self.ieee), "device_event_type": "device_offline", }, ) diff --git a/homeassistant/components/zha/core/helpers.py b/homeassistant/components/zha/core/helpers.py index 9b62cef4ace..47911fc1078 100644 --- a/homeassistant/components/zha/core/helpers.py +++ b/homeassistant/components/zha/core/helpers.py @@ -7,7 +7,7 @@ https://home-assistant.io/integrations/zha/ import asyncio import binascii -import collections +from dataclasses import dataclass import functools import itertools import logging @@ -19,13 +19,29 @@ import voluptuous as vol import zigpy.exceptions import zigpy.types import zigpy.util +import zigpy.zdo.types as zdo_types from homeassistant.core import State, callback from .const import CLUSTER_TYPE_IN, CLUSTER_TYPE_OUT, DATA_ZHA, DATA_ZHA_GATEWAY from .registries import BINDABLE_CLUSTERS +from .typing import ZhaDeviceType, ZigpyClusterType -ClusterPair = collections.namedtuple("ClusterPair", "source_cluster target_cluster") + +@dataclass +class BindingPair: + """Information for binding.""" + + source_cluster: ZigpyClusterType + target_ieee: zigpy.types.EUI64 + target_ep_id: int + + @property + def destination_address(self) -> zdo_types.MultiAddress: + """Return a ZDO multi address instance.""" + return zdo_types.MultiAddress( + addrmode=3, ieee=self.target_ieee, endpoint=self.target_ep_id + ) async def safe_read( @@ -49,7 +65,9 @@ async def safe_read( return {} -async def get_matched_clusters(source_zha_device, target_zha_device): +async def get_matched_clusters( + source_zha_device: ZhaDeviceType, target_zha_device: ZhaDeviceType +) -> List[BindingPair]: """Get matched input/output cluster pairs for 2 devices.""" source_clusters = source_zha_device.async_get_std_clusters() target_clusters = target_zha_device.async_get_std_clusters() @@ -59,15 +77,26 @@ async def get_matched_clusters(source_zha_device, target_zha_device): for cluster_id in source_clusters[endpoint_id][CLUSTER_TYPE_OUT]: if cluster_id not in BINDABLE_CLUSTERS: continue + if target_zha_device.nwk == 0x0000: + cluster_pair = BindingPair( + source_cluster=source_clusters[endpoint_id][CLUSTER_TYPE_OUT][ + cluster_id + ], + target_ieee=target_zha_device.ieee, + target_ep_id=target_zha_device.device.application.get_endpoint_id( + cluster_id, is_server_cluster=True + ), + ) + clusters_to_bind.append(cluster_pair) + continue for t_endpoint_id in target_clusters: if cluster_id in target_clusters[t_endpoint_id][CLUSTER_TYPE_IN]: - cluster_pair = ClusterPair( + cluster_pair = BindingPair( source_cluster=source_clusters[endpoint_id][CLUSTER_TYPE_OUT][ cluster_id ], - target_cluster=target_clusters[t_endpoint_id][CLUSTER_TYPE_IN][ - cluster_id - ], + target_ieee=target_zha_device.ieee, + target_ep_id=t_endpoint_id, ) clusters_to_bind.append(cluster_pair) return clusters_to_bind @@ -76,6 +105,9 @@ async def get_matched_clusters(source_zha_device, target_zha_device): @callback def async_is_bindable_target(source_zha_device, target_zha_device): """Determine if target is bindable to source.""" + if target_zha_device.nwk == 0x0000: + return True + source_clusters = source_zha_device.async_get_std_clusters() target_clusters = target_zha_device.async_get_std_clusters() diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index 34c27f0af45..22ab0cdcb21 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -328,6 +328,7 @@ class Light(BaseLight, ZhaEntity): """Initialize the ZHA light.""" super().__init__(unique_id, zha_device, channels, **kwargs) self._on_off_channel = self.cluster_channels.get(CHANNEL_ON_OFF) + self._state = bool(self._on_off_channel.on_off) self._level_channel = self.cluster_channels.get(CHANNEL_LEVEL) self._color_channel = self.cluster_channels.get(CHANNEL_COLOR) self._identify_channel = self.zha_device.channels.identify_ch @@ -340,20 +341,30 @@ class Light(BaseLight, ZhaEntity): if self._level_channel: self._supported_features |= light.SUPPORT_BRIGHTNESS self._supported_features |= light.SUPPORT_TRANSITION - self._brightness = 0 + self._brightness = self._level_channel.current_level if self._color_channel: color_capabilities = self._color_channel.get_color_capabilities() if color_capabilities & CAPABILITIES_COLOR_TEMP: self._supported_features |= light.SUPPORT_COLOR_TEMP + self._color_temp = self._color_channel.color_temperature if color_capabilities & CAPABILITIES_COLOR_XY: self._supported_features |= light.SUPPORT_COLOR - self._hs_color = (0, 0) + curr_x = self._color_channel.current_x + curr_y = self._color_channel.current_y + if curr_x is not None and curr_y is not None: + self._hs_color = color_util.color_xy_to_hs( + float(curr_x / 65535), float(curr_y / 65535) + ) + else: + self._hs_color = (0, 0) if color_capabilities & CAPABILITIES_COLOR_LOOP: self._supported_features |= light.SUPPORT_EFFECT effect_list.append(light.EFFECT_COLORLOOP) + if self._color_channel.color_loop_active == 1: + self._effect = light.EFFECT_COLORLOOP if self._identify_channel: self._supported_features |= light.SUPPORT_FLASH diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index be8619811d8..0dfb9ab5098 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -6,12 +6,12 @@ "requirements": [ "bellows==0.20.3", "pyserial==3.4", - "zha-quirks==0.0.45", + "zha-quirks==0.0.46", "zigpy-cc==0.5.2", "zigpy-deconz==0.11.0", "zigpy==0.27.0", "zigpy-xbee==0.13.0", - "zigpy-zigate==0.6.2", + "zigpy-zigate==0.7.2", "zigpy-znp==0.2.2" ], "codeowners": ["@dmulcahey", "@adminiuga"] diff --git a/homeassistant/components/zha/translations/cs.json b/homeassistant/components/zha/translations/cs.json index b36a1651e0a..1ac4c7c2d61 100644 --- a/homeassistant/components/zha/translations/cs.json +++ b/homeassistant/components/zha/translations/cs.json @@ -14,11 +14,15 @@ "title": "Nastaven\u00ed" }, "user": { + "description": "Vyberte s\u00e9riov\u00fd port pro r\u00e1dio Zigbee", "title": "ZHA" } } }, "device_automation": { + "action_type": { + "warn": "Varovat" + }, "trigger_subtype": { "both_buttons": "Ob\u011b tla\u010d\u00edtka", "button_1": "Prvn\u00ed tla\u010d\u00edtko", diff --git a/homeassistant/components/zha/translations/et.json b/homeassistant/components/zha/translations/et.json index 9d43ded0eb2..4926476a5c6 100644 --- a/homeassistant/components/zha/translations/et.json +++ b/homeassistant/components/zha/translations/et.json @@ -48,6 +48,13 @@ "close": "Sulge", "dim_down": "H\u00e4marda", "dim_up": "Tee heledamaks", + "face_1": "k\u00fclg 1 on \u00fcleval", + "face_2": "k\u00fclg 2 on \u00fcleval", + "face_3": "k\u00fclg 3 on \u00fcleval", + "face_4": "k\u00fclg 4 on \u00fcleval", + "face_5": "k\u00fclg 5 on \u00fcleval", + "face_6": "k\u00fclg 6 on \u00fcleval", + "face_any": "mistahes k\u00fclg on \u00fcleval", "left": "Vasakule", "open": "Ava", "right": "Paremale", @@ -56,23 +63,23 @@ }, "trigger_type": { "device_dropped": "Seade kukkus", - "device_flipped": "Seade \" {subtype} \" p\u00f6\u00f6rati \u00fcmber", - "device_knocked": "Seadet \" {subtype} \" koputati", + "device_flipped": "Seadet p\u00f6\u00f6rati {subtype}", + "device_knocked": "Seadet koputati {subtype}", "device_offline": "Seade on v\u00f5rgu\u00fchenduseta", - "device_rotated": "Seadet \" {subtype} \" keerati", + "device_rotated": "Seadet keerati {subtype}", "device_shaken": "Seadet raputati", - "device_slid": "Seade \" {subtype} \" libises", + "device_slid": "Seadet libistati {subtype}", "device_tilted": "Seadet kallutati", "remote_button_alt_double_press": "\"{subtype}\" on topeltkl\u00f5psatud (alternatiivre\u017eiim)", "remote_button_alt_long_press": "\"{subtype}\" nuppu vajutati pikalt (alternatiivre\u017eiim)", "remote_button_alt_long_release": "\"{subtype}\" nupp vabastati peale pikka vajutust (alternatiivre\u017eiim)", "remote_button_alt_quadruple_press": "\"{subtype}\" on neljakordselt kl\u00f5psatud (alternatiivre\u017eiim)", - "remote_button_alt_quintuple_press": "\"{subtype}\" on neljakordselt kl\u00f5psatud (alternatiivre\u017eiim)", - "remote_button_alt_short_press": "\"{subtype}\" nuppu vajutati (alternatiivre\u017eiim)", - "remote_button_alt_short_release": "\"{subtype}\" nupp vabastati (alternatiivre\u017eiim)", - "remote_button_alt_triple_press": "\"{subtype}\" on kolmekordselt kl\u00f5psatud (alternatiivre\u017eiim)", - "remote_button_double_press": "\" {subtype} \" on topeltkl\u00f5psatud", - "remote_button_long_press": "\" {subtype} \" on pikalt alla vajutatud", + "remote_button_alt_quintuple_press": "{subtype} on neljakordselt kl\u00f5psatud (alternatiivre\u017eiim)", + "remote_button_alt_short_press": "{subtype} nuppu vajutati (alternatiivre\u017eiim)", + "remote_button_alt_short_release": "{subtype} nupp vabastati (alternatiivre\u017eiim)", + "remote_button_alt_triple_press": "{subtype} on kolmekordselt kl\u00f5psatud (alternatiivre\u017eiim)", + "remote_button_double_press": "{subtype} on topeltkl\u00f5psatud", + "remote_button_long_press": "{subtype} on pikalt alla vajutatud", "remote_button_long_release": "\"{subtype}\" nupp vabastatati p\u00e4rast pikka vajutust", "remote_button_quadruple_press": "\"{subtype}\" nuppu on neljakordselt kl\u00f5psatud", "remote_button_quintuple_press": "\"{subtype}\" nuppu on viiekordselt kl\u00f5psatud", diff --git a/homeassistant/components/zha/translations/lb.json b/homeassistant/components/zha/translations/lb.json index e2c4a63f8d7..3e076eca496 100644 --- a/homeassistant/components/zha/translations/lb.json +++ b/homeassistant/components/zha/translations/lb.json @@ -1,10 +1,10 @@ { "config": { "abort": { - "single_instance_allowed": "N\u00ebmmen eng eenzeg Konfiguratioun vun ZHA ass erlaabt." + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { - "cannot_connect": "Keng Verbindung mam ZHA Apparat m\u00e9iglech." + "cannot_connect": "Feeler beim verbannen" }, "step": { "pick_radio": { diff --git a/homeassistant/components/zha/translations/nl.json b/homeassistant/components/zha/translations/nl.json index 569358d9fc7..9a7a83e19d3 100644 --- a/homeassistant/components/zha/translations/nl.json +++ b/homeassistant/components/zha/translations/nl.json @@ -17,6 +17,7 @@ "port_config": { "data": { "baudrate": "poort snelheid", + "flow_control": "gegevensstroombeheer", "path": "Serieel apparaatpad" }, "description": "Voer poortspecifieke instellingen in", diff --git a/homeassistant/components/zha/translations/pl.json b/homeassistant/components/zha/translations/pl.json index 3e047b558ef..ab4402558ba 100644 --- a/homeassistant/components/zha/translations/pl.json +++ b/homeassistant/components/zha/translations/pl.json @@ -58,14 +58,14 @@ "left": "w lewo", "open": "otw\u00f3rz", "right": "w prawo", - "turn_off": "wy\u0142\u0105cz", - "turn_on": "w\u0142\u0105cz" + "turn_off": "wy\u0142\u0105cznik", + "turn_on": "w\u0142\u0105cznik" }, "trigger_type": { "device_dropped": "nast\u0105pi upadek urz\u0105dzenia", "device_flipped": "nast\u0105pi odwr\u00f3cenie urz\u0105dzenia \"{subtype}\"", "device_knocked": "nast\u0105pi pukni\u0119cie w urz\u0105dzenie \"{subtype}\"", - "device_offline": "Urz\u0105dzenie offline", + "device_offline": "urz\u0105dzenie przejdzie w tryb offline", "device_rotated": "nast\u0105pi obr\u00f3cenie urz\u0105dzenia \"{subtype}\"", "device_shaken": "nast\u0105pi potrz\u0105\u015bni\u0119cie urz\u0105dzeniem", "device_slid": "nast\u0105pi przesuni\u0119cie urz\u0105dzenia \"{subtype}\"", diff --git a/homeassistant/components/zha/translations/ru.json b/homeassistant/components/zha/translations/ru.json index 4070d759a90..b97e27ced5d 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/zha/translations/zh-Hans.json b/homeassistant/components/zha/translations/zh-Hans.json index 4df88473d0d..a594ffe3545 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 diff --git a/homeassistant/components/zone/trigger.py b/homeassistant/components/zone/trigger.py index 9958d201810..bc827c2ba0d 100644 --- a/homeassistant/components/zone/trigger.py +++ b/homeassistant/components/zone/trigger.py @@ -8,11 +8,12 @@ from homeassistant.const import ( CONF_PLATFORM, CONF_ZONE, ) -from homeassistant.core import HassJob, callback +from homeassistant.core import CALLBACK_TYPE, HassJob, callback from homeassistant.helpers import condition, config_validation as cv, location from homeassistant.helpers.event import async_track_state_change_event -# mypy: allow-untyped-defs, no-check-untyped-defs +# mypy: allow-incomplete-defs, allow-untyped-defs +# mypy: no-check-untyped-defs EVENT_ENTER = "enter" EVENT_LEAVE = "leave" @@ -32,7 +33,9 @@ TRIGGER_SCHEMA = vol.Schema( ) -async def async_attach_trigger(hass, config, action, automation_info): +async def async_attach_trigger( + hass, config, action, automation_info, *, platform_type: str = "zone" +) -> CALLBACK_TYPE: """Listen for state changes based on configuration.""" entity_id = config.get(CONF_ENTITY_ID) zone_entity_id = config.get(CONF_ZONE) @@ -70,7 +73,7 @@ async def async_attach_trigger(hass, config, action, automation_info): job, { "trigger": { - "platform": "zone", + "platform": platform_type, "entity_id": entity, "from_state": from_s, "to_state": to_s, diff --git a/homeassistant/components/zoneminder/translations/nl.json b/homeassistant/components/zoneminder/translations/nl.json index 126abbe2d28..ebfd26329dc 100644 --- a/homeassistant/components/zoneminder/translations/nl.json +++ b/homeassistant/components/zoneminder/translations/nl.json @@ -3,13 +3,15 @@ "abort": { "auth_fail": "Gebruikersnaam of wachtwoord is onjuist.", "cannot_connect": "Kan geen verbinding maken", - "connection_error": "Kan geen verbinding maken met een ZoneMinder-server." + "connection_error": "Kan geen verbinding maken met een ZoneMinder-server.", + "invalid_auth": "Ongeldige authenticatie" }, "create_entry": { "default": "ZoneMinder-server toegevoegd." }, "error": { "auth_fail": "Gebruikersnaam of wachtwoord is onjuist.", + "cannot_connect": "Kon niet verbinden", "connection_error": "Kan geen verbinding maken met een ZoneMinder-server." }, "flow_title": "ZoneMinder", diff --git a/homeassistant/components/zoneminder/translations/pl.json b/homeassistant/components/zoneminder/translations/pl.json index 055b60de794..f8919d7a054 100644 --- a/homeassistant/components/zoneminder/translations/pl.json +++ b/homeassistant/components/zoneminder/translations/pl.json @@ -12,7 +12,7 @@ "error": { "auth_fail": "Nazwa u\u017cytkownika lub has\u0142o jest niepoprawne", "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia", - "connection_error": "Nie uda\u0142o si\u0119 po\u0142\u0105czy\u0107 z serwerem ZoneMinder", + "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia z serwerem ZoneMinder", "invalid_auth": "Niepoprawne uwierzytelnienie" }, "flow_title": "ZoneMinder", diff --git a/homeassistant/components/zwave/translations/bg.json b/homeassistant/components/zwave/translations/bg.json index e1ce9e37a70..191640ad0a0 100644 --- a/homeassistant/components/zwave/translations/bg.json +++ b/homeassistant/components/zwave/translations/bg.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d", - "one_instance_only": "\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0441\u0430\u043c\u043e \u0435\u0434\u0438\u043d Z-Wave \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440." + "already_configured": "Z-Wave \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d" }, "error": { "option_error": "\u0412\u0430\u043b\u0438\u0434\u0438\u0440\u0430\u043d\u0435\u0442\u043e \u043d\u0430 Z-Wave \u043d\u0435 \u0431\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e. \u041f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u043b\u0438 \u0435 \u043f\u044a\u0442\u044f\u0442 \u043a\u044a\u043c USB \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e?" diff --git a/homeassistant/components/zwave/translations/ca.json b/homeassistant/components/zwave/translations/ca.json index ce4e7f5301b..3c97d8c212f 100644 --- a/homeassistant/components/zwave/translations/ca.json +++ b/homeassistant/components/zwave/translations/ca.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "El dispositiu ja est\u00e0 configurat", - "one_instance_only": "El component nom\u00e9s admet una inst\u00e0ncia de Z-Wave", "single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3." }, "error": { diff --git a/homeassistant/components/zwave/translations/cs.json b/homeassistant/components/zwave/translations/cs.json index 0e107422a47..40488adfe52 100644 --- a/homeassistant/components/zwave/translations/cs.json +++ b/homeassistant/components/zwave/translations/cs.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno", - "one_instance_only": "Komponenta podporuje pouze jednu instanci Z-Wave", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "error": { diff --git a/homeassistant/components/zwave/translations/da.json b/homeassistant/components/zwave/translations/da.json index 233b8250991..effd2d5a98a 100644 --- a/homeassistant/components/zwave/translations/da.json +++ b/homeassistant/components/zwave/translations/da.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave er allerede konfigureret", - "one_instance_only": "Komponenten underst\u00f8tter kun \u00e9n Z-Wave-instans" + "already_configured": "Z-Wave er allerede konfigureret" }, "error": { "option_error": "Z-Wave-validering mislykkedes. Er stien til USB-enhed korrekt?" diff --git a/homeassistant/components/zwave/translations/de.json b/homeassistant/components/zwave/translations/de.json index 876cdf42921..60b5aa88024 100644 --- a/homeassistant/components/zwave/translations/de.json +++ b/homeassistant/components/zwave/translations/de.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave ist bereits konfiguriert", - "one_instance_only": "Komponente unterst\u00fctzt nur eine Z-Wave-Instanz" + "already_configured": "Z-Wave ist bereits konfiguriert" }, "error": { "option_error": "Z-Wave-Validierung fehlgeschlagen. Ist der Pfad zum USB-Stick korrekt?" diff --git a/homeassistant/components/zwave/translations/en.json b/homeassistant/components/zwave/translations/en.json index 19732f99e6f..d13e5575e61 100644 --- a/homeassistant/components/zwave/translations/en.json +++ b/homeassistant/components/zwave/translations/en.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Device is already configured", - "one_instance_only": "Component only supports one Z-Wave instance", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "error": { diff --git a/homeassistant/components/zwave/translations/es-419.json b/homeassistant/components/zwave/translations/es-419.json index e4cb16af6c4..0376714dd84 100644 --- a/homeassistant/components/zwave/translations/es-419.json +++ b/homeassistant/components/zwave/translations/es-419.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave ya est\u00e1 configurado", - "one_instance_only": "El componente solo admite una instancia de Z-Wave" + "already_configured": "Z-Wave ya est\u00e1 configurado" }, "error": { "option_error": "La validaci\u00f3n de Z-Wave fall\u00f3. \u00bfEs correcta la ruta a la memoria USB?" diff --git a/homeassistant/components/zwave/translations/es.json b/homeassistant/components/zwave/translations/es.json index f4d8141d7d7..08408bf9d92 100644 --- a/homeassistant/components/zwave/translations/es.json +++ b/homeassistant/components/zwave/translations/es.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Z-Wave ya est\u00e1 configurado", - "one_instance_only": "El componente solo admite una instancia de Z-Wave", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "error": { diff --git a/homeassistant/components/zwave/translations/et.json b/homeassistant/components/zwave/translations/et.json index 93705f4c805..ef36101b3ad 100644 --- a/homeassistant/components/zwave/translations/et.json +++ b/homeassistant/components/zwave/translations/et.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Seade on juba h\u00e4\u00e4lestatud", - "one_instance_only": "Komponent toetab ainult \u00fchte Z-Wave sidumist", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "error": { diff --git a/homeassistant/components/zwave/translations/fr.json b/homeassistant/components/zwave/translations/fr.json index d60a1c9f11e..6c23d35ac4e 100644 --- a/homeassistant/components/zwave/translations/fr.json +++ b/homeassistant/components/zwave/translations/fr.json @@ -2,7 +2,7 @@ "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" + "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?" diff --git a/homeassistant/components/zwave/translations/hu.json b/homeassistant/components/zwave/translations/hu.json index b443a30bada..240e7fe776c 100644 --- a/homeassistant/components/zwave/translations/hu.json +++ b/homeassistant/components/zwave/translations/hu.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "A Z-Wave m\u00e1r konfigur\u00e1lva van", - "one_instance_only": "Az \u00f6sszetev\u0151 csak egy Z-Wave p\u00e9ld\u00e1nyt t\u00e1mogat" + "already_configured": "A Z-Wave m\u00e1r konfigur\u00e1lva van" }, "error": { "option_error": "A Z-Wave \u00e9rv\u00e9nyes\u00edt\u00e9s sikertelen. Az USB-meghajt\u00f3 el\u00e9r\u00e9si \u00fatj\u00e1t helyesen adtad meg?" diff --git a/homeassistant/components/zwave/translations/it.json b/homeassistant/components/zwave/translations/it.json index d8647733fad..0534d54f32f 100644 --- a/homeassistant/components/zwave/translations/it.json +++ b/homeassistant/components/zwave/translations/it.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato", - "one_instance_only": "Il componente supporta solo un'istanza di Z-Wave", "single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione." }, "error": { diff --git a/homeassistant/components/zwave/translations/ko.json b/homeassistant/components/zwave/translations/ko.json index 0cf4e05c19d..1357fd492c5 100644 --- a/homeassistant/components/zwave/translations/ko.json +++ b/homeassistant/components/zwave/translations/ko.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave \uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", - "one_instance_only": "\uad6c\uc131\uc694\uc18c\ub294 \ud558\ub098\uc758 Z-Wave \uc778\uc2a4\ud134\uc2a4\ub9cc \uc9c0\uc6d0\ud569\ub2c8\ub2e4" + "already_configured": "Z-Wave \uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4" }, "error": { "option_error": "Z-Wave \uc720\ud6a8\uc131 \uac80\uc0ac\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. USB \uc2a4\ud2f1\uc758 \uacbd\ub85c\uac00 \uc815\ud655\ud569\ub2c8\uae4c?" diff --git a/homeassistant/components/zwave/translations/lb.json b/homeassistant/components/zwave/translations/lb.json index 4b2caf08ad9..d2359ff4c61 100644 --- a/homeassistant/components/zwave/translations/lb.json +++ b/homeassistant/components/zwave/translations/lb.json @@ -1,8 +1,8 @@ { "config": { "abort": { - "already_configured": "Z-Wave ass scho konfigur\u00e9iert", - "one_instance_only": "Komponent \u00ebnnerst\u00ebtzt n\u00ebmmen eng Z-Wave Instanz" + "already_configured": "Apparat ass scho konfigur\u00e9iert", + "single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech." }, "error": { "option_error": "Z-Wave Validatioun net g\u00eblteg. Ass de Pad zum USB Stick richteg?" diff --git a/homeassistant/components/zwave/translations/nl.json b/homeassistant/components/zwave/translations/nl.json index 35f912576e5..50e81003d27 100644 --- a/homeassistant/components/zwave/translations/nl.json +++ b/homeassistant/components/zwave/translations/nl.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Z-Wave is al geconfigureerd", - "one_instance_only": "Component ondersteunt slechts \u00e9\u00e9n Z-Wave-instantie", "single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk." }, "error": { diff --git a/homeassistant/components/zwave/translations/no.json b/homeassistant/components/zwave/translations/no.json index f20cf46aeb4..ba875354f7f 100644 --- a/homeassistant/components/zwave/translations/no.json +++ b/homeassistant/components/zwave/translations/no.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Enheten er allerede konfigurert", - "one_instance_only": "Komponenten st\u00f8tter kun en Z-Wave-forekomst", "single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig." }, "error": { diff --git a/homeassistant/components/zwave/translations/pl.json b/homeassistant/components/zwave/translations/pl.json index 6d7675391ff..90ff1a37894 100644 --- a/homeassistant/components/zwave/translations/pl.json +++ b/homeassistant/components/zwave/translations/pl.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane", - "one_instance_only": "Komponent obs\u0142uguje tylko jedn\u0105 instancj\u0119 Z-Wave", "single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja." }, "error": { diff --git a/homeassistant/components/zwave/translations/pt-BR.json b/homeassistant/components/zwave/translations/pt-BR.json index 5bd0ef9d1a8..e46a1bb14cb 100644 --- a/homeassistant/components/zwave/translations/pt-BR.json +++ b/homeassistant/components/zwave/translations/pt-BR.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave j\u00e1 est\u00e1 configurado.", - "one_instance_only": "Componente suporta apenas uma inst\u00e2ncia do Z-Wave" + "already_configured": "Z-Wave j\u00e1 est\u00e1 configurado." }, "error": { "option_error": "A valida\u00e7\u00e3o Z-Wave falhou. O caminho para o USB est\u00e1 correto?" diff --git a/homeassistant/components/zwave/translations/pt.json b/homeassistant/components/zwave/translations/pt.json index b216bfa0984..49be02c195c 100644 --- a/homeassistant/components/zwave/translations/pt.json +++ b/homeassistant/components/zwave/translations/pt.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "O Z-Wave j\u00e1 est\u00e1 configurado", - "one_instance_only": "Componente suporta apenas uma inst\u00e2ncia Z-Wave" + "already_configured": "O Z-Wave j\u00e1 est\u00e1 configurado" }, "error": { "option_error": "A valida\u00e7\u00e3o Z-Wave falhou. O caminho para o dispositivo USB est\u00e1 correto?" diff --git a/homeassistant/components/zwave/translations/ro.json b/homeassistant/components/zwave/translations/ro.json index 1ba9ba80bf9..aa644cde3fa 100644 --- a/homeassistant/components/zwave/translations/ro.json +++ b/homeassistant/components/zwave/translations/ro.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave este deja configurat", - "one_instance_only": "Componenta accept\u0103 numai o instan\u021b\u0103 Z-Wave" + "already_configured": "Z-Wave este deja configurat" }, "error": { "option_error": "Validarea Z-Wave a e\u0219uat. Este corect\u0103 calea c\u0103tre stick-ul USB?" diff --git a/homeassistant/components/zwave/translations/ru.json b/homeassistant/components/zwave/translations/ru.json index c74405767a2..515a47d87a6 100644 --- a/homeassistant/components/zwave/translations/ru.json +++ b/homeassistant/components/zwave/translations/ru.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.", - "one_instance_only": "\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u043e\u0434\u043d\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c Z-Wave.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e." }, "error": { diff --git a/homeassistant/components/zwave/translations/sl.json b/homeassistant/components/zwave/translations/sl.json index ccd3c5dfdd6..f84f4c926ee 100644 --- a/homeassistant/components/zwave/translations/sl.json +++ b/homeassistant/components/zwave/translations/sl.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave je \u017ee konfiguriran", - "one_instance_only": "Komponente podpirajo le eno Z-Wave instanco" + "already_configured": "Z-Wave je \u017ee konfiguriran" }, "error": { "option_error": "Potrjevanje Z-Wave ni uspelo. Ali je pot do USB klju\u010da pravilna?" diff --git a/homeassistant/components/zwave/translations/sv.json b/homeassistant/components/zwave/translations/sv.json index 0f8d7b4c614..5d5e5adc210 100644 --- a/homeassistant/components/zwave/translations/sv.json +++ b/homeassistant/components/zwave/translations/sv.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave \u00e4r redan konfigurerat", - "one_instance_only": "Komponenten st\u00f6der endast en Z-Wave-instans" + "already_configured": "Z-Wave \u00e4r redan konfigurerat" }, "error": { "option_error": "Z-Wave-valideringen misslyckades. \u00c4r s\u00f6kv\u00e4gen till USB-minnet korrekt?" diff --git a/homeassistant/components/zwave/translations/tr.json b/homeassistant/components/zwave/translations/tr.json index 3a007d1db61..3938868d280 100644 --- a/homeassistant/components/zwave/translations/tr.json +++ b/homeassistant/components/zwave/translations/tr.json @@ -16,8 +16,8 @@ "sleeping": "Uyuyor" }, "query_stage": { - "dead": "\u00d6l\u00fc ({query_stage})", - "initializing": "Ba\u015flat\u0131l\u0131yor ( {query_stage} )" + "dead": "\u00d6l\u00fc", + "initializing": "Ba\u015flat\u0131l\u0131yor" } } } \ No newline at end of file diff --git a/homeassistant/components/zwave/translations/zh-Hans.json b/homeassistant/components/zwave/translations/zh-Hans.json index 9236b7de146..c6a220617c1 100644 --- a/homeassistant/components/zwave/translations/zh-Hans.json +++ b/homeassistant/components/zwave/translations/zh-Hans.json @@ -1,8 +1,7 @@ { "config": { "abort": { - "already_configured": "Z-Wave \u5df2\u914d\u7f6e\u5b8c\u6210", - "one_instance_only": "\u7ec4\u4ef6\u53ea\u652f\u6301\u4e00\u4e2a Z-Wave \u5b9e\u4f8b" + "already_configured": "Z-Wave \u5df2\u914d\u7f6e\u5b8c\u6210" }, "error": { "option_error": "Z-Wave \u9a8c\u8bc1\u5931\u8d25\u3002 USB \u68d2\u7684\u8def\u5f84\u662f\u5426\u6b63\u786e\uff1f" diff --git a/homeassistant/components/zwave/translations/zh-Hant.json b/homeassistant/components/zwave/translations/zh-Hant.json index dd309a245c7..fdb263fd5f7 100644 --- a/homeassistant/components/zwave/translations/zh-Hant.json +++ b/homeassistant/components/zwave/translations/zh-Hant.json @@ -2,7 +2,6 @@ "config": { "abort": { "already_configured": "\u8a2d\u5099\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", - "one_instance_only": "\u7d44\u4ef6\u50c5\u652f\u63f4\u4e00\u7d44 Z-Wave \u7269\u4ef6", "single_instance_allowed": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u8a2d\u5099\u3002" }, "error": { diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index a7de2107ecd..af82db0ffbb 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -89,6 +89,8 @@ CONN_CLASS_LOCAL_POLL = "local_poll" CONN_CLASS_ASSUMED = "assumed" CONN_CLASS_UNKNOWN = "unknown" +RELOAD_AFTER_UPDATE_DELAY = 30 + class ConfigError(HomeAssistantError): """Error while configuring an account.""" @@ -1075,6 +1077,9 @@ class OptionsFlowManager(data_entry_flow.FlowManager): """ flow = cast(OptionsFlow, flow) + if result["type"] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: + return result + entry = self.hass.config_entries.async_get_entry(flow.handler) if entry is None: raise UnknownEntry(flow.handler) @@ -1109,8 +1114,6 @@ class SystemOptions: class EntityRegistryDisabledHandler: """Handler to handle when entities related to config entries updating disabled_by.""" - RELOAD_AFTER_UPDATE_DELAY = 30 - def __init__(self, hass: HomeAssistant) -> None: """Initialize the handler.""" self.hass = hass @@ -1167,7 +1170,7 @@ class EntityRegistryDisabledHandler: self._remove_call_later() self._remove_call_later = self.hass.helpers.event.async_call_later( - self.RELOAD_AFTER_UPDATE_DELAY, self._handle_reload + RELOAD_AFTER_UPDATE_DELAY, self._handle_reload ) async def _handle_reload(self, _now: Any) -> None: diff --git a/homeassistant/const.py b/homeassistant/const.py index 6e7056648d5..9bcd046c7e6 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 -MINOR_VERSION = 117 -PATCH_VERSION = "6" +MINOR_VERSION = 118 +PATCH_VERSION = "0" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1) @@ -288,6 +288,9 @@ ATTR_ENTITY_ID = "entity_id" # Contains one string or a list of strings, each being an area id ATTR_AREA_ID = "area_id" +# Contains one string, the device ID +ATTR_DEVICE_ID = "device_id" + # String with a friendly name for the entity ATTR_FRIENDLY_NAME = "friendly_name" @@ -370,18 +373,18 @@ ATTR_TEMPERATURE = "temperature" # #### UNITS OF MEASUREMENT #### # Power units POWER_WATT = "W" -POWER_KILO_WATT = f"k{POWER_WATT}" +POWER_KILO_WATT = "kW" # Voltage units VOLT = "V" # Energy units -ENERGY_WATT_HOUR = f"{POWER_WATT}h" -ENERGY_KILO_WATT_HOUR = f"k{ENERGY_WATT_HOUR}" +ENERGY_WATT_HOUR = "Wh" +ENERGY_KILO_WATT_HOUR = "kWh" # Electrical units ELECTRICAL_CURRENT_AMPERE = "A" -ELECTRICAL_VOLT_AMPERE = f"{VOLT}{ELECTRICAL_CURRENT_AMPERE}" +ELECTRICAL_VOLT_AMPERE = "VA" # Degree units DEGREE = "°" @@ -392,8 +395,8 @@ CURRENCY_DOLLAR = "$" CURRENCY_CENT = "¢" # Temperature units -TEMP_CELSIUS = f"{DEGREE}C" -TEMP_FAHRENHEIT = f"{DEGREE}F" +TEMP_CELSIUS = "°C" +TEMP_FAHRENHEIT = "°F" TEMP_KELVIN = "K" # Time units @@ -420,7 +423,7 @@ LENGTH_MILES: str = "mi" # Frequency units FREQUENCY_HERTZ = "Hz" -FREQUENCY_GIGAHERTZ = f"G{FREQUENCY_HERTZ}" +FREQUENCY_GIGAHERTZ = "GHz" # Pressure units PRESSURE_PA: str = "Pa" @@ -433,14 +436,18 @@ PRESSURE_PSI: str = "psi" # Volume units VOLUME_LITERS: str = "L" VOLUME_MILLILITERS: str = "mL" -VOLUME_CUBIC_METERS = f"{LENGTH_METERS}³" -VOLUME_CUBIC_FEET = f"{LENGTH_FEET}³" +VOLUME_CUBIC_METERS = "m³" +VOLUME_CUBIC_FEET = "ft³" VOLUME_GALLONS: str = "gal" VOLUME_FLUID_OUNCE: str = "fl. oz." +# Volume Flow Rate units +VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR = "m³/h" +VOLUME_FLOW_RATE_CUBIC_FEET_PER_MINUTE = "ft³/m" + # Area units -AREA_SQUARE_METERS = f"{LENGTH_METERS}²" +AREA_SQUARE_METERS = "m²" # Mass units MASS_GRAMS: str = "g" @@ -452,7 +459,7 @@ MASS_OUNCES: str = "oz" MASS_POUNDS: str = "lb" # Conductivity units -CONDUCTIVITY: str = f"µS/{LENGTH_CENTIMETERS}" +CONDUCTIVITY: str = "µS/cm" # Light units LIGHT_LUX: str = "lx" @@ -464,17 +471,24 @@ UV_INDEX: str = "UV index" PERCENTAGE = "%" # Irradiation units -IRRADIATION_WATTS_PER_SQUARE_METER = f"{POWER_WATT}/{AREA_SQUARE_METERS}" +IRRADIATION_WATTS_PER_SQUARE_METER = "W/m²" + +# Precipitation units +PRECIPITATION_MILLIMETERS_PER_HOUR = "mm/h" # Concentration units -CONCENTRATION_MICROGRAMS_PER_CUBIC_METER = f"{MASS_MICROGRAMS}/{VOLUME_CUBIC_METERS}" -CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER = f"{MASS_MILLIGRAMS}/{VOLUME_CUBIC_METERS}" +CONCENTRATION_MICROGRAMS_PER_CUBIC_METER = "µg/m³" +CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER = "mg/m³" +CONCENTRATION_PARTS_PER_CUBIC_METER = "p/m³" CONCENTRATION_PARTS_PER_MILLION = "ppm" CONCENTRATION_PARTS_PER_BILLION = "ppb" # Speed units -SPEED_METERS_PER_SECOND = f"{LENGTH_METERS}/{TIME_SECONDS}" -SPEED_KILOMETERS_PER_HOUR = f"{LENGTH_KILOMETERS}/{TIME_HOURS}" +SPEED_MILLIMETERS_PER_DAY = "mm/d" +SPEED_INCHES_PER_DAY = "in/d" +SPEED_METERS_PER_SECOND = "m/s" +SPEED_INCHES_PER_HOUR = "in/h" +SPEED_KILOMETERS_PER_HOUR = "km/h" SPEED_MILES_PER_HOUR = "mph" # Signal_strength units @@ -503,17 +517,17 @@ DATA_PEBIBYTES = "PiB" DATA_EXBIBYTES = "EiB" DATA_ZEBIBYTES = "ZiB" DATA_YOBIBYTES = "YiB" -DATA_RATE_BITS_PER_SECOND = f"{DATA_BITS}/{TIME_SECONDS}" -DATA_RATE_KILOBITS_PER_SECOND = f"{DATA_KILOBITS}/{TIME_SECONDS}" -DATA_RATE_MEGABITS_PER_SECOND = f"{DATA_MEGABITS}/{TIME_SECONDS}" -DATA_RATE_GIGABITS_PER_SECOND = f"{DATA_GIGABITS}/{TIME_SECONDS}" -DATA_RATE_BYTES_PER_SECOND = f"{DATA_BYTES}/{TIME_SECONDS}" -DATA_RATE_KILOBYTES_PER_SECOND = f"{DATA_KILOBYTES}/{TIME_SECONDS}" -DATA_RATE_MEGABYTES_PER_SECOND = f"{DATA_MEGABYTES}/{TIME_SECONDS}" -DATA_RATE_GIGABYTES_PER_SECOND = f"{DATA_GIGABYTES}/{TIME_SECONDS}" -DATA_RATE_KIBIBYTES_PER_SECOND = f"{DATA_KIBIBYTES}/{TIME_SECONDS}" -DATA_RATE_MEBIBYTES_PER_SECOND = f"{DATA_MEBIBYTES}/{TIME_SECONDS}" -DATA_RATE_GIBIBYTES_PER_SECOND = f"{DATA_GIBIBYTES}/{TIME_SECONDS}" +DATA_RATE_BITS_PER_SECOND = "bit/s" +DATA_RATE_KILOBITS_PER_SECOND = "kbit/s" +DATA_RATE_MEGABITS_PER_SECOND = "Mbit/s" +DATA_RATE_GIGABITS_PER_SECOND = "Gbit/s" +DATA_RATE_BYTES_PER_SECOND = "B/s" +DATA_RATE_KILOBYTES_PER_SECOND = "kB/s" +DATA_RATE_MEGABYTES_PER_SECOND = "MB/s" +DATA_RATE_GIGABYTES_PER_SECOND = "GB/s" +DATA_RATE_KIBIBYTES_PER_SECOND = "KiB/s" +DATA_RATE_MEBIBYTES_PER_SECOND = "MiB/s" +DATA_RATE_GIBIBYTES_PER_SECOND = "GiB/s" # #### SERVICES #### SERVICE_HOMEASSISTANT_STOP = "stop" @@ -633,7 +647,3 @@ CLOUD_NEVER_EXPOSED_ENTITIES = ["group.all_locks"] # The ID of the Home Assistant Cast App CAST_APP_ID_HOMEASSISTANT = "B12CE3CA" - -# The tracker error allow when converting -# loop time to human readable time -MAX_TIME_TRACKING_ERROR = 0.001 diff --git a/homeassistant/core.py b/homeassistant/core.py index ca4a27eef3d..ed8ae854106 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -820,7 +820,7 @@ class EventBus: 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: @@ -1180,12 +1180,14 @@ class StateMachine: if context is None: context = Context() + now = dt_util.utcnow() + state = State( entity_id, new_state, attributes, last_changed, - None, + now, context, old_state is None, ) @@ -1195,6 +1197,7 @@ class StateMachine: {"entity_id": entity_id, "old_state": old_state, "new_state": state}, EventOrigin.local, context, + time_fired=now, ) @@ -1530,7 +1533,7 @@ class Config: self.safe_mode: bool = False # Use legacy template behavior - self.legacy_templates: bool = True + self.legacy_templates: bool = False def distance(self, lat: float, lon: float) -> Optional[float]: """Calculate distance from Home Assistant. diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index b707ec62d3d..c5b67ff16e8 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -14,8 +14,10 @@ RESULT_TYPE_CREATE_ENTRY = "create_entry" RESULT_TYPE_ABORT = "abort" RESULT_TYPE_EXTERNAL_STEP = "external" RESULT_TYPE_EXTERNAL_STEP_DONE = "external_done" +RESULT_TYPE_SHOW_PROGRESS = "progress" +RESULT_TYPE_SHOW_PROGRESS_DONE = "progress_done" -# Event that is fired when a flow is progressed via external source. +# Event that is fired when a flow is progressed via external or progress source. EVENT_DATA_ENTRY_FLOW_PROGRESSED = "data_entry_flow_progressed" @@ -152,8 +154,8 @@ class FlowManager(abc.ABC): result = await self._async_handle_step(flow, cur_step["step_id"], user_input) - if cur_step["type"] == RESULT_TYPE_EXTERNAL_STEP: - if result["type"] not in ( + if cur_step["type"] in (RESULT_TYPE_EXTERNAL_STEP, RESULT_TYPE_SHOW_PROGRESS): + if cur_step["type"] == RESULT_TYPE_EXTERNAL_STEP and result["type"] not in ( RESULT_TYPE_EXTERNAL_STEP, RESULT_TYPE_EXTERNAL_STEP_DONE, ): @@ -161,10 +163,20 @@ class FlowManager(abc.ABC): "External step can only transition to " "external step or external step done." ) + if cur_step["type"] == RESULT_TYPE_SHOW_PROGRESS and result["type"] not in ( + RESULT_TYPE_SHOW_PROGRESS, + RESULT_TYPE_SHOW_PROGRESS_DONE, + ): + raise ValueError( + "Show progress can only transition to show progress or show progress done." + ) # If the result has changed from last result, fire event to update # the frontend. - if cur_step["step_id"] != result.get("step_id"): + if ( + cur_step["step_id"] != result.get("step_id") + or result["type"] == RESULT_TYPE_SHOW_PROGRESS + ): # Tell frontend to reload the flow state. self.hass.bus.async_fire( EVENT_DATA_ENTRY_FLOW_PROGRESSED, @@ -217,6 +229,8 @@ class FlowManager(abc.ABC): RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_ABORT, RESULT_TYPE_EXTERNAL_STEP_DONE, + RESULT_TYPE_SHOW_PROGRESS, + RESULT_TYPE_SHOW_PROGRESS_DONE, ): raise ValueError(f"Handler returned incorrect type: {result['type']}") @@ -224,6 +238,8 @@ class FlowManager(abc.ABC): RESULT_TYPE_FORM, RESULT_TYPE_EXTERNAL_STEP, RESULT_TYPE_EXTERNAL_STEP_DONE, + RESULT_TYPE_SHOW_PROGRESS, + RESULT_TYPE_SHOW_PROGRESS_DONE, ): flow.cur_step = result return result @@ -348,6 +364,34 @@ class FlowHandler: "step_id": next_step_id, } + @callback + def async_show_progress( + self, + *, + step_id: str, + progress_action: str, + description_placeholders: Optional[Dict] = None, + ) -> Dict[str, Any]: + """Show a progress message to the user, without user input allowed.""" + return { + "type": RESULT_TYPE_SHOW_PROGRESS, + "flow_id": self.flow_id, + "handler": self.handler, + "step_id": step_id, + "progress_action": progress_action, + "description_placeholders": description_placeholders, + } + + @callback + def async_show_progress_done(self, *, next_step_id: str) -> Dict[str, Any]: + """Mark the progress done.""" + return { + "type": RESULT_TYPE_SHOW_PROGRESS_DONE, + "flow_id": self.flow_id, + "handler": self.handler, + "step_id": next_step_id, + } + @callback def _create_abort_data( diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py index bd1a1ed4e53..3ac7fbae020 100644 --- a/homeassistant/generated/config_flows.py +++ b/homeassistant/generated/config_flows.py @@ -55,6 +55,7 @@ FLOWS = [ "elkm1", "emulated_roku", "enocean", + "epson", "esphome", "flick_electric", "flo", @@ -132,6 +133,7 @@ FLOWS = [ "nws", "nzbget", "omnilogic", + "onewire", "onvif", "opentherm_gw", "openuv", diff --git a/homeassistant/helpers/aiohttp_client.py b/homeassistant/helpers/aiohttp_client.py index e33492c21a8..fe995222c67 100644 --- a/homeassistant/helpers/aiohttp_client.py +++ b/homeassistant/helpers/aiohttp_client.py @@ -118,13 +118,14 @@ async def async_aiohttp_proxy_stream( hass: HomeAssistantType, request: web.BaseRequest, stream: aiohttp.StreamReader, - content_type: str, + content_type: Optional[str], buffer_size: int = 102400, timeout: int = 10, ) -> web.StreamResponse: """Stream a stream to aiohttp web response.""" response = web.StreamResponse() - response.content_type = content_type + if content_type is not None: + response.content_type = content_type await response.prepare(request) try: diff --git a/homeassistant/helpers/area_registry.py b/homeassistant/helpers/area_registry.py index 347e552a012..b8f7952cd5a 100644 --- a/homeassistant/helpers/area_registry.py +++ b/homeassistant/helpers/area_registry.py @@ -1,5 +1,5 @@ """Provide a way to connect devices to one physical location.""" -from asyncio import Event +from asyncio import Event, gather from collections import OrderedDict from typing import Dict, Iterable, List, MutableMapping, Optional, cast @@ -64,8 +64,12 @@ class AreaRegistry: async def async_delete(self, area_id: str) -> None: """Delete area.""" - device_registry = await self.hass.helpers.device_registry.async_get_registry() + device_registry, entity_registry = await gather( + self.hass.helpers.device_registry.async_get_registry(), + self.hass.helpers.entity_registry.async_get_registry(), + ) device_registry.async_clear_area_id(area_id) + entity_registry.async_clear_area_id(area_id) del self.areas[area_id] diff --git a/homeassistant/helpers/collection.py b/homeassistant/helpers/collection.py index 9e7c6061987..6733b1d3dbd 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_UPDATED = "updated" 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 @@ class ObservableCollection(ABC): """ 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 @@ class YamlCollection(ObservableCollection): 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 @@ class StorageCollection(ObservableCollection): 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 @@ class StorageCollection(ObservableCollection): 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 @@ class StorageCollection(ObservableCollection): 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 @@ class StorageCollection(ObservableCollection): 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 @@ class IDLessCollection(ObservableCollection): 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/homeassistant/helpers/config_entry_oauth2_flow.py b/homeassistant/helpers/config_entry_oauth2_flow.py index ace1365df1b..4d05ad7beab 100644 --- a/homeassistant/helpers/config_entry_oauth2_flow.py +++ b/homeassistant/helpers/config_entry_oauth2_flow.py @@ -33,6 +33,8 @@ DATA_IMPLEMENTATIONS = "oauth2_impl" DATA_PROVIDERS = "oauth2_providers" AUTH_CALLBACK_PATH = "/auth/external/callback" +CLOCK_OUT_OF_SYNC_MAX_SEC = 20 + class AbstractOAuth2Implementation(ABC): """Base class to abstract OAuth2 authentication.""" @@ -231,7 +233,7 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta): 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()}) } ), @@ -435,7 +437,10 @@ class OAuth2Session: @property def valid_token(self) -> bool: """Return if token is still valid.""" - return cast(float, self.token["expires_at"]) > time.time() + return ( + cast(float, self.token["expires_at"]) + > time.time() + CLOCK_OUT_OF_SYNC_MAX_SEC + ) async def async_ensure_token_valid(self) -> None: """Ensure that the current token is valid.""" diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 190cee5e050..5b2ad0da2ac 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -87,7 +87,7 @@ from homeassistant.helpers import ( template as template_helper, ) from homeassistant.helpers.logging import KeywordStyleAdapter -from homeassistant.util import slugify as util_slugify +from homeassistant.util import sanitize_path, slugify as util_slugify import homeassistant.util.dt as dt_util # pylint: disable=invalid-name @@ -113,6 +113,17 @@ port = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)) T = TypeVar("T") +def path(value: Any) -> str: + """Validate it's a safe path.""" + if not isinstance(value, str): + raise vol.Invalid("Expected a string") + + if sanitize_path(value) != value: + raise vol.Invalid("Invalid path") + + return value + + # Adapted from: # https://github.com/alecthomas/voluptuous/issues/115#issuecomment-144464666 def has_at_least_one_key(*keys: str) -> Callable: @@ -123,7 +134,7 @@ def has_at_least_one_key(*keys: str) -> Callable: if not isinstance(obj, dict): raise vol.Invalid("expected dictionary") - for k in obj.keys(): + for k in obj: if k in keys: return obj raise vol.Invalid("must contain at least one of {}.".format(", ".join(keys))) @@ -271,25 +282,36 @@ comp_entity_ids = vol.Any( ) -def entity_domain(domain: str) -> Callable[[Any], str]: +def entity_domain(domain: Union[str, List[str]]) -> Callable[[Any], str]: """Validate that entity belong to domain.""" + ent_domain = entities_domain(domain) def validate(value: Any) -> str: """Test if entity domain is domain.""" - ent_domain = entities_domain(domain) return ent_domain(value)[0] return validate -def entities_domain(domain: str) -> Callable[[Union[str, List]], List[str]]: +def entities_domain( + domain: Union[str, List[str]] +) -> Callable[[Union[str, List]], List[str]]: """Validate that entities belong to domain.""" + if isinstance(domain, str): + + def check_invalid(val: str) -> bool: + return val != domain + + else: + + def check_invalid(val: str) -> bool: + return val not in domain def validate(values: Union[str, List]) -> List[str]: """Test if entity domain is domain.""" values = entity_ids(values) for ent_id in values: - if split_entity_id(ent_id)[0] != domain: + if check_invalid(split_entity_id(ent_id)[0]): raise vol.Invalid( f"Entity ID '{ent_id}' does not belong to domain '{domain}'" ) diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py index fcb9b4ddcb8..388db62ebae 100644 --- a/homeassistant/helpers/device_registry.py +++ b/homeassistant/helpers/device_registry.py @@ -47,12 +47,12 @@ class DeletedDeviceEntry: identifiers: Set[Tuple[str, str]] = attr.ib() id: str = attr.ib() - def to_device_entry(self): + def to_device_entry(self, config_entry_id, connections, identifiers): """Create DeviceEntry from DeletedDeviceEntry.""" return DeviceEntry( - config_entries=self.config_entries, - connections=self.connections, - identifiers=self.identifiers, + config_entries={config_entry_id}, + connections=self.connections & connections, + identifiers=self.identifiers & identifiers, id=self.id, is_new=True, ) @@ -236,7 +236,9 @@ class DeviceRegistry: device = DeviceEntry(is_new=True) else: self._remove_device(deleted_device) - device = deleted_device.to_device_entry() + device = deleted_device.to_device_entry( + config_entry_id, connections, identifiers + ) self._add_device(device) if default_manufacturer is not _UNDEF and device.manufacturer is None: @@ -338,7 +340,7 @@ class DeviceRegistry: config_entries = config_entries - {remove_config_entry_id} - if config_entries is not old.config_entries: + if config_entries != old.config_entries: changes["config_entries"] = config_entries for attr_name, value in ( diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index 693c01b982f..ddd1847f6a8 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -63,6 +63,8 @@ class EntityPlatform: self.config_entry: Optional[config_entries.ConfigEntry] = None self.entities: Dict[str, Entity] = {} # pylint: disable=used-before-assignment self._tasks: List[asyncio.Future] = [] + # Stop tracking tasks after setup is completed + self._setup_complete = False # Method to cancel the state change listener self._async_unsub_polling: Optional[CALLBACK_TYPE] = None # Method to cancel the retry of setup @@ -197,7 +199,7 @@ class EntityPlatform: await asyncio.shield(task) # Block till all entities are done - if self._tasks: + while self._tasks: pending = [task for task in self._tasks if not task.done()] self._tasks.clear() @@ -205,6 +207,7 @@ class EntityPlatform: await asyncio.gather(*pending) hass.config.components.add(full_name) + self._setup_complete = True return True except PlatformNotReady: tries += 1 @@ -258,14 +261,13 @@ class EntityPlatform: self, new_entities: Iterable["Entity"], update_before_add: bool = False ) -> None: """Schedule adding entities for a single platform async.""" - self._tasks.append( - self.hass.async_create_task( - self.async_add_entities( - new_entities, update_before_add=update_before_add - ), - ) + task = self.hass.async_create_task( + self.async_add_entities(new_entities, update_before_add=update_before_add), ) + if not self._setup_complete: + self._tasks.append(task) + def add_entities( self, new_entities: Iterable["Entity"], update_before_add: bool = False ) -> None: @@ -523,6 +525,7 @@ class EntityPlatform: if self._async_unsub_polling is not None: self._async_unsub_polling() self._async_unsub_polling = None + self._setup_complete = False async def async_destroy(self) -> None: """Destroy an entity platform. diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index 14dce1d6d2c..872d87e732f 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -83,6 +83,7 @@ class RegistryEntry: name: Optional[str] = attr.ib(default=None) icon: Optional[str] = attr.ib(default=None) device_id: Optional[str] = attr.ib(default=None) + area_id: Optional[str] = attr.ib(default=None) config_entry_id: Optional[str] = attr.ib(default=None) disabled_by: Optional[str] = attr.ib( default=None, @@ -204,6 +205,7 @@ class EntityRegistry: # Data that we want entry to have config_entry: Optional["ConfigEntry"] = None, device_id: Optional[str] = None, + area_id: Optional[str] = None, capabilities: Optional[Dict[str, Any]] = None, supported_features: Optional[int] = None, device_class: Optional[str] = None, @@ -223,6 +225,7 @@ class EntityRegistry: entity_id, config_entry_id=config_entry_id or _UNDEF, device_id=device_id or _UNDEF, + area_id=area_id or _UNDEF, capabilities=capabilities or _UNDEF, supported_features=supported_features or _UNDEF, device_class=device_class or _UNDEF, @@ -253,6 +256,7 @@ class EntityRegistry: entity_id=entity_id, config_entry_id=config_entry_id, device_id=device_id, + area_id=area_id, unique_id=unique_id, platform=platform, disabled_by=disabled_by, @@ -302,6 +306,7 @@ class EntityRegistry: *, name=_UNDEF, icon=_UNDEF, + area_id=_UNDEF, new_entity_id=_UNDEF, new_unique_id=_UNDEF, disabled_by=_UNDEF, @@ -313,6 +318,7 @@ class EntityRegistry: entity_id, name=name, icon=icon, + area_id=area_id, new_entity_id=new_entity_id, new_unique_id=new_unique_id, disabled_by=disabled_by, @@ -329,6 +335,7 @@ class EntityRegistry: config_entry_id=_UNDEF, new_entity_id=_UNDEF, device_id=_UNDEF, + area_id=_UNDEF, new_unique_id=_UNDEF, disabled_by=_UNDEF, capabilities=_UNDEF, @@ -348,6 +355,7 @@ class EntityRegistry: ("icon", icon), ("config_entry_id", config_entry_id), ("device_id", device_id), + ("area_id", area_id), ("disabled_by", disabled_by), ("capabilities", capabilities), ("supported_features", supported_features), @@ -425,6 +433,7 @@ class EntityRegistry: entity_id=entity["entity_id"], config_entry_id=entity.get("config_entry_id"), device_id=entity.get("device_id"), + area_id=entity.get("area_id"), unique_id=entity["unique_id"], platform=entity["platform"], name=entity.get("name"), @@ -456,6 +465,7 @@ class EntityRegistry: "entity_id": entry.entity_id, "config_entry_id": entry.config_entry_id, "device_id": entry.device_id, + "area_id": entry.area_id, "unique_id": entry.unique_id, "platform": entry.platform, "name": entry.name, @@ -483,6 +493,13 @@ class EntityRegistry: ]: self.async_remove(entity_id) + @callback + def async_clear_area_id(self, area_id: str) -> None: + """Clear area id from registry entries.""" + for entity_id, entry in self.entities.items(): + if area_id == entry.area_id: + self._async_update_entity(entity_id, area_id=None) # type: ignore + def _register_entry(self, entry: RegistryEntry) -> None: self.entities[entry.entity_id] = entry self._add_index(entry) @@ -521,6 +538,14 @@ def async_entries_for_device( ] +@callback +def async_entries_for_area( + registry: EntityRegistry, area_id: str +) -> List[RegistryEntry]: + """Return entries that match an area.""" + return [entry for entry in registry.entities.values() if entry.area_id == area_id] + + @callback def async_entries_for_config_entry( registry: EntityRegistry, config_entry_id: str diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index 2044dbd7856..661e1a11b56 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -28,7 +28,6 @@ from homeassistant.const import ( EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL, - MAX_TIME_TRACKING_ERROR, SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET, ) @@ -1133,16 +1132,36 @@ def async_track_point_in_utc_time( # having to figure out how to call the action every time its called. job = action if isinstance(action, HassJob) else HassJob(action) - cancel_callback = hass.loop.call_at( - hass.loop.time() + point_in_time.timestamp() - time.time(), - hass.async_run_hass_job, - job, - utc_point_in_time, - ) + cancel_callback: Optional[asyncio.TimerHandle] = None + + @callback + def run_action() -> None: + """Call the action.""" + nonlocal cancel_callback + + now = time_tracker_utcnow() + + # Depending on the available clock support (including timer hardware + # and the OS kernel) it can happen that we fire a little bit too early + # as measured by utcnow(). That is bad when callbacks have assumptions + # about the current time. Thus, we rearm the timer for the remaining + # time. + delta = (utc_point_in_time - now).total_seconds() + if delta > 0: + _LOGGER.debug("Called %f seconds too early, rearming", delta) + + cancel_callback = hass.loop.call_later(delta, run_action) + return + + hass.async_run_hass_job(job, utc_point_in_time) + + delta = utc_point_in_time.timestamp() - time.time() + cancel_callback = hass.loop.call_later(delta, run_action) @callback def unsub_point_in_time_listener() -> None: """Cancel the call_later.""" + assert cancel_callback is not None cancel_callback.cancel() return unsub_point_in_time_listener @@ -1294,7 +1313,7 @@ def async_track_sunset( track_sunset = threaded_listener_factory(async_track_sunset) # For targeted patching in tests -pattern_utc_now = dt_util.utcnow +time_tracker_utcnow = dt_util.utcnow @callback @@ -1325,75 +1344,38 @@ def async_track_utc_time_change( matching_minutes = dt_util.parse_time_expression(minute, 0, 59) matching_hours = dt_util.parse_time_expression(hour, 0, 23) - next_time: datetime = dt_util.utcnow() - - def calculate_next(now: datetime) -> None: + def calculate_next(now: datetime) -> datetime: """Calculate and set the next time the trigger should fire.""" - nonlocal next_time - localized_now = dt_util.as_local(now) if local else now - next_time = dt_util.find_next_time_expression_time( + return dt_util.find_next_time_expression_time( localized_now, matching_seconds, matching_minutes, matching_hours ) - # Make sure rolling back the clock doesn't prevent the timer from - # triggering. - cancel_callback: Optional[asyncio.TimerHandle] = None - calculate_next(next_time) + time_listener: Optional[CALLBACK_TYPE] = None @callback - def pattern_time_change_listener() -> None: + def pattern_time_change_listener(_: datetime) -> None: """Listen for matching time_changed events.""" - nonlocal next_time, cancel_callback + nonlocal time_listener - now = pattern_utc_now() + now = time_tracker_utcnow() hass.async_run_hass_job(job, dt_util.as_local(now) if local else now) - calculate_next(now + timedelta(seconds=1)) - - cancel_callback = hass.loop.call_at( - -time.time() - + hass.loop.time() - + next_time.timestamp() - + MAX_TIME_TRACKING_ERROR, + time_listener = async_track_point_in_utc_time( + hass, pattern_time_change_listener, + calculate_next(now + timedelta(seconds=1)), ) - # We always get time.time() first to avoid time.time() - # ticking forward after fetching hass.loop.time() - # and callback being scheduled a few microseconds early. - # - # Since we loose additional time calling `hass.loop.time()` - # we add MAX_TIME_TRACKING_ERROR to ensure - # we always schedule the call within the time window between - # second and the next second. - # - # For example: - # If the clock ticks forward 30 microseconds when fectching - # `hass.loop.time()` and we want the event to fire at exactly - # 03:00:00.000000, the event would actually fire around - # 02:59:59.999970. To ensure we always fire sometime between - # 03:00:00.000000 and 03:00:00.999999 we add - # MAX_TIME_TRACKING_ERROR to make up for the time - # lost fetching the time. This ensures we do not fire the - # event before the next time pattern match which would result - # in the event being fired again since we would otherwise - # potentially fire early. - # - cancel_callback = hass.loop.call_at( - -time.time() - + hass.loop.time() - + next_time.timestamp() - + MAX_TIME_TRACKING_ERROR, - pattern_time_change_listener, + time_listener = async_track_point_in_utc_time( + hass, pattern_time_change_listener, calculate_next(dt_util.utcnow()) ) @callback def unsub_pattern_time_change_listener() -> None: - """Cancel the call_later.""" - nonlocal cancel_callback - assert cancel_callback is not None - cancel_callback.cancel() + """Cancel the time listener.""" + assert time_listener is not None + time_listener() return unsub_pattern_time_change_listener diff --git a/homeassistant/helpers/location.py b/homeassistant/helpers/location.py index 856c5c4d8e3..bca2996dfa2 100644 --- a/homeassistant/helpers/location.py +++ b/homeassistant/helpers/location.py @@ -7,7 +7,6 @@ import voluptuous as vol from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE from homeassistant.core import State -import homeassistant.helpers.config_validation as cv from homeassistant.helpers.typing import HomeAssistantType from homeassistant.util import location as loc_util @@ -91,6 +90,9 @@ def find_coordinates( # Check if state is valid coordinate set try: + # Import here, not at top-level to avoid circular import + import homeassistant.helpers.config_validation as cv # pylint: disable=import-outside-toplevel + cv.gps(entity_state.state.split(",")) except vol.Invalid: _LOGGER.error( diff --git a/homeassistant/helpers/network.py b/homeassistant/helpers/network.py index 9cff5058a00..3990662dc02 100644 --- a/homeassistant/helpers/network.py +++ b/homeassistant/helpers/network.py @@ -24,6 +24,16 @@ class NoURLAvailableError(HomeAssistantError): """An URL to the Home Assistant instance is not available.""" +@bind_hass +def is_internal_request(hass: HomeAssistant) -> bool: + """Test if the current request is internal.""" + try: + _get_internal_url(hass, require_current_request=True) + return True + except NoURLAvailableError: + return False + + @bind_hass def get_url( hass: HomeAssistant, diff --git a/homeassistant/helpers/placeholder.py b/homeassistant/helpers/placeholder.py new file mode 100644 index 00000000000..3da5eaba76f --- /dev/null +++ b/homeassistant/helpers/placeholder.py @@ -0,0 +1,53 @@ +"""Placeholder helpers.""" +from typing import Any, Dict, Set + +from homeassistant.util.yaml import Placeholder + + +class UndefinedSubstitution(Exception): + """Error raised when we find a substitution that is not defined.""" + + def __init__(self, placeholder: str) -> None: + """Initialize the undefined substitution exception.""" + super().__init__(f"No substitution found for placeholder {placeholder}") + self.placeholder = placeholder + + +def extract_placeholders(obj: Any) -> Set[str]: + """Extract placeholders from a structure.""" + found: Set[str] = set() + _extract_placeholders(obj, found) + return found + + +def _extract_placeholders(obj: Any, found: Set[str]) -> None: + """Extract placeholders from a structure.""" + if isinstance(obj, Placeholder): + found.add(obj.name) + return + + if isinstance(obj, list): + for val in obj: + _extract_placeholders(val, found) + return + + if isinstance(obj, dict): + for val in obj.values(): + _extract_placeholders(val, found) + return + + +def substitute(obj: Any, substitutions: Dict[str, Any]) -> Any: + """Substitute values.""" + if isinstance(obj, Placeholder): + if obj.name not in substitutions: + raise UndefinedSubstitution(obj.name) + return substitutions[obj.name] + + if isinstance(obj, list): + return [substitute(val, substitutions) for val in obj] + + if isinstance(obj, dict): + return {key: substitute(val, substitutions) for key, val in obj.items()} + + return obj diff --git a/homeassistant/helpers/ratelimit.py b/homeassistant/helpers/ratelimit.py index d7099e9fe3d..40f10e69d25 100644 --- a/homeassistant/helpers/ratelimit.py +++ b/homeassistant/helpers/ratelimit.py @@ -4,7 +4,6 @@ from datetime import datetime, timedelta import logging from typing import Any, Callable, Dict, Hashable, Optional -from homeassistant.const import MAX_TIME_TRACKING_ERROR from homeassistant.core import HomeAssistant, callback import homeassistant.util.dt as dt_util @@ -95,7 +94,7 @@ class KeyedRateLimit: if key not in self._rate_limit_timers: self._rate_limit_timers[key] = self.hass.loop.call_later( - (next_call_time - now).total_seconds() + MAX_TIME_TRACKING_ERROR, + (next_call_time - now).total_seconds(), action, *args, ) diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index d03fb8c91c6..06d0ae46ae3 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -38,7 +38,13 @@ from homeassistant.helpers import template import homeassistant.helpers.config_validation as cv from homeassistant.helpers.template import Template from homeassistant.helpers.typing import ConfigType, HomeAssistantType, TemplateVarsType -from homeassistant.loader import Integration, async_get_integration, bind_hass +from homeassistant.loader import ( + MAX_LOAD_CONCURRENTLY, + Integration, + async_get_integration, + bind_hass, +) +from homeassistant.util.async_ import gather_with_concurrency from homeassistant.util.yaml import load_yaml from homeassistant.util.yaml.loader import JSON_TYPE @@ -234,6 +240,15 @@ async def async_extract_entity_ids( hass.helpers.device_registry.async_get_registry(), hass.helpers.entity_registry.async_get_registry(), ) + + extracted.update( + entry.entity_id + for area_id in area_ids + for entry in hass.helpers.entity_registry.async_entries_for_area( + ent_reg, area_id + ) + ) + devices = [ device for area_id in area_ids @@ -247,6 +262,7 @@ async def async_extract_entity_ids( for entry in hass.helpers.entity_registry.async_entries_for_device( ent_reg, device.id ) + if not entry.area_id ) return extracted @@ -297,8 +313,9 @@ async def async_get_all_descriptions( loaded = {} if missing: - integrations = await asyncio.gather( - *(async_get_integration(hass, domain) for domain in missing) + integrations = await gather_with_concurrency( + MAX_LOAD_CONCURRENTLY, + *(async_get_integration(hass, domain) for domain in missing), ) contents = await hass.async_add_executor_job( diff --git a/homeassistant/helpers/storage.py b/homeassistant/helpers/storage.py index daf9e2f6a89..a969b2cad9a 100644 --- a/homeassistant/helpers/storage.py +++ b/homeassistant/helpers/storage.py @@ -105,6 +105,13 @@ class Store: return await self._load_task async def _async_load(self): + """Load the data and ensure the task is removed.""" + try: + return await self._async_load_data() + finally: + self._load_task = None + + async def _async_load_data(self): """Load the data.""" # Check if we have a pending write if self._data is not None: @@ -131,16 +138,12 @@ class Store: ) stored = await self._async_migrate_func(data["version"], data["data"]) - self._load_task = None return stored 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 +156,14 @@ class Store: 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 +193,20 @@ class Store: 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 +230,7 @@ class Store: 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 +239,9 @@ class Store: 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/homeassistant/helpers/system_info.py b/homeassistant/helpers/system_info.py index 12fc07dfbd8..9c2c4b181ad 100644 --- a/homeassistant/helpers/system_info.py +++ b/homeassistant/helpers/system_info.py @@ -47,8 +47,8 @@ async def async_get_system_info(hass: HomeAssistantType) -> Dict[str, Any]: info_object["supervisor"] = info.get("supervisor") info_object["host_os"] = host.get("operating_system") - info_object["chassis"] = host.get("chassis") info_object["docker_version"] = info.get("docker") + info_object["chassis"] = host.get("chassis") if info.get("hassos") is not None: info_object["installation_type"] = "Home Assistant OS" diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index d6c89f28e6e..c6efa717fa7 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -11,7 +11,7 @@ import math 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 @@ from homeassistant.const import ( 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 import location as loc_helper 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 @@ -50,12 +48,6 @@ DATE_STR_FORMAT = "%Y-%m-%d %H:%M:%S" _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"} @@ -184,59 +176,6 @@ RESULT_WRAPPERS: Dict[Type, Type] = { 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 +309,6 @@ class Template: 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, @@ -861,6 +791,11 @@ def result_as_boolean(template_result: Optional[str]) -> bool: """ try: + # Import here, not at top-level to avoid circular import + from homeassistant.helpers import ( # pylint: disable=import-outside-toplevel + config_validation as cv, + ) + return cv.boolean(template_result) except vol.Invalid: return False diff --git a/homeassistant/helpers/translation.py b/homeassistant/helpers/translation.py index 53d808a5a85..bd229d79111 100644 --- a/homeassistant/helpers/translation.py +++ b/homeassistant/helpers/translation.py @@ -1,16 +1,18 @@ """Translation string lookup helpers.""" import asyncio +from collections import ChainMap import logging -from typing import Any, Dict, Optional, Set +from typing import Any, Dict, List, Optional, Set -from homeassistant.const import EVENT_COMPONENT_LOADED -from homeassistant.core import Event, callback +from homeassistant.core import callback from homeassistant.loader import ( + MAX_LOAD_CONCURRENTLY, Integration, async_get_config_flows, async_get_integration, bind_hass, ) +from homeassistant.util.async_ import gather_with_concurrency from homeassistant.util.json import load_json from .typing import HomeAssistantType @@ -19,6 +21,7 @@ _LOGGER = logging.getLogger(__name__) TRANSLATION_LOAD_LOCK = "translation_load_lock" TRANSLATION_FLATTEN_CACHE = "translation_flatten_cache" +LOCALE_EN = "en" def recursive_flatten(prefix: Any, data: Dict) -> Dict[str, Any]: @@ -32,11 +35,6 @@ def recursive_flatten(prefix: Any, data: Dict) -> Dict[str, Any]: return output -def flatten(data: Dict) -> Dict[str, Any]: - """Return a flattened representation of dict data.""" - return recursive_flatten("", data) - - @callback def component_translation_path( component: str, language: str, integration: Integration @@ -91,7 +89,7 @@ def load_translations_files( return loaded -def merge_resources( +def _merge_resources( translation_strings: Dict[str, Dict[str, Any]], components: Set[str], category: str, @@ -120,57 +118,31 @@ def merge_resources( if new_value is None: continue - cur_value = domain_resources.get(category) - - # If not exists, set value. - if cur_value is None: - domain_resources[category] = new_value - - # If exists, and a list, append - elif isinstance(cur_value, list): - cur_value.append(new_value) - - # If exists, and a dict make it a list with 2 entries. + if isinstance(new_value, dict): + domain_resources.update(new_value) else: - domain_resources[category] = [cur_value, new_value] + _LOGGER.error( + "An integration providing translations for %s provided invalid data: %s", + domain, + new_value, + ) - # Merge all the lists - for domain, domain_resources in list(resources.items()): - if not isinstance(domain_resources.get(category), list): - continue - - merged = {} - for entry in domain_resources[category]: - if isinstance(entry, dict): - merged.update(entry) - else: - _LOGGER.error( - "An integration providing translations for %s provided invalid data: %s", - domain, - entry, - ) - domain_resources[category] = merged - - return {"component": resources} + return resources -def build_resources( +def _build_resources( translation_strings: Dict[str, Dict[str, Any]], components: Set[str], category: str, ) -> Dict[str, Dict[str, Any]]: """Build the resources response for the given components.""" # Build response - resources: Dict[str, Dict[str, Any]] = {} - for component in components: - new_value = translation_strings[component].get(category) - - if new_value is None: - continue - - resources[component] = {category: new_value} - - return {"component": resources} + return { + component: translation_strings[component][category] + for component in components + if category in translation_strings[component] + and translation_strings[component][category] is not None + } async def async_get_component_strings( @@ -181,8 +153,9 @@ async def async_get_component_strings( integrations = dict( zip( domains, - await asyncio.gather( - *[async_get_integration(hass, domain) for domain in domains] + await gather_with_concurrency( + MAX_LOAD_CONCURRENTLY, + *[async_get_integration(hass, domain) for domain in domains], ), ) ) @@ -226,35 +199,83 @@ async def async_get_component_strings( return translations -class FlatCache: +class _TranslationCache: """Cache for flattened translations.""" def __init__(self, hass: HomeAssistantType) -> None: """Initialize the cache.""" self.hass = hass - self.cache: Dict[str, Dict[str, Dict[str, str]]] = {} + self.loaded: Dict[str, Set[str]] = {} + self.cache: Dict[str, Dict[str, Dict[str, Any]]] = {} + + async def async_fetch( + self, + language: str, + category: str, + components: Set, + ) -> List[Dict[str, Dict[str, Any]]]: + """Load resources into the cache.""" + components_to_load = components - self.loaded.setdefault(language, set()) + + if components_to_load: + await self._async_load(language, components_to_load) + + cached = self.cache.get(language, {}) + + return [cached.get(component, {}).get(category, {}) for component in components] + + async def _async_load(self, language: str, components: Set) -> None: + """Populate the cache for a given set of components.""" + _LOGGER.debug( + "Cache miss for %s: %s", + language, + ", ".join(components), + ) + # Fetch the English resources, as a fallback for missing keys + languages = [LOCALE_EN] if language == LOCALE_EN else [LOCALE_EN, language] + for translation_strings in await asyncio.gather( + *[ + async_get_component_strings(self.hass, lang, components) + for lang in languages + ] + ): + self._build_category_cache(language, components, translation_strings) + + self.loaded[language].update(components) @callback - def async_setup(self) -> None: - """Initialize the cache clear listeners.""" - self.hass.bus.async_listen(EVENT_COMPONENT_LOADED, self._async_component_loaded) - - @callback - def _async_component_loaded(self, event: Event) -> None: - """Clear cache when a new component is loaded.""" - self.cache = {} - - @callback - def async_get_cache(self, language: str, category: str) -> Optional[Dict[str, str]]: - """Get cache.""" - return self.cache.setdefault(language, {}).get(category) - - @callback - def async_set_cache( - self, language: str, category: str, data: Dict[str, str] + def _build_category_cache( + self, + language: str, + components: Set, + translation_strings: Dict[str, Dict[str, Any]], ) -> None: - """Set cache.""" - self.cache.setdefault(language, {})[category] = data + """Extract resources into the cache.""" + cached = self.cache.setdefault(language, {}) + categories: Set[str] = set() + for resource in translation_strings.values(): + categories.update(resource) + + for category in categories: + resource_func = ( + _merge_resources if category == "state" else _build_resources + ) + new_resources = resource_func(translation_strings, components, category) + + for component, resource in new_resources.items(): + category_cache: Dict[str, Any] = cached.setdefault( + component, {} + ).setdefault(category, {}) + + if isinstance(resource, dict): + category_cache.update( + recursive_flatten( + f"component.{component}.{category}.", + resource, + ) + ) + else: + category_cache[f"component.{component}.{category}"] = resource @bind_hass @@ -271,70 +292,22 @@ async def async_get_translations( Otherwise default to loaded intgrations combined with config flow integrations if config_flow is true. """ - lock = hass.data.get(TRANSLATION_LOAD_LOCK) - if lock is None: - lock = hass.data[TRANSLATION_LOAD_LOCK] = asyncio.Lock() + lock = hass.data.setdefault(TRANSLATION_LOAD_LOCK, asyncio.Lock()) if integration is not None: components = {integration} elif config_flow: - # When it's a config flow, we're going to merge the cached loaded component results - # with the integrations that have not been loaded yet. We merge this at the end. - # We can't cache with config flow, as we can't monitor it during runtime. components = (await async_get_config_flows(hass)) - hass.config.components + elif category == "state": + components = set(hass.config.components) else: # Only 'state' supports merging, so remove platforms from selection - if category == "state": - components = set(hass.config.components) - else: - components = { - component - for component in hass.config.components - if "." not in component - } + components = { + component for component in hass.config.components if "." not in component + } async with lock: - if integration is None and not config_flow: - cache = hass.data.get(TRANSLATION_FLATTEN_CACHE) - if cache is None: - cache = hass.data[TRANSLATION_FLATTEN_CACHE] = FlatCache(hass) - cache.async_setup() + cache = hass.data.setdefault(TRANSLATION_FLATTEN_CACHE, _TranslationCache(hass)) + cached = await cache.async_fetch(language, category, components) - cached_translations = cache.async_get_cache(language, category) - - if cached_translations is not None: - return cached_translations - - tasks = [async_get_component_strings(hass, language, components)] - - # Fetch the English resources, as a fallback for missing keys - if language != "en": - tasks.append(async_get_component_strings(hass, "en", components)) - - _LOGGER.debug( - "Cache miss for %s, %s: %s", language, category, ", ".join(components) - ) - - results = await asyncio.gather(*tasks) - - if category == "state": - resource_func = merge_resources - else: - resource_func = build_resources - - resources = flatten(resource_func(results[0], components, category)) - - if language != "en": - base_resources = flatten(resource_func(results[1], components, category)) - resources = {**base_resources, **resources} - - if integration is not None: - pass - elif config_flow: - loaded_comp_resources = await async_get_translations(hass, language, category) - resources.update(loaded_comp_resources) - else: - assert cache is not None - cache.async_set_cache(language, category, resources) - - return resources + return dict(ChainMap(*cached)) diff --git a/homeassistant/helpers/update_coordinator.py b/homeassistant/helpers/update_coordinator.py index 2abe7b8c6b7..895eff01f57 100644 --- a/homeassistant/helpers/update_coordinator.py +++ b/homeassistant/helpers/update_coordinator.py @@ -138,9 +138,9 @@ class DataUpdateCoordinator(Generic[T]): self._unsub_refresh = None self._debounced_refresh.async_cancel() + start = monotonic() try: - start = monotonic() self.data = await self._async_update_data() except (asyncio.TimeoutError, requests.exceptions.Timeout): @@ -192,6 +192,28 @@ class DataUpdateCoordinator(Generic[T]): for update_callback in self._listeners: update_callback() + @callback + def async_set_updated_data(self, data: T) -> None: + """Manually update data, notify listeners and reset refresh interval.""" + if self._unsub_refresh: + self._unsub_refresh() + self._unsub_refresh = None + + self._debounced_refresh.async_cancel() + + self.data = data + self.last_update_success = True + self.logger.debug( + "Manually updated %s data", + self.name, + ) + + if self._listeners: + self._schedule_refresh() + + for update_callback in self._listeners: + update_callback() + class CoordinatorEntity(entity.Entity): """A class for entities using DataUpdateCoordinator.""" diff --git a/homeassistant/loader.py b/homeassistant/loader.py index cb701213fe7..6dabfdf0447 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -50,6 +50,8 @@ CUSTOM_WARNING = ( ) _UNDEF = object() +MAX_LOAD_CONCURRENTLY = 4 + def manifest_from_legacy_module(domain: str, module: ModuleType) -> Dict: """Generate a manifest from a legacy module.""" diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 01c2a30d2de..ad46a8a36f4 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -1,6 +1,6 @@ PyJWT==1.7.1 PyNaCl==1.3.0 -aiohttp==3.6.2 +aiohttp==3.7.1 aiohttp_cors==0.7.0 astral==1.10.1 async_timeout==3.0.1 @@ -12,19 +12,19 @@ cryptography==3.2 defusedxml==0.6.0 distro==1.5.0 emoji==0.5.4 -hass-nabucasa==0.37.1 -home-assistant-frontend==20201021.4 +hass-nabucasa==0.37.2 +home-assistant-frontend==20201111.2 httpx==0.16.1 importlib-metadata==1.6.0;python_version<'3.8' jinja2>=2.11.2 netdisco==2.8.2 -paho-mqtt==1.5.0 +paho-mqtt==1.5.1 pillow==7.2.0 pip>=8.0.3 python-slugify==4.0.1 pytz>=2020.1 pyyaml==5.3.1 -requests==2.24.0 +requests==2.25.0 ruamel.yaml==0.15.100 sqlalchemy==1.3.20 voluptuous-serialize==2.4.0 diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index 8d0235413db..b5745d533fb 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -17,7 +17,7 @@ import homeassistant.util.yaml.loader as yaml_loader # mypy: allow-untyped-calls, allow-untyped-defs -REQUIREMENTS = ("colorlog==4.2.1",) +REQUIREMENTS = ("colorlog==4.5.0",) _LOGGER = logging.getLogger(__name__) # pylint: disable=protected-access diff --git a/homeassistant/strings.json b/homeassistant/strings.json index 56577c04c2a..f36c62b91ce 100644 --- a/homeassistant/strings.json +++ b/homeassistant/strings.json @@ -40,9 +40,12 @@ "api_token": "API Token", "ssl": "Uses an SSL certificate", "verify_ssl": "Verify SSL certificate", + "elevation": "Elevation", "longitude": "Longitude", "latitude": "Latitude", - "pin": "PIN Code" + "location": "Location", + "pin": "PIN Code", + "mode": "Mode" }, "create_entry": { "authenticated": "Successfully authenticated" @@ -63,6 +66,7 @@ "already_configured_service": "Service is already configured", "already_in_progress": "Configuration flow is already in progress", "no_devices_found": "No devices found on the network", + "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages.", "oauth2_missing_configuration": "The component is not configured. Please follow the documentation.", "oauth2_authorize_url_timeout": "Timeout generating authorize URL.", "oauth2_no_url_available": "No URL available. For information about this error, [check the help section]({docs_url})", diff --git a/homeassistant/util/async_.py b/homeassistant/util/async_.py index 0b48e2159c0..ded44473038 100644 --- a/homeassistant/util/async_.py +++ b/homeassistant/util/async_.py @@ -1,12 +1,12 @@ -"""Asyncio backports for Python 3.6 compatibility.""" -from asyncio import coroutines, ensure_future, get_running_loop +"""Asyncio utilities.""" +from asyncio import Semaphore, coroutines, ensure_future, gather, get_running_loop from asyncio.events import AbstractEventLoop import concurrent.futures import functools import logging import threading from traceback import extract_stack -from typing import Any, Callable, Coroutine, TypeVar +from typing import Any, Awaitable, Callable, Coroutine, TypeVar _LOGGER = logging.getLogger(__name__) @@ -121,3 +121,21 @@ def protect_loop(func: Callable) -> Callable: return func(*args, **kwargs) return protected_loop_func + + +async def gather_with_concurrency( + limit: int, *tasks: Any, return_exceptions: bool = False +) -> Any: + """Wrap asyncio.gather to limit the number of concurrent tasks. + + From: https://stackoverflow.com/a/61478547/9127614 + """ + semaphore = Semaphore(limit) + + async def sem_task(task: Awaitable[Any]) -> Any: + async with semaphore: + return await task + + return await gather( + *(sem_task(task) for task in tasks), return_exceptions=return_exceptions + ) diff --git a/homeassistant/util/distance.py b/homeassistant/util/distance.py index 3ae809b2a9f..3bb3c258516 100644 --- a/homeassistant/util/distance.py +++ b/homeassistant/util/distance.py @@ -3,14 +3,27 @@ from numbers import Number from homeassistant.const import ( LENGTH, + LENGTH_CENTIMETERS, LENGTH_FEET, + LENGTH_INCHES, LENGTH_KILOMETERS, LENGTH_METERS, LENGTH_MILES, + LENGTH_MILLIMETERS, + LENGTH_YARD, UNIT_NOT_RECOGNIZED_TEMPLATE, ) -VALID_UNITS = [LENGTH_KILOMETERS, LENGTH_MILES, LENGTH_FEET, LENGTH_METERS] +VALID_UNITS = [ + LENGTH_KILOMETERS, + LENGTH_MILES, + LENGTH_FEET, + LENGTH_METERS, + LENGTH_CENTIMETERS, + LENGTH_MILLIMETERS, + LENGTH_INCHES, + LENGTH_YARD, +] def convert(value: float, unit_1: str, unit_2: str) -> float: @@ -30,19 +43,35 @@ def convert(value: float, unit_1: str, unit_2: str) -> float: if unit_1 == LENGTH_MILES: meters = __miles_to_meters(value) + elif unit_1 == LENGTH_YARD: + meters = __yards_to_meters(value) elif unit_1 == LENGTH_FEET: meters = __feet_to_meters(value) + elif unit_1 == LENGTH_INCHES: + meters = __inches_to_meters(value) elif unit_1 == LENGTH_KILOMETERS: meters = __kilometers_to_meters(value) + elif unit_1 == LENGTH_CENTIMETERS: + meters = __centimeters_to_meters(value) + elif unit_1 == LENGTH_MILLIMETERS: + meters = __millimeters_to_meters(value) result = meters if unit_2 == LENGTH_MILES: result = __meters_to_miles(meters) + elif unit_2 == LENGTH_YARD: + result = __meters_to_yards(meters) elif unit_2 == LENGTH_FEET: result = __meters_to_feet(meters) + elif unit_2 == LENGTH_INCHES: + result = __meters_to_inches(meters) elif unit_2 == LENGTH_KILOMETERS: result = __meters_to_kilometers(meters) + elif unit_2 == LENGTH_CENTIMETERS: + result = __meters_to_centimeters(meters) + elif unit_2 == LENGTH_MILLIMETERS: + result = __meters_to_millimeters(meters) return result @@ -52,26 +81,66 @@ def __miles_to_meters(miles: float) -> float: return miles * 1609.344 +def __yards_to_meters(yards: float) -> float: + """Convert yards to meters.""" + return yards * 0.9144 + + def __feet_to_meters(feet: float) -> float: """Convert feet to meters.""" return feet * 0.3048 +def __inches_to_meters(inches: float) -> float: + """Convert inches to meters.""" + return inches * 0.0254 + + def __kilometers_to_meters(kilometers: float) -> float: """Convert kilometers to meters.""" return kilometers * 1000 +def __centimeters_to_meters(centimeters: float) -> float: + """Convert centimeters to meters.""" + return centimeters * 0.01 + + +def __millimeters_to_meters(millimeters: float) -> float: + """Convert millimeters to meters.""" + return millimeters * 0.001 + + def __meters_to_miles(meters: float) -> float: """Convert meters to miles.""" return meters * 0.000621371 +def __meters_to_yards(meters: float) -> float: + """Convert meters to yards.""" + return meters * 1.09361 + + def __meters_to_feet(meters: float) -> float: """Convert meters to feet.""" return meters * 3.28084 +def __meters_to_inches(meters: float) -> float: + """Convert meters to inches.""" + return meters * 39.3701 + + def __meters_to_kilometers(meters: float) -> float: """Convert meters to kilometers.""" return meters * 0.001 + + +def __meters_to_centimeters(meters: float) -> float: + """Convert meters to centimeters.""" + return meters * 100 + + +def __meters_to_millimeters(meters: float) -> float: + """Convert meters to millimeters.""" + return meters * 1000 diff --git a/homeassistant/util/yaml/__init__.py b/homeassistant/util/yaml/__init__.py index 106bdbf8ef5..bb6eb122de5 100644 --- a/homeassistant/util/yaml/__init__.py +++ b/homeassistant/util/yaml/__init__.py @@ -1,14 +1,17 @@ """YAML utility functions.""" from .const import _SECRET_NAMESPACE, SECRET_YAML from .dumper import dump, save_yaml -from .loader import clear_secret_cache, load_yaml, secret_yaml +from .loader import clear_secret_cache, load_yaml, parse_yaml, secret_yaml +from .objects import Placeholder __all__ = [ "SECRET_YAML", "_SECRET_NAMESPACE", + "Placeholder", "dump", "save_yaml", "clear_secret_cache", "load_yaml", "secret_yaml", + "parse_yaml", ] diff --git a/homeassistant/util/yaml/dumper.py b/homeassistant/util/yaml/dumper.py index 3d11e943a91..6834323ed72 100644 --- a/homeassistant/util/yaml/dumper.py +++ b/homeassistant/util/yaml/dumper.py @@ -3,7 +3,7 @@ from collections import OrderedDict import yaml -from .objects import NodeListClass +from .objects import NodeListClass, Placeholder # mypy: allow-untyped-calls, no-warn-return-any @@ -60,3 +60,8 @@ yaml.SafeDumper.add_representer( NodeListClass, lambda dumper, value: dumper.represent_sequence("tag:yaml.org,2002:seq", value), ) + +yaml.SafeDumper.add_representer( + Placeholder, + lambda dumper, value: dumper.represent_scalar("!placeholder", value.name), +) diff --git a/homeassistant/util/yaml/loader.py b/homeassistant/util/yaml/loader.py index 7e954f21e1a..c9e191db5de 100644 --- a/homeassistant/util/yaml/loader.py +++ b/homeassistant/util/yaml/loader.py @@ -4,14 +4,14 @@ import fnmatch import logging import os import sys -from typing import Dict, Iterator, List, TypeVar, Union, overload +from typing import Dict, Iterator, List, TextIO, TypeVar, Union, overload import yaml from homeassistant.exceptions import HomeAssistantError from .const import _SECRET_NAMESPACE, SECRET_YAML -from .objects import NodeListClass, NodeStrClass +from .objects import NodeListClass, NodeStrClass, Placeholder try: import keyring @@ -56,17 +56,23 @@ def load_yaml(fname: str) -> JSON_TYPE: """Load a YAML file.""" try: with open(fname, encoding="utf-8") as conf_file: - # If configuration file is empty YAML returns None - # We convert that to an empty dict - return yaml.load(conf_file, Loader=SafeLineLoader) or OrderedDict() - except yaml.YAMLError as exc: - _LOGGER.error(str(exc)) - raise HomeAssistantError(exc) from exc + return parse_yaml(conf_file) except UnicodeDecodeError as exc: _LOGGER.error("Unable to read file %s: %s", fname, exc) raise HomeAssistantError(exc) from exc +def parse_yaml(content: Union[str, TextIO]) -> JSON_TYPE: + """Load a YAML file.""" + try: + # If configuration file is empty YAML returns None + # We convert that to an empty dict + return yaml.load(content, Loader=SafeLineLoader) or OrderedDict() + except yaml.YAMLError as exc: + _LOGGER.error(str(exc)) + raise HomeAssistantError(exc) from exc + + @overload def _add_reference( obj: Union[list, NodeListClass], loader: yaml.SafeLoader, node: yaml.nodes.Node @@ -325,3 +331,4 @@ yaml.SafeLoader.add_constructor("!include_dir_named", _include_dir_named_yaml) yaml.SafeLoader.add_constructor( "!include_dir_merge_named", _include_dir_merge_named_yaml ) +yaml.SafeLoader.add_constructor("!placeholder", Placeholder.from_node) diff --git a/homeassistant/util/yaml/objects.py b/homeassistant/util/yaml/objects.py index cae957740e4..c3f4c0ff140 100644 --- a/homeassistant/util/yaml/objects.py +++ b/homeassistant/util/yaml/objects.py @@ -1,4 +1,7 @@ """Custom yaml object types.""" +from dataclasses import dataclass + +import yaml class NodeListClass(list): @@ -7,3 +10,15 @@ class NodeListClass(list): class NodeStrClass(str): """Wrapper class to be able to add attributes on a string.""" + + +@dataclass(frozen=True) +class Placeholder: + """A placeholder that should be substituted.""" + + name: str + + @classmethod + def from_node(cls, loader: yaml.Loader, node: yaml.nodes.Node) -> "Placeholder": + """Create a new placeholder from a node.""" + return cls(node.value) diff --git a/machine/odroid-c4 b/machine/odroid-c4 new file mode 100644 index 00000000000..9bfbb931ed0 --- /dev/null +++ b/machine/odroid-c4 @@ -0,0 +1,34 @@ +ARG BUILD_VERSION +FROM homeassistant/aarch64-homeassistant:$BUILD_VERSION + +RUN apk --no-cache add \ + usbutils + +## +# Build libcec for HDMI-CEC +ARG LIBCEC_VERSION=6.0.2 +RUN apk add --no-cache \ + eudev-libs \ + p8-platform \ + && apk add --no-cache --virtual .build-dependencies \ + build-base \ + cmake \ + eudev-dev \ + swig \ + p8-platform-dev \ + linux-headers \ + && git clone --depth 1 -b libcec-${LIBCEC_VERSION} https://github.com/Pulse-Eight/libcec /usr/src/libcec \ + && cd /usr/src/libcec \ + && mkdir -p /usr/src/libcec/build \ + && cd /usr/src/libcec/build \ + && cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr/local \ + -DPYTHON_LIBRARY="/usr/local/lib/libpython3.8.so" \ + -DPYTHON_INCLUDE_DIR="/usr/local/include/python3.8" \ + -DHAVE_LINUX_API=1 \ + -DHAVE_AOCEC_API=1 \ + .. \ + && make -j$(nproc) \ + && make install \ + && echo "cec" > "/usr/local/lib/python3.8/site-packages/cec.pth" \ + && apk del .build-dependencies \ + && rm -rf /usr/src/libcec* diff --git a/requirements.txt b/requirements.txt index 498b948e478..3a376b6e7cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -c homeassistant/package_constraints.txt # Home Assistant Core -aiohttp==3.6.2 +aiohttp==3.7.1 astral==1.10.1 async_timeout==3.0.1 attrs==19.3.0 @@ -17,7 +17,7 @@ pip>=8.0.3 python-slugify==4.0.1 pytz>=2020.1 pyyaml==5.3.1 -requests==2.24.0 +requests==2.25.0 ruamel.yaml==0.15.100 voluptuous==0.12.0 voluptuous-serialize==2.4.0 diff --git a/requirements_all.txt b/requirements_all.txt index bbb60c6e189..aaa443263bf 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -70,7 +70,7 @@ PyTurboJPEG==1.4.0 PyViCare==0.2.0 # homeassistant.components.xiaomi_aqara -PyXiaomiGateway==0.13.3 +PyXiaomiGateway==0.13.4 # homeassistant.components.bmp280 # homeassistant.components.mcp23017 @@ -138,13 +138,13 @@ aio_geojson_geonetnz_volcano==0.5 aio_geojson_nsw_rfs_incidents==0.3 # homeassistant.components.gdacs -aio_georss_gdacs==0.3 +aio_georss_gdacs==0.4 # homeassistant.components.ambient_station aioambient==1.2.1 # homeassistant.components.asuswrt -aioasuswrt==1.2.8 +aioasuswrt==1.3.0 # homeassistant.components.azure_devops aioazuredevops==1.3.5 @@ -172,7 +172,7 @@ aiofreepybox==0.0.8 aioftp==0.12.0 # homeassistant.components.guardian -aioguardian==1.0.1 +aioguardian==1.0.4 # homeassistant.components.harmony aioharmony==0.2.6 @@ -220,14 +220,17 @@ aiopvpc==2.0.2 # homeassistant.components.webostv aiopylgtv==0.3.3 +# homeassistant.components.recollect_waste +aiorecollect==0.2.1 + # homeassistant.components.shelly -aioshelly==0.4.0 +aioshelly==0.5.1 # homeassistant.components.switcher_kis aioswitcher==1.2.1 # homeassistant.components.unifi -aiounifi==23 +aiounifi==25 # homeassistant.components.yandex_transport aioymaps==1.1.0 @@ -248,7 +251,7 @@ ambiclimate==0.2.1 amcrest==1.7.0 # homeassistant.components.androidtv -androidtv[async]==0.0.52 +androidtv[async]==0.0.54 # homeassistant.components.anel_pwrctrl anel_pwrctrl-homeassistant==0.0.1.dev2 @@ -300,7 +303,7 @@ aurorapy==0.2.6 av==8.0.2 # homeassistant.components.avea -# avea==1.4 +# avea==1.5 # homeassistant.components.avion # avion==0.10 @@ -342,7 +345,7 @@ beautifulsoup4==4.9.1 bellows==0.20.3 # homeassistant.components.bmw_connected_drive -bimmer_connected==0.7.12 +bimmer_connected==0.7.13 # homeassistant.components.bizkaibus bizkaibus==0.1.1 @@ -377,10 +380,10 @@ bond-api==0.1.8 boto3==1.9.252 # homeassistant.components.braviatv -bravia-tv==1.0.6 +bravia-tv==1.0.8 # homeassistant.components.broadlink -broadlink==0.15.0 +broadlink==0.16.0 # homeassistant.components.brother brother==0.1.18 @@ -392,7 +395,7 @@ brottsplatskartan==0.0.1 brunt==0.1.3 # homeassistant.components.bsblan -bsblan==0.3.7 +bsblan==0.4.0 # homeassistant.components.bluetooth_tracker bt_proximity==0.2 @@ -431,7 +434,10 @@ coinbase==2.1.0 coinmarketcap==5.0.3 # homeassistant.scripts.check_config -colorlog==4.2.1 +colorlog==4.5.0 + +# homeassistant.components.color_extractor +colorthief==0.2.1 # homeassistant.components.concord232 concord232==0.15 @@ -460,7 +466,7 @@ datadog==0.15.0 datapoint==0.9.5 # homeassistant.components.debugpy -debugpy==1.0.0rc2 +debugpy==1.1.0 # homeassistant.components.decora # decora==0.6 @@ -481,7 +487,7 @@ deluge-client==1.7.1 denonavr==0.9.5 # homeassistant.components.devolo_home_control -devolo-home-control-api==0.15.1 +devolo-home-control-api==0.16.0 # homeassistant.components.directv directv==0.3.0 @@ -535,7 +541,7 @@ elgato==0.2.0 eliqonline==1.2.2 # homeassistant.components.elkm1 -elkm1-lib==0.8.4 +elkm1-lib==0.8.8 # homeassistant.components.mobile_app emoji==0.5.4 @@ -550,19 +556,19 @@ enocean==0.50 enturclient==0.2.1 # homeassistant.components.environment_canada -# env_canada==0.2.0 +env_canada==0.2.4 # homeassistant.components.envirophat # envirophat==0.0.6 # homeassistant.components.enphase_envoy -envoy_reader==0.16.1 +envoy_reader==0.16.2 # homeassistant.components.season ephem==3.7.7.0 # homeassistant.components.epson -epson-projector==0.1.3 +epson-projector==0.2.3 # homeassistant.components.epsonworkforce epsonprinter==0.0.9 @@ -616,13 +622,13 @@ freesms==0.1.2 # homeassistant.components.fritz # homeassistant.components.fritzbox_callmonitor # homeassistant.components.fritzbox_netmonitor -fritzconnection==1.2.0 +fritzconnection==1.3.4 # homeassistant.components.google_translate gTTS-token==1.1.4 # homeassistant.components.garmin_connect -garminconnect==0.1.13 +garminconnect==0.1.16 # homeassistant.components.geizhals geizhals==0.0.9 @@ -675,13 +681,13 @@ gogogate2-api==2.0.3 google-api-python-client==1.6.4 # homeassistant.components.google_pubsub -google-cloud-pubsub==0.39.1 +google-cloud-pubsub==2.1.0 # homeassistant.components.google_cloud google-cloud-texttospeech==0.4.0 # homeassistant.components.nest -google-nest-sdm==0.1.6 +google-nest-sdm==0.1.14 # homeassistant.components.google_travel_time googlemaps==2.5.1 @@ -696,7 +702,7 @@ gpiozero==1.5.1 gps3==0.33.3 # homeassistant.components.gree -greeclimate==0.9.5 +greeclimate==0.10.3 # homeassistant.components.greeneye_monitor greeneye_monitor==2.1 @@ -713,6 +719,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 @@ -726,13 +735,13 @@ habitipy==0.2.0 hangups==0.4.11 # homeassistant.components.cloud -hass-nabucasa==0.37.1 +hass-nabucasa==0.37.2 # homeassistant.components.splunk hass_splunk==0.1.1 # homeassistant.components.tasmota -hatasmota==0.0.25.1 +hatasmota==0.0.31 # homeassistant.components.jewish_calendar hdate==0.9.12 @@ -759,7 +768,7 @@ hole==0.5.1 holidays==0.10.3 # homeassistant.components.frontend -home-assistant-frontend==20201021.4 +home-assistant-frontend==20201111.2 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 @@ -768,7 +777,7 @@ homeassistant-pyozw==0.1.10 homeconnect==0.6.3 # homeassistant.components.homematicip_cloud -homematicip==0.11.0 +homematicip==0.12.1 # homeassistant.components.horizon horimote==0.4.1 @@ -1018,6 +1027,9 @@ oasatelematics==0.3 # homeassistant.components.google oauth2client==4.0.0 +# homeassistant.components.profiler +objgraph==3.4.1 + # homeassistant.components.oem oemthermostat==1.1.1 @@ -1064,8 +1076,6 @@ orvibo==1.1.1 ovoenergy==1.1.7 # homeassistant.components.mqtt -paho-mqtt==1.5.0 - # homeassistant.components.shiftr paho-mqtt==1.5.1 @@ -1121,7 +1131,7 @@ pillow==7.2.0 pizzapi==0.0.3 # homeassistant.components.plex -plexapi==4.1.1 +plexapi==4.2.0 # homeassistant.components.plex plexauth==0.0.6 @@ -1231,7 +1241,7 @@ pyRFXtrx==0.26 # pySwitchmate==0.4.6 # homeassistant.components.tibber -pyTibber==0.15.7 +pyTibber==0.16.0 # homeassistant.components.dlink pyW215==0.7.0 @@ -1312,7 +1322,7 @@ pycoolmasternet-async==0.1.2 pycountry==19.8.18 # homeassistant.components.microsoft -pycsspeechtts==1.0.3 +pycsspeechtts==1.0.4 # homeassistant.components.cups # pycups==1.9.73 @@ -1351,7 +1361,7 @@ pyeconet==0.0.11 pyedimax==0.2.1 # homeassistant.components.eight_sleep -pyeight==0.1.4 +pyeight==0.1.5 # homeassistant.components.emby pyemby==1.7 @@ -1384,7 +1394,7 @@ pyflunearyou==1.0.7 pyfnip==0.2 # homeassistant.components.forked_daapd -pyforked-daapd==0.1.10 +pyforked-daapd==0.1.11 # homeassistant.components.fritzbox pyfritzhome==0.4.2 @@ -1423,9 +1433,6 @@ pyhomematic==0.1.70 # homeassistant.components.homeworks pyhomeworks==0.0.6 -# homeassistant.components.ialarm -pyialarm==0.3 - # homeassistant.components.icloud pyicloud==0.9.7 @@ -1466,13 +1473,13 @@ 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 # homeassistant.components.launch_library -pylaunches==0.2.0 +pylaunches==1.0.0 # homeassistant.components.lg_netcast pylgnetcast-homeassistant==0.2.0.dev0 @@ -1487,7 +1494,7 @@ pylitejet==0.1 pyloopenergy==0.2.1 # homeassistant.components.lutron_caseta -pylutron-caseta==0.7.1 +pylutron-caseta==0.7.2 # homeassistant.components.lutron pylutron==0.2.5 @@ -1505,7 +1512,7 @@ pymediaroom==0.6.4.1 pymelcloud==2.5.2 # homeassistant.components.somfy -pymfy==0.9.0 +pymfy==0.9.1 # homeassistant.components.xiaomi_tv pymitv==1.4.3 @@ -1585,7 +1592,7 @@ pyotgw==0.6b1 pyotp==2.3.0 # homeassistant.components.openweathermap -pyowm==2.10.0 +pyowm==3.1.0 # homeassistant.components.onewire pyownet==0.10.0.post1 @@ -1594,7 +1601,7 @@ pyownet==0.10.0.post1 pypca==0.0.7 # homeassistant.components.lcn -pypck==0.7.2 +pypck==0.7.4 # homeassistant.components.pjlink pypjlink2==1.2.1 @@ -1688,13 +1695,13 @@ pysnmp==4.4.12 pysoma==0.0.10 # homeassistant.components.sonos -pysonos==0.0.35 +pysonos==0.0.36 # homeassistant.components.spc pyspcwebgw==0.4.0 # homeassistant.components.squeezebox -pysqueezebox==0.5.4 +pysqueezebox==0.5.5 # homeassistant.components.stiebel_eltron pystiebeleltron==0.0.1.dev2 @@ -1781,7 +1788,7 @@ python-nest==4.1.0 python-nmap==0.6.1 # homeassistant.components.ozw -python-openzwave-mqtt==1.2.2 +python-openzwave-mqtt==1.3.2 # homeassistant.components.qbittorrent python-qbittorrent==0.4.1 @@ -1811,7 +1818,7 @@ python-telnet-vlc==1.0.4 python-twitch-client==0.6.0 # homeassistant.components.velbus -python-velbus==2.0.46 +python-velbus==2.1.1 # homeassistant.components.vlc python-vlc==1.1.2 @@ -1844,7 +1851,7 @@ pytraccar==0.9.0 pytrackr==0.0.5 # homeassistant.components.tradfri -pytradfri[async]==7.0.2 +pytradfri[async]==7.0.4 # homeassistant.components.trafikverket_train # homeassistant.components.trafikverket_weatherstation @@ -1860,7 +1867,7 @@ pyuptimerobot==0.0.5 # pyuserinput==0.1.11 # homeassistant.components.vera -pyvera==0.3.10 +pyvera==0.3.11 # homeassistant.components.versasense pyversasense==0.0.6 @@ -1872,7 +1879,7 @@ pyvesync==1.2.0 pyvizio==0.1.56 # homeassistant.components.velux -pyvlx==0.2.17 +pyvlx==0.2.18 # homeassistant.components.volumio pyvolumio==0.1.3 @@ -1881,7 +1888,7 @@ pyvolumio==0.1.3 pywebpush==1.9.2 # homeassistant.components.wemo -pywemo==0.5.0 +pywemo==0.5.2 # homeassistant.components.wilight pywilight==0.0.65 @@ -1916,11 +1923,8 @@ raincloudy==0.0.7 # homeassistant.components.raspyrfm raspyrfm-client==1.2.8 -# homeassistant.components.recollect_waste -recollect-waste==1.0.1 - # homeassistant.components.rainmachine -regenmaschine==2.1.0 +regenmaschine==3.0.0 # homeassistant.components.python_script restrictedpython==5.0 @@ -1950,7 +1954,7 @@ rokuecp==0.6.0 roombapy==1.6.1 # homeassistant.components.roon -roonapi==0.0.21 +roonapi==0.0.25 # homeassistant.components.rova rova==0.1.0 @@ -1999,7 +2003,7 @@ sense-hat==2.2.0 sense_energy==0.8.1 # homeassistant.components.sentry -sentry-sdk==0.19.1 +sentry-sdk==0.19.2 # homeassistant.components.sharkiq sharkiqpy==0.1.8 @@ -2008,7 +2012,7 @@ sharkiqpy==0.1.8 sharp_aquos_rc==0.3.2 # homeassistant.components.shodan -shodan==1.23.0 +shodan==1.24.0 # homeassistant.components.sighthound simplehound==0.3 @@ -2020,7 +2024,7 @@ simplepush==1.1.4 simplisafe-python==9.6.0 # homeassistant.components.sisyphus -sisyphus-control==2.2.1 +sisyphus-control==3.0 # homeassistant.components.skybell skybellpy==0.6.1 @@ -2206,7 +2210,7 @@ twentemilieu==0.3.0 twilio==6.32.0 # homeassistant.components.rainforest_eagle -uEagle==0.0.1 +uEagle==0.0.2 # homeassistant.components.unifiled unifiled==0.11 @@ -2297,7 +2301,7 @@ xboxapi==2.0.1 xfinity-gateway==0.0.4 # homeassistant.components.knx -xknx==0.15.0 +xknx==0.15.3 # homeassistant.components.bluesound # homeassistant.components.rest @@ -2319,7 +2323,7 @@ yeelight==0.5.4 yeelightsunflower==0.0.10 # homeassistant.components.media_extractor -youtube_dl==2020.09.20 +youtube_dl==2020.11.01.1 # homeassistant.components.onvif zeep[async]==4.0.0 @@ -2331,7 +2335,7 @@ zengge==0.2 zeroconf==0.28.6 # homeassistant.components.zha -zha-quirks==0.0.45 +zha-quirks==0.0.46 # homeassistant.components.zhong_hong zhong_hong_hvac==1.0.9 @@ -2349,7 +2353,7 @@ zigpy-deconz==0.11.0 zigpy-xbee==0.13.0 # homeassistant.components.zha -zigpy-zigate==0.6.2 +zigpy-zigate==0.7.2 # homeassistant.components.zha zigpy-znp==0.2.2 diff --git a/requirements_test.txt b/requirements_test.txt index 744765bec77..77c68763894 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -10,7 +10,7 @@ coverage==5.3 jsonpickle==1.4.1 mock-open==1.4.0 mypy==0.790 -pre-commit==2.7.1 +pre-commit==2.8.2 pylint==2.6.0 astroid==2.4.2 pipdeptree==1.0.0 @@ -21,7 +21,7 @@ pytest-test-groups==1.0.3 pytest-sugar==0.9.4 pytest-timeout==1.4.2 pytest-xdist==2.1.0 -pytest==6.0.2 +pytest==6.1.2 requests_mock==1.8.0 responses==0.12.0 respx==0.14.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f71678da698..4841444b7a0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -30,7 +30,7 @@ PyTransportNSW==0.1.1 PyTurboJPEG==1.4.0 # homeassistant.components.xiaomi_aqara -PyXiaomiGateway==0.13.3 +PyXiaomiGateway==0.13.4 # homeassistant.components.remember_the_milk RtmAPI==0.7.2 @@ -72,13 +72,13 @@ aio_geojson_geonetnz_volcano==0.5 aio_geojson_nsw_rfs_incidents==0.3 # homeassistant.components.gdacs -aio_georss_gdacs==0.3 +aio_georss_gdacs==0.4 # homeassistant.components.ambient_station aioambient==1.2.1 # homeassistant.components.asuswrt -aioasuswrt==1.2.8 +aioasuswrt==1.3.0 # homeassistant.components.azure_devops aioazuredevops==1.3.5 @@ -103,7 +103,7 @@ aioflo==0.4.1 aiofreepybox==0.0.8 # homeassistant.components.guardian -aioguardian==1.0.1 +aioguardian==1.0.4 # homeassistant.components.harmony aioharmony==0.2.6 @@ -137,13 +137,13 @@ aiopvpc==2.0.2 aiopylgtv==0.3.3 # homeassistant.components.shelly -aioshelly==0.4.0 +aioshelly==0.5.1 # homeassistant.components.switcher_kis aioswitcher==1.2.1 # homeassistant.components.unifi -aiounifi==23 +aiounifi==25 # homeassistant.components.yandex_transport aioymaps==1.1.0 @@ -155,7 +155,7 @@ airly==1.0.0 ambiclimate==0.2.1 # homeassistant.components.androidtv -androidtv[async]==0.0.52 +androidtv[async]==0.0.54 # homeassistant.components.apns apns2==0.3.0 @@ -201,16 +201,16 @@ blinkpy==0.16.3 bond-api==0.1.8 # homeassistant.components.braviatv -bravia-tv==1.0.6 +bravia-tv==1.0.8 # homeassistant.components.broadlink -broadlink==0.15.0 +broadlink==0.16.0 # homeassistant.components.brother brother==0.1.18 # homeassistant.components.bsblan -bsblan==0.3.7 +bsblan==0.4.0 # homeassistant.components.buienradar buienradar==1.0.4 @@ -222,7 +222,10 @@ caldav==0.6.1 coinmarketcap==5.0.3 # homeassistant.scripts.check_config -colorlog==4.2.1 +colorlog==4.5.0 + +# homeassistant.components.color_extractor +colorthief==0.2.1 # homeassistant.components.eddystone_temperature # homeassistant.components.eq3btsmart @@ -242,7 +245,7 @@ datadog==0.15.0 datapoint==0.9.5 # homeassistant.components.debugpy -debugpy==1.0.0rc2 +debugpy==1.1.0 # homeassistant.components.ihc # homeassistant.components.namecheapdns @@ -254,7 +257,7 @@ defusedxml==0.6.0 denonavr==0.9.5 # homeassistant.components.devolo_home_control -devolo-home-control-api==0.15.1 +devolo-home-control-api==0.16.0 # homeassistant.components.directv directv==0.3.0 @@ -278,7 +281,7 @@ eebrightbox==0.0.4 elgato==0.2.0 # homeassistant.components.elkm1 -elkm1-lib==0.8.4 +elkm1-lib==0.8.8 # homeassistant.components.mobile_app emoji==0.5.4 @@ -292,6 +295,9 @@ enocean==0.50 # homeassistant.components.season ephem==3.7.7.0 +# homeassistant.components.epson +epson-projector==0.2.3 + # homeassistant.components.feedreader feedparser-homeassistant==5.2.2.dev1 @@ -305,7 +311,7 @@ foobot_async==0.3.2 gTTS-token==1.1.4 # homeassistant.components.garmin_connect -garminconnect==0.1.13 +garminconnect==0.1.16 # homeassistant.components.geo_json_events # homeassistant.components.usgs_earthquakes_feed @@ -346,17 +352,20 @@ gogogate2-api==2.0.3 google-api-python-client==1.6.4 # homeassistant.components.google_pubsub -google-cloud-pubsub==0.39.1 +google-cloud-pubsub==2.1.0 # homeassistant.components.nest -google-nest-sdm==0.1.6 +google-nest-sdm==0.1.14 # homeassistant.components.gree -greeclimate==0.9.5 +greeclimate==0.10.3 # homeassistant.components.griddy griddypower==0.1.0 +# homeassistant.components.profiler +guppy3==3.1.0 + # homeassistant.components.ffmpeg ha-ffmpeg==2.0 @@ -364,10 +373,10 @@ ha-ffmpeg==2.0 hangups==0.4.11 # homeassistant.components.cloud -hass-nabucasa==0.37.1 +hass-nabucasa==0.37.2 # homeassistant.components.tasmota -hatasmota==0.0.25.1 +hatasmota==0.0.31 # homeassistant.components.jewish_calendar hdate==0.9.12 @@ -385,7 +394,7 @@ hole==0.5.1 holidays==0.10.3 # homeassistant.components.frontend -home-assistant-frontend==20201021.4 +home-assistant-frontend==20201111.2 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 @@ -394,7 +403,7 @@ homeassistant-pyozw==0.1.10 homeconnect==0.6.3 # homeassistant.components.homematicip_cloud -homematicip==0.11.0 +homematicip==0.12.1 # homeassistant.components.google # homeassistant.components.remember_the_milk @@ -495,6 +504,9 @@ numpy==1.19.2 # homeassistant.components.google oauth2client==4.0.0 +# homeassistant.components.profiler +objgraph==3.4.1 + # homeassistant.components.omnilogic omnilogic==0.4.2 @@ -508,7 +520,8 @@ openerz-api==0.1.0 ovoenergy==1.1.7 # homeassistant.components.mqtt -paho-mqtt==1.5.0 +# homeassistant.components.shiftr +paho-mqtt==1.5.1 # homeassistant.components.panasonic_viera panasonic_viera==0.3.6 @@ -538,7 +551,7 @@ pilight==0.1.1 pillow==7.2.0 # homeassistant.components.plex -plexapi==4.1.1 +plexapi==4.2.0 # homeassistant.components.plex plexauth==0.0.6 @@ -606,7 +619,7 @@ pyMetno==0.8.1 pyRFXtrx==0.26 # homeassistant.components.tibber -pyTibber==0.15.7 +pyTibber==0.16.0 # homeassistant.components.nextbus py_nextbusnext==0.1.4 @@ -672,7 +685,7 @@ pyflume==0.5.5 pyflunearyou==1.0.7 # homeassistant.components.forked_daapd -pyforked-daapd==0.1.10 +pyforked-daapd==0.1.11 # homeassistant.components.fritzbox pyfritzhome==0.4.2 @@ -730,7 +743,7 @@ pylibrespot-java==0.1.0 pylitejet==0.1 # homeassistant.components.lutron_caseta -pylutron-caseta==0.7.1 +pylutron-caseta==0.7.2 # homeassistant.components.mailgun pymailgunner==1.4 @@ -742,7 +755,7 @@ pymata-express==1.19 pymelcloud==2.5.2 # homeassistant.components.somfy -pymfy==0.9.0 +pymfy==0.9.1 # homeassistant.components.mochad pymochad==0.2.0 @@ -783,7 +796,7 @@ pyotgw==0.6b1 pyotp==2.3.0 # homeassistant.components.openweathermap -pyowm==2.10.0 +pyowm==3.1.0 # homeassistant.components.onewire pyownet==0.10.0.post1 @@ -829,13 +842,13 @@ pysmartthings==0.7.4 pysoma==0.0.10 # homeassistant.components.sonos -pysonos==0.0.35 +pysonos==0.0.36 # homeassistant.components.spc pyspcwebgw==0.4.0 # homeassistant.components.squeezebox -pysqueezebox==0.5.4 +pysqueezebox==0.5.5 # homeassistant.components.syncthru pysyncthru==0.7.0 @@ -859,7 +872,7 @@ python-miio==0.5.3 python-nest==4.1.0 # homeassistant.components.ozw -python-openzwave-mqtt==1.2.2 +python-openzwave-mqtt==1.3.2 # homeassistant.components.songpal python-songpal==0.12 @@ -874,7 +887,7 @@ python-tado==0.8.1 python-twitch-client==0.6.0 # homeassistant.components.velbus -python-velbus==2.0.46 +python-velbus==2.1.1 # homeassistant.components.awair python_awair==0.1.1 @@ -886,10 +899,10 @@ pytile==4.0.0 pytraccar==0.9.0 # homeassistant.components.tradfri -pytradfri[async]==7.0.2 +pytradfri[async]==7.0.4 # homeassistant.components.vera -pyvera==0.3.10 +pyvera==0.3.11 # homeassistant.components.vesync pyvesync==1.2.0 @@ -913,7 +926,7 @@ pyzerproc==0.2.5 rachiopy==1.0.3 # homeassistant.components.rainmachine -regenmaschine==2.1.0 +regenmaschine==3.0.0 # homeassistant.components.python_script restrictedpython==5.0 @@ -931,7 +944,7 @@ rokuecp==0.6.0 roombapy==1.6.1 # homeassistant.components.roon -roonapi==0.0.21 +roonapi==0.0.25 # homeassistant.components.rpi_power rpi-bad-power==0.0.3 @@ -950,7 +963,7 @@ samsungtvws==1.4.0 sense_energy==0.8.1 # homeassistant.components.sentry -sentry-sdk==0.19.1 +sentry-sdk==0.19.2 # homeassistant.components.sharkiq sharkiqpy==0.1.8 @@ -1106,7 +1119,7 @@ zeep[async]==4.0.0 zeroconf==0.28.6 # homeassistant.components.zha -zha-quirks==0.0.45 +zha-quirks==0.0.46 # homeassistant.components.zha zigpy-cc==0.5.2 @@ -1118,7 +1131,7 @@ zigpy-deconz==0.11.0 zigpy-xbee==0.13.0 # homeassistant.components.zha -zigpy-zigate==0.6.2 +zigpy-zigate==0.7.2 # homeassistant.components.zha zigpy-znp==0.2.2 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index c3e489c1ebb..f627346c67b 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -24,7 +24,6 @@ COMMENT_REQUIREMENTS = ( "credstash", "decora", "decora_wifi", - "env_canada", "envirophat", "evdev", "face_recognition", diff --git a/script/hassfest/codeowners.py b/script/hassfest/codeowners.py index 6d312bf8610..eba657f64cf 100644 --- a/script/hassfest/codeowners.py +++ b/script/hassfest/codeowners.py @@ -15,6 +15,12 @@ homeassistant/*.py @home-assistant/core homeassistant/helpers/* @home-assistant/core homeassistant/util/* @home-assistant/core +# Home Assistant Supervisor +build.json @home-assistant/supervisor +machine/* @home-assistant/supervisor +rootfs/* @home-assistant/supervisor +Dockerfile @home-assistant/supervisor + # Other code homeassistant/scripts/check_config.py @kellerza diff --git a/script/hassfest/translations.py b/script/hassfest/translations.py index 6f94b88816c..17da80c3e8a 100644 --- a/script/hassfest/translations.py +++ b/script/hassfest/translations.py @@ -137,6 +137,9 @@ def gen_strings_schema(config: Config, integration: Integration): cv.schema_with_slug_keys(str, slug_validator=lowercase_validator), slug_validator=vol.Any("_", cv.slug), ), + vol.Optional("system_health"): { + vol.Optional("info"): {str: cv.string_with_no_html} + }, } ) diff --git a/script/scaffold/generate.py b/script/scaffold/generate.py index 4c50b8971fb..4cf1624eb4b 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%]" diff --git a/script/scaffold/templates/config_flow/integration/config_flow.py b/script/scaffold/templates/config_flow/integration/config_flow.py index bfa1d65c257..c9700463c86 100644 --- a/script/scaffold/templates/config_flow/integration/config_flow.py +++ b/script/scaffold/templates/config_flow/integration/config_flow.py @@ -10,7 +10,7 @@ from .const import DOMAIN # pylint:disable=unused-import _LOGGER = logging.getLogger(__name__) # TODO adjust the data schema to the data that you need -DATA_SCHEMA = vol.Schema({"host": str, "username": str, "password": str}) +STEP_USER_DATA_SCHEMA = vol.Schema({"host": str, "username": str, "password": str}) class PlaceholderHub: @@ -31,7 +31,7 @@ class PlaceholderHub: async def validate_input(hass: core.HomeAssistant, data): """Validate the user input allows us to connect. - Data has the keys from DATA_SCHEMA with values provided by the user. + Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user. """ # TODO validate the data can be used to set up a connection. @@ -64,22 +64,27 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): async def async_step_user(self, user_input=None): """Handle the initial step.""" - errors = {} - if user_input is not None: - try: - info = await validate_input(self.hass, user_input) + if user_input is None: + return self.async_show_form( + step_id="user", data_schema=STEP_USER_DATA_SCHEMA + ) - return self.async_create_entry(title=info["title"], data=user_input) - except CannotConnect: - errors["base"] = "cannot_connect" - except InvalidAuth: - errors["base"] = "invalid_auth" - except Exception: # pylint: disable=broad-except - _LOGGER.exception("Unexpected exception") - errors["base"] = "unknown" + errors = {} + + try: + info = await validate_input(self.hass, user_input) + except CannotConnect: + errors["base"] = "cannot_connect" + except InvalidAuth: + errors["base"] = "invalid_auth" + except Exception: # pylint: disable=broad-except + _LOGGER.exception("Unexpected exception") + errors["base"] = "unknown" + else: + return self.async_create_entry(title=info["title"], data=user_input) return self.async_show_form( - step_id="user", data_schema=DATA_SCHEMA, errors=errors + step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors ) diff --git a/script/scaffold/templates/config_flow/tests/test_config_flow.py b/script/scaffold/templates/config_flow/tests/test_config_flow.py index 7cd09ad1f42..a69bea2abd8 100644 --- a/script/scaffold/templates/config_flow/tests/test_config_flow.py +++ b/script/scaffold/templates/config_flow/tests/test_config_flow.py @@ -32,6 +32,7 @@ async def test_form(hass): "password": "test-password", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Name of the device" @@ -40,7 +41,6 @@ async def test_form(hass): "username": "test-username", "password": "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/script/translations/clean.py b/script/translations/clean.py index 370c1d672ea..63281b36229 100644 --- a/script/translations/clean.py +++ b/script/translations/clean.py @@ -91,22 +91,25 @@ def run(): print("No missing translations!") return 0 - key_data = lokalise.keys_list( - {"filter_keys": ",".join(missing_keys), "limit": 1000} - ) - if len(key_data) != len(missing_keys): - print( - f"Lookin up key in Lokalise returns {len(key_data)} results, expected {len(missing_keys)}" - ) - return 1 + # We can't query too many keys at once, so limit the number to 50. + for i in range(0, len(missing_keys), 50): + chunk = missing_keys[i : i + 50] - print(f"Deleting {len(missing_keys)} keys:") - for key in missing_keys: - print(" -", key) - print() - while input("Type YES to delete these keys: ") != "YES": - pass + key_data = lokalise.keys_list({"filter_keys": ",".join(chunk), "limit": 1000}) + if len(key_data) != len(chunk): + print( + f"Lookin up key in Lokalise returns {len(key_data)} results, expected {len(chunk)}" + ) + return 1 - print(lokalise.keys_delete_multiple([key["key_id"] for key in key_data])) + print(f"Deleting {len(chunk)} keys:") + for key in chunk: + print(" -", key) + print() + while input("Type YES to delete these keys: ") != "YES": + pass + + print(lokalise.keys_delete_multiple([key["key_id"] for key in key_data])) + print() return 0 diff --git a/setup.py b/setup.py index a1794f7880b..885d6e192d6 100755 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ PROJECT_URLS = { PACKAGES = find_packages(exclude=["tests", "tests.*"]) REQUIRES = [ - "aiohttp==3.6.2", + "aiohttp==3.7.1", "astral==1.10.1", "async_timeout==3.0.1", "attrs==19.3.0", @@ -49,7 +49,7 @@ REQUIRES = [ "python-slugify==4.0.1", "pytz>=2020.1", "pyyaml==5.3.1", - "requests==2.24.0", + "requests==2.25.0", "ruamel.yaml==0.15.100", "voluptuous==0.12.0", "voluptuous-serialize==2.4.0", diff --git a/tests/common.py b/tests/common.py index 0b56d10188e..611becabe33 100644 --- a/tests/common.py +++ b/tests/common.py @@ -207,7 +207,6 @@ async def async_test_home_assistant(loop): hass.config.units = METRIC_SYSTEM hass.config.media_dirs = {"local": get_test_config_dir("media")} hass.config.skip_pip = True - hass.config.legacy_templates = False hass.config_entries = config_entries.ConfigEntries(hass, {}) hass.config_entries._entries = [] @@ -301,7 +300,7 @@ def async_fire_time_changed(hass, datetime_, fire_all=False): if fire_all or mock_seconds_into_future >= future_seconds: with patch( - "homeassistant.helpers.event.pattern_utc_now", + "homeassistant.helpers.event.time_tracker_utcnow", return_value=date_util.as_utc(datetime_), ): task._run() @@ -965,7 +964,7 @@ async def flush_store(store): async def get_system_health_info(hass, domain): """Get system health info.""" - return await hass.data["system_health"]["info"][domain](hass) + return await hass.data["system_health"][domain].info_callback(hass) def mock_integration(hass, module): diff --git a/tests/components/abode/conftest.py b/tests/components/abode/conftest.py index 681f65ddf93..cc18597c56e 100644 --- a/tests/components/abode/conftest.py +++ b/tests/components/abode/conftest.py @@ -3,6 +3,7 @@ import abodepy.helpers.constants as CONST import pytest from tests.common import load_fixture +from tests.components.light.conftest import mock_light_profiles # noqa @pytest.fixture(autouse=True) diff --git a/tests/components/accuweather/test_config_flow.py b/tests/components/accuweather/test_config_flow.py index 2d4769204ac..89159d7c1bf 100644 --- a/tests/components/accuweather/test_config_flow.py +++ b/tests/components/accuweather/test_config_flow.py @@ -159,6 +159,8 @@ async def test_options_flow(hass): return_value=json.loads( load_fixture("accuweather/current_conditions_data.json") ), + ), patch( + "accuweather.AccuWeather.async_get_forecast" ): assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -174,3 +176,7 @@ async def test_options_flow(hass): assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert config_entry.options == {CONF_FORECAST: True} + + await hass.async_block_till_done() + assert await hass.config_entries.async_unload(config_entry.entry_id) + await hass.async_block_till_done() diff --git a/tests/components/accuweather/test_sensor.py b/tests/components/accuweather/test_sensor.py index 4ce34dfebe9..d4aae9a94fc 100644 --- a/tests/components/accuweather/test_sensor.py +++ b/tests/components/accuweather/test_sensor.py @@ -2,11 +2,7 @@ from datetime import timedelta import json -from homeassistant.components.accuweather.const import ( - ATTRIBUTION, - CONCENTRATION_PARTS_PER_CUBIC_METER, - DOMAIN, -) +from homeassistant.components.accuweather.const import ATTRIBUTION, DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.const import ( ATTR_ATTRIBUTION, @@ -14,6 +10,7 @@ from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, + CONCENTRATION_PARTS_PER_CUBIC_METER, DEVICE_CLASS_TEMPERATURE, LENGTH_METERS, LENGTH_MILLIMETERS, diff --git a/tests/components/airvisual/test_config_flow.py b/tests/components/airvisual/test_config_flow.py index 19390231550..3eb22360c5c 100644 --- a/tests/components/airvisual/test_config_flow.py +++ b/tests/components/airvisual/test_config_flow.py @@ -9,7 +9,7 @@ from homeassistant.components.airvisual import ( INTEGRATION_TYPE_GEOGRAPHY, INTEGRATION_TYPE_NODE_PRO, ) -from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER +from homeassistant.config_entries import SOURCE_USER from homeassistant.const import ( CONF_API_KEY, CONF_IP_ADDRESS, @@ -37,7 +37,10 @@ async def test_duplicate_error(hass): ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=geography_conf + DOMAIN, context={"source": SOURCE_USER}, data={"type": "Geographical Location"} + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input=geography_conf ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT @@ -69,12 +72,18 @@ async def test_invalid_identifier(hass): } with patch( - "pyairvisual.air_quality.AirQuality", + "pyairvisual.air_quality.AirQuality.nearest_city", side_effect=InvalidKeyError, ): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=geography_conf + DOMAIN, + context={"source": SOURCE_USER}, + data={"type": "Geographical Location"}, ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input=geography_conf + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] == {CONF_API_KEY: "invalid_api_key"} @@ -162,6 +171,7 @@ async def test_options_flow(hass): with patch( "homeassistant.components.airvisual.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 @@ -187,31 +197,12 @@ async def test_step_geography(hass): "homeassistant.components.airvisual.async_setup_entry", return_value=True ), patch("pyairvisual.air_quality.AirQuality.nearest_city"): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=conf + DOMAIN, + context={"source": SOURCE_USER}, + data={"type": "Geographical Location"}, ) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result["title"] == "Cloud API (51.528308, -0.3817765)" - assert result["data"] == { - CONF_API_KEY: "abcde12345", - CONF_LATITUDE: 51.528308, - CONF_LONGITUDE: -0.3817765, - CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY, - } - - -async def test_step_import(hass): - """Test the import step for both types of configuration.""" - geography_conf = { - CONF_API_KEY: "abcde12345", - CONF_LATITUDE: 51.528308, - CONF_LONGITUDE: -0.3817765, - } - - with patch( - "homeassistant.components.airvisual.async_setup_entry", return_value=True - ), patch("pyairvisual.air_quality.AirQuality.nearest_city"): - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=geography_conf + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input=conf ) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY diff --git a/tests/components/alarmdecoder/__init__.py b/tests/components/alarmdecoder/__init__.py new file mode 100644 index 00000000000..acfe3195aad --- /dev/null +++ b/tests/components/alarmdecoder/__init__.py @@ -0,0 +1 @@ +"""The tests for AlarmDecoder integration.""" diff --git a/tests/components/alarmdecoder/test_config_flow.py b/tests/components/alarmdecoder/test_config_flow.py index 4af8b783b07..b858671fb54 100644 --- a/tests/components/alarmdecoder/test_config_flow.py +++ b/tests/components/alarmdecoder/test_config_flow.py @@ -89,8 +89,8 @@ async def test_setups(hass: HomeAssistant, protocol, connection, title): **connection, CONF_PROTOCOL: protocol, } + await hass.async_block_till_done() - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/androidtv/patchers.py b/tests/components/androidtv/patchers.py index a89abe33de3..b5b6bbd0a46 100644 --- a/tests/components/androidtv/patchers.py +++ b/tests/components/androidtv/patchers.py @@ -155,16 +155,16 @@ PATCH_ISFILE = patch("os.path.isfile", isfile) PATCH_ACCESS = patch("os.access", return_value=True) -def patch_firetv_update(state, current_app, running_apps): +def patch_firetv_update(state, current_app, running_apps, hdmi_input): """Patch the `FireTV.update()` method.""" return patch( "androidtv.firetv.firetv_async.FireTVAsync.update", - return_value=(state, current_app, running_apps), + return_value=(state, current_app, running_apps, hdmi_input), ) def patch_androidtv_update( - state, current_app, running_apps, device, is_volume_muted, volume_level + state, current_app, running_apps, device, is_volume_muted, volume_level, hdmi_input ): """Patch the `AndroidTV.update()` method.""" return patch( @@ -176,6 +176,7 @@ def patch_androidtv_update( device, is_volume_muted, volume_level, + hdmi_input, ), ) diff --git a/tests/components/androidtv/test_media_player.py b/tests/components/androidtv/test_media_player.py index c497a9daa48..f6d189cfbc2 100644 --- a/tests/components/androidtv/test_media_player.py +++ b/tests/components/androidtv/test_media_player.py @@ -3,6 +3,7 @@ import base64 import copy import logging +from androidtv.constants import APPS as ANDROIDTV_APPS from androidtv.exceptions import LockNotAcquiredException import pytest @@ -341,12 +342,14 @@ async def _test_sources(hass, config0): "hdmi", False, 1, + "HW5", ) else: patch_update = patchers.patch_firetv_update( "playing", "com.app.test1", ["com.app.test1", "com.app.test2", "com.app.test3", "com.app.test4"], + "HW5", ) with patch_update: @@ -365,12 +368,14 @@ async def _test_sources(hass, config0): "hdmi", True, 0, + "HW5", ) else: patch_update = patchers.patch_firetv_update( "playing", "com.app.test2", ["com.app.test2", "com.app.test1", "com.app.test3", "com.app.test4"], + "HW5", ) with patch_update: @@ -428,6 +433,7 @@ async def _test_exclude_sources(hass, config0, expected_sources): "hdmi", False, 1, + "HW5", ) else: patch_update = patchers.patch_firetv_update( @@ -440,6 +446,7 @@ async def _test_exclude_sources(hass, config0, expected_sources): "com.app.test4", "com.app.test5", ], + "HW5", ) with patch_update: @@ -470,7 +477,11 @@ async def test_firetv_exclude_sources(hass): async def _test_select_source(hass, config0, source, expected_arg, method_patch): """Test that the methods for launching and stopping apps are called correctly when selecting a source.""" config = copy.deepcopy(config0) - config[DOMAIN][CONF_APPS] = {"com.app.test1": "TEST 1", "com.app.test3": None} + config[DOMAIN][CONF_APPS] = { + "com.app.test1": "TEST 1", + "com.app.test3": None, + "com.youtube.test": "YouTube", + } patch_key, entity_id = _setup(config) with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[ @@ -539,6 +550,20 @@ async def test_androidtv_select_source_launch_app_hidden(hass): ) +async def test_androidtv_select_source_overridden_app_name(hass): + """Test that when an app name is overridden via the `apps` configuration parameter, the app is launched correctly.""" + # Evidence that the default YouTube app ID will be overridden + assert "YouTube" in ANDROIDTV_APPS.values() + assert "com.youtube.test" not in ANDROIDTV_APPS + assert await _test_select_source( + hass, + CONFIG_ANDROIDTV_ADB_SERVER, + "YouTube", + "com.youtube.test", + patchers.PATCH_LAUNCH_APP, + ) + + async def test_androidtv_select_source_stop_app_id(hass): """Test that an app can be stopped using its app ID.""" assert await _test_select_source( diff --git a/tests/components/august/test_config_flow.py b/tests/components/august/test_config_flow.py index 1c23976a6f9..0f9a8ebbd2f 100644 --- a/tests/components/august/test_config_flow.py +++ b/tests/components/august/test_config_flow.py @@ -46,6 +46,7 @@ async def test_form(hass): CONF_PASSWORD: "test-password", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "my@email.tld" @@ -57,7 +58,6 @@ async def test_form(hass): CONF_TIMEOUT: 10, CONF_ACCESS_TOKEN_CACHE_FILE: ".my@email.tld.august.conf", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -205,6 +205,7 @@ async def test_form_needs_validate(hass): result["flow_id"], {VERIFICATION_CODE_KEY: "correct"}, ) + await hass.async_block_till_done() assert len(mock_send_verification_code.mock_calls) == 0 assert len(mock_validate_verification_code.mock_calls) == 1 @@ -218,7 +219,6 @@ async def test_form_needs_validate(hass): CONF_TIMEOUT: 10, CONF_ACCESS_TOKEN_CACHE_FILE: ".my@email.tld.august.conf", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -261,9 +261,9 @@ async def test_form_reauth(hass): CONF_PASSWORD: "new-test-password", }, ) + await hass.async_block_till_done() assert result2["type"] == "abort" assert result2["reason"] == "reauth_successful" - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/automation/test_init.py b/tests/components/automation/test_init.py index 1cdcfc11dfb..95667d9a690 100644 --- a/tests/components/automation/test_init.py +++ b/tests/components/automation/test_init.py @@ -1232,3 +1232,25 @@ async def test_automation_variables(hass, caplog): hass.bus.async_fire("test_event_3", {"break": 0}) await hass.async_block_till_done() assert len(calls) == 3 + + +async def test_blueprint_automation(hass, calls): + """Test blueprint automation.""" + assert await async_setup_component( + hass, + "automation", + { + "automation": { + "use_blueprint": { + "path": "test_event_service.yaml", + "input": { + "trigger_event": "blueprint_event", + "service_to_call": "test.automation", + }, + } + } + }, + ) + hass.bus.async_fire("blueprint_event") + await hass.async_block_till_done() + assert len(calls) == 1 diff --git a/tests/components/axis/conftest.py b/tests/components/axis/conftest.py new file mode 100644 index 00000000000..33ea820f9cf --- /dev/null +++ b/tests/components/axis/conftest.py @@ -0,0 +1,2 @@ +"""axis conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/axis/test_binary_sensor.py b/tests/components/axis/test_binary_sensor.py index e2d820a959e..0c6f4535cd0 100644 --- a/tests/components/axis/test_binary_sensor.py +++ b/tests/components/axis/test_binary_sensor.py @@ -5,6 +5,7 @@ from homeassistant.components.binary_sensor import ( DEVICE_CLASS_MOTION, DOMAIN as BINARY_SENSOR_DOMAIN, ) +from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.setup import async_setup_component from .test_device import NAME, setup_axis_integration @@ -50,7 +51,8 @@ async def test_no_binary_sensors(hass): async def test_binary_sensors(hass): """Test that sensors are loaded properly.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] for event in EVENTS: device.api.event.process_event(event) @@ -58,12 +60,12 @@ async def test_binary_sensors(hass): assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 2 - pir = hass.states.get(f"binary_sensor.{NAME}_pir_0") - assert pir.state == "off" + pir = hass.states.get(f"{BINARY_SENSOR_DOMAIN}.{NAME}_pir_0") + assert pir.state == STATE_OFF assert pir.name == f"{NAME} PIR 0" assert pir.attributes["device_class"] == DEVICE_CLASS_MOTION - vmd4 = hass.states.get(f"binary_sensor.{NAME}_vmd4_profile_1") - assert vmd4.state == "on" + vmd4 = hass.states.get(f"{BINARY_SENSOR_DOMAIN}.{NAME}_vmd4_profile_1") + assert vmd4.state == STATE_ON assert vmd4.name == f"{NAME} VMD4 Profile 1" assert vmd4.attributes["device_class"] == DEVICE_CLASS_MOTION diff --git a/tests/components/axis/test_camera.py b/tests/components/axis/test_camera.py index af276fe6fe5..01c5a677e38 100644 --- a/tests/components/axis/test_camera.py +++ b/tests/components/axis/test_camera.py @@ -6,6 +6,7 @@ from homeassistant.components.axis.const import ( DOMAIN as AXIS_DOMAIN, ) from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN +from homeassistant.const import STATE_IDLE from homeassistant.setup import async_setup_component from .test_device import ENTRY_OPTIONS, NAME, setup_axis_integration @@ -17,7 +18,7 @@ async def test_platform_manually_configured(hass): """Test that nothing happens when platform is manually configured.""" assert ( await async_setup_component( - hass, CAMERA_DOMAIN, {"camera": {"platform": AXIS_DOMAIN}} + hass, CAMERA_DOMAIN, {CAMERA_DOMAIN: {"platform": AXIS_DOMAIN}} ) is True ) @@ -31,11 +32,13 @@ async def test_camera(hass): assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 1 - cam = hass.states.get(f"camera.{NAME}") - assert cam.state == "idle" + entity_id = f"{CAMERA_DOMAIN}.{NAME}" + + cam = hass.states.get(entity_id) + assert cam.state == STATE_IDLE assert cam.name == NAME - camera_entity = camera._get_camera_from_entity_id(hass, f"camera.{NAME}") + camera_entity = camera._get_camera_from_entity_id(hass, entity_id) assert camera_entity.image_source == "http://1.2.3.4:80/axis-cgi/jpg/image.cgi" assert camera_entity.mjpeg_source == "http://1.2.3.4:80/axis-cgi/mjpg/video.cgi" assert ( @@ -51,11 +54,13 @@ async def test_camera_with_stream_profile(hass): assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 1 - cam = hass.states.get(f"camera.{NAME}") - assert cam.state == "idle" + entity_id = f"{CAMERA_DOMAIN}.{NAME}" + + cam = hass.states.get(entity_id) + assert cam.state == STATE_IDLE assert cam.name == NAME - camera_entity = camera._get_camera_from_entity_id(hass, f"camera.{NAME}") + camera_entity = camera._get_camera_from_entity_id(hass, entity_id) assert camera_entity.image_source == "http://1.2.3.4:80/axis-cgi/jpg/image.cgi" assert ( camera_entity.mjpeg_source diff --git a/tests/components/axis/test_config_flow.py b/tests/components/axis/test_config_flow.py index 0def1d84251..24f888ea6ef 100644 --- a/tests/components/axis/test_config_flow.py +++ b/tests/components/axis/test_config_flow.py @@ -8,6 +8,7 @@ from homeassistant.components.axis.const import ( DEFAULT_STREAM_PROFILE, DOMAIN as AXIS_DOMAIN, ) +from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF from homeassistant.const import ( CONF_HOST, CONF_MAC, @@ -16,6 +17,11 @@ from homeassistant.const import ( CONF_PORT, CONF_USERNAME, ) +from homeassistant.data_entry_flow import ( + RESULT_TYPE_ABORT, + RESULT_TYPE_CREATE_ENTRY, + RESULT_TYPE_FORM, +) from .test_device import MAC, MODEL, NAME, setup_axis_integration, vapix_request @@ -26,11 +32,11 @@ from tests.common import MockConfigEntry async def test_flow_manual_configuration(hass): """Test that config flow works.""" result = await hass.config_entries.flow.async_init( - AXIS_DOMAIN, context={"source": "user"} + AXIS_DOMAIN, context={"source": SOURCE_USER} ) - assert result["type"] == "form" - assert result["step_id"] == "user" + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == SOURCE_USER with patch("axis.vapix.Vapix.request", new=vapix_request): result = await hass.config_entries.flow.async_configure( @@ -43,7 +49,7 @@ async def test_flow_manual_configuration(hass): }, ) - assert result["type"] == "create_entry" + assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == f"M1065-LW - {MAC}" assert result["data"] == { CONF_HOST: "1.2.3.4", @@ -58,14 +64,15 @@ async def test_flow_manual_configuration(hass): async def test_manual_configuration_update_configuration(hass): """Test that config flow fails on already configured device.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] result = await hass.config_entries.flow.async_init( - AXIS_DOMAIN, context={"source": "user"} + AXIS_DOMAIN, context={"source": SOURCE_USER} ) - assert result["type"] == "form" - assert result["step_id"] == "user" + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == SOURCE_USER with patch( "homeassistant.components.axis.async_setup_entry", @@ -82,7 +89,7 @@ async def test_manual_configuration_update_configuration(hass): ) await hass.async_block_till_done() - assert result["type"] == "abort" + assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "already_configured" assert device.host == "2.3.4.5" assert len(mock_setup_entry.mock_calls) == 1 @@ -93,11 +100,11 @@ async def test_flow_fails_already_configured(hass): await setup_axis_integration(hass) result = await hass.config_entries.flow.async_init( - AXIS_DOMAIN, context={"source": "user"} + AXIS_DOMAIN, context={"source": SOURCE_USER} ) - assert result["type"] == "form" - assert result["step_id"] == "user" + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == SOURCE_USER with patch("axis.vapix.Vapix.request", new=vapix_request): result = await hass.config_entries.flow.async_configure( @@ -110,18 +117,18 @@ async def test_flow_fails_already_configured(hass): }, ) - assert result["type"] == "abort" + assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "already_configured" async def test_flow_fails_faulty_credentials(hass): """Test that config flow fails on faulty credentials.""" result = await hass.config_entries.flow.async_init( - AXIS_DOMAIN, context={"source": "user"} + AXIS_DOMAIN, context={"source": SOURCE_USER} ) - assert result["type"] == "form" - assert result["step_id"] == "user" + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == SOURCE_USER with patch( "homeassistant.components.axis.config_flow.get_device", @@ -143,11 +150,11 @@ async def test_flow_fails_faulty_credentials(hass): async def test_flow_fails_cannot_connect(hass): """Test that config flow fails on cannot connect.""" result = await hass.config_entries.flow.async_init( - AXIS_DOMAIN, context={"source": "user"} + AXIS_DOMAIN, context={"source": SOURCE_USER} ) - assert result["type"] == "form" - assert result["step_id"] == "user" + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == SOURCE_USER with patch( "homeassistant.components.axis.config_flow.get_device", @@ -180,11 +187,11 @@ async def test_flow_create_entry_multiple_existing_entries_of_same_model(hass): entry2.add_to_hass(hass) result = await hass.config_entries.flow.async_init( - AXIS_DOMAIN, context={"source": "user"} + AXIS_DOMAIN, context={"source": SOURCE_USER} ) - assert result["type"] == "form" - assert result["step_id"] == "user" + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == SOURCE_USER with patch("axis.vapix.Vapix.request", new=vapix_request): result = await hass.config_entries.flow.async_configure( @@ -197,7 +204,7 @@ async def test_flow_create_entry_multiple_existing_entries_of_same_model(hass): }, ) - assert result["type"] == "create_entry" + assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == f"M1065-LW - {MAC}" assert result["data"] == { CONF_HOST: "1.2.3.4", @@ -222,11 +229,11 @@ async def test_zeroconf_flow(hass): "hostname": "name", "properties": {"macaddress": MAC}, }, - context={"source": "zeroconf"}, + context={"source": SOURCE_ZEROCONF}, ) - assert result["type"] == "form" - assert result["step_id"] == "user" + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == SOURCE_USER with patch("axis.vapix.Vapix.request", new=vapix_request): result = await hass.config_entries.flow.async_configure( @@ -239,7 +246,7 @@ async def test_zeroconf_flow(hass): }, ) - assert result["type"] == "create_entry" + assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == f"M1065-LW - {MAC}" assert result["data"] == { CONF_HOST: "1.2.3.4", @@ -256,7 +263,8 @@ async def test_zeroconf_flow(hass): async def test_zeroconf_flow_already_configured(hass): """Test that zeroconf doesn't setup already configured devices.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] assert device.host == "1.2.3.4" result = await hass.config_entries.flow.async_init( @@ -267,17 +275,18 @@ async def test_zeroconf_flow_already_configured(hass): "hostname": "name", "properties": {"macaddress": MAC}, }, - context={"source": "zeroconf"}, + context={"source": SOURCE_ZEROCONF}, ) - assert result["type"] == "abort" + assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "already_configured" assert device.host == "1.2.3.4" async def test_zeroconf_flow_updated_configuration(hass): """Test that zeroconf update configuration with new parameters.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] assert device.host == "1.2.3.4" assert device.config_entry.data == { CONF_HOST: "1.2.3.4", @@ -301,11 +310,11 @@ async def test_zeroconf_flow_updated_configuration(hass): "hostname": "name", "properties": {"macaddress": MAC}, }, - context={"source": "zeroconf"}, + context={"source": SOURCE_ZEROCONF}, ) await hass.async_block_till_done() - assert result["type"] == "abort" + assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "already_configured" assert device.config_entry.data == { CONF_HOST: "2.3.4.5", @@ -324,10 +333,10 @@ async def test_zeroconf_flow_ignore_non_axis_device(hass): result = await hass.config_entries.flow.async_init( AXIS_DOMAIN, data={CONF_HOST: "169.254.3.4", "properties": {"macaddress": "01234567890"}}, - context={"source": "zeroconf"}, + context={"source": SOURCE_ZEROCONF}, ) - assert result["type"] == "abort" + assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "not_axis_device" @@ -336,16 +345,17 @@ async def test_zeroconf_flow_ignore_link_local_address(hass): result = await hass.config_entries.flow.async_init( AXIS_DOMAIN, data={CONF_HOST: "169.254.3.4", "properties": {"macaddress": MAC}}, - context={"source": "zeroconf"}, + context={"source": SOURCE_ZEROCONF}, ) - assert result["type"] == "abort" + assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "link_local_address" async def test_option_flow(hass): """Test config flow options.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] assert device.option_stream_profile == DEFAULT_STREAM_PROFILE result = await hass.config_entries.options.async_init(device.config_entry.entry_id) diff --git a/tests/components/axis/test_device.py b/tests/components/axis/test_device.py index 627a17ecf60..b7612a01c1d 100644 --- a/tests/components/axis/test_device.py +++ b/tests/components/axis/test_device.py @@ -29,6 +29,7 @@ from homeassistant.components.axis.const import ( DOMAIN as AXIS_DOMAIN, ) from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN +from homeassistant.config_entries import SOURCE_ZEROCONF from homeassistant.const import ( CONF_HOST, CONF_MAC, @@ -36,6 +37,7 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_PORT, CONF_USERNAME, + STATE_ON, ) from tests.async_mock import AsyncMock, Mock, patch @@ -229,7 +231,6 @@ async def setup_axis_integration(hass, config=ENTRY_CONFIG, options=ENTRY_OPTION data=deepcopy(config), connection_class=config_entries.CONN_CLASS_LOCAL_PUSH, options=deepcopy(options), - entry_id="1", version=2, ) config_entry.add_to_hass(hass) @@ -241,7 +242,7 @@ async def setup_axis_integration(hass, config=ENTRY_CONFIG, options=ENTRY_OPTION await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() - return hass.data[AXIS_DOMAIN].get(config_entry.unique_id) + return config_entry async def test_device_setup(hass): @@ -250,7 +251,8 @@ async def test_device_setup(hass): "homeassistant.config_entries.ConfigEntries.async_forward_entry_setup", return_value=True, ) as forward_entry_setup: - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] assert device.api.vapix.firmware_version == "9.10.1" assert device.api.vapix.product_number == "M1065-LW" @@ -277,7 +279,8 @@ async def test_device_info(hass): api_discovery["data"]["apiList"].append(API_DISCOVERY_BASIC_DEVICE_INFO) with patch.dict(API_DISCOVERY_RESPONSE, api_discovery): - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] assert device.api.vapix.firmware_version == "9.80.1" assert device.api.vapix.product_number == "M1065-LW" @@ -303,14 +306,15 @@ async def test_device_support_mqtt(hass, mqtt_mock): await hass.async_block_till_done() assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 1 - pir = hass.states.get(f"binary_sensor.{NAME}_pir_0") - assert pir.state == "on" + pir = hass.states.get(f"{BINARY_SENSOR_DOMAIN}.{NAME}_pir_0") + assert pir.state == STATE_ON assert pir.name == f"{NAME} PIR 0" async def test_update_address(hass): """Test update address works.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] assert device.api.config.host == "1.2.3.4" with patch("axis.vapix.Vapix.request", new=vapix_request), patch( @@ -325,7 +329,7 @@ async def test_update_address(hass): "hostname": "name", "properties": {"macaddress": MAC}, }, - context={"source": "zeroconf"}, + context={"source": SOURCE_ZEROCONF}, ) await hass.async_block_till_done() @@ -335,14 +339,16 @@ async def test_update_address(hass): async def test_device_unavailable(hass): """Successful setup.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] device.async_connection_status_callback(status=False) assert not device.available async def test_device_reset(hass): """Successfully reset device.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] result = await device.async_reset() assert result is True diff --git a/tests/components/axis/test_init.py b/tests/components/axis/test_init.py index 3feee94267a..cf5253d4675 100644 --- a/tests/components/axis/test_init.py +++ b/tests/components/axis/test_init.py @@ -51,7 +51,8 @@ async def test_setup_entry_fails(hass): async def test_unload_entry(hass): """Test successful unload of entry.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] assert hass.data[AXIS_DOMAIN] assert await hass.config_entries.async_unload(device.config_entry.entry_id) diff --git a/tests/components/axis/test_light.py b/tests/components/axis/test_light.py index 987ef1cd48b..06612daa313 100644 --- a/tests/components/axis/test_light.py +++ b/tests/components/axis/test_light.py @@ -4,6 +4,13 @@ from copy import deepcopy from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN as LIGHT_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + STATE_OFF, + STATE_ON, +) from homeassistant.setup import async_setup_component from .test_device import API_DISCOVERY_RESPONSE, NAME, setup_axis_integration @@ -57,7 +64,8 @@ async def test_lights(hass): api_discovery["data"]["apiList"].append(API_DISCOVERY_LIGHT_CONTROL) with patch.dict(API_DISCOVERY_RESPONSE, api_discovery): - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] # Add light with patch( @@ -72,8 +80,10 @@ async def test_lights(hass): assert len(hass.states.async_entity_ids(LIGHT_DOMAIN)) == 1 - light_0 = hass.states.get(f"light.{NAME}_ir_light_0") - assert light_0.state == "on" + entity_id = f"{LIGHT_DOMAIN}.{NAME}_ir_light_0" + + light_0 = hass.states.get(entity_id) + assert light_0.state == STATE_ON assert light_0.name == f"{NAME} IR Light 0" # Turn on, set brightness, light already on @@ -87,8 +97,8 @@ async def test_lights(hass): ): await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", - {"entity_id": f"light.{NAME}_ir_light_0", ATTR_BRIGHTNESS: 50}, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 50}, blocking=True, ) mock_activate.assert_not_awaited() @@ -103,8 +113,8 @@ async def test_lights(hass): ): await hass.services.async_call( LIGHT_DOMAIN, - "turn_off", - {"entity_id": f"light.{NAME}_ir_light_0"}, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) mock_deactivate.assert_called_once() @@ -113,8 +123,8 @@ async def test_lights(hass): device.api.event.process_event(EVENT_OFF) await hass.async_block_till_done() - light_0 = hass.states.get(f"light.{NAME}_ir_light_0") - assert light_0.state == "off" + light_0 = hass.states.get(entity_id) + assert light_0.state == STATE_OFF # Turn on, set brightness with patch( @@ -127,8 +137,8 @@ async def test_lights(hass): ): await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", - {"entity_id": f"light.{NAME}_ir_light_0"}, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) mock_activate.assert_called_once() @@ -143,8 +153,8 @@ async def test_lights(hass): ): await hass.services.async_call( LIGHT_DOMAIN, - "turn_off", - {"entity_id": f"light.{NAME}_ir_light_0"}, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) mock_deactivate.assert_not_called() diff --git a/tests/components/axis/test_switch.py b/tests/components/axis/test_switch.py index 37d50e33e3e..fbcf0624fc9 100644 --- a/tests/components/axis/test_switch.py +++ b/tests/components/axis/test_switch.py @@ -4,6 +4,13 @@ from copy import deepcopy from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + STATE_OFF, + STATE_ON, +) from homeassistant.setup import async_setup_component from .test_device import ( @@ -53,7 +60,8 @@ async def test_no_switches(hass): async def test_switches_with_port_cgi(hass): """Test that switches are loaded properly using port.cgi.""" - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] device.api.vapix.ports = {"0": AsyncMock(), "1": AsyncMock()} device.api.vapix.ports["0"].name = "Doorbell" @@ -67,26 +75,28 @@ async def test_switches_with_port_cgi(hass): assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 - relay_0 = hass.states.get(f"switch.{NAME}_doorbell") - assert relay_0.state == "off" - assert relay_0.name == f"{NAME} Doorbell" - - relay_1 = hass.states.get(f"switch.{NAME}_relay_1") - assert relay_1.state == "on" + relay_1 = hass.states.get(f"{SWITCH_DOMAIN}.{NAME}_relay_1") + assert relay_1.state == STATE_ON assert relay_1.name == f"{NAME} Relay 1" + entity_id = f"{SWITCH_DOMAIN}.{NAME}_doorbell" + + relay_0 = hass.states.get(entity_id) + assert relay_0.state == STATE_OFF + assert relay_0.name == f"{NAME} Doorbell" + await hass.services.async_call( SWITCH_DOMAIN, - "turn_on", - {"entity_id": f"switch.{NAME}_doorbell"}, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) device.api.vapix.ports["0"].close.assert_called_once() await hass.services.async_call( SWITCH_DOMAIN, - "turn_off", - {"entity_id": f"switch.{NAME}_doorbell"}, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) device.api.vapix.ports["0"].open.assert_called_once() @@ -98,7 +108,8 @@ async def test_switches_with_port_management(hass): api_discovery["data"]["apiList"].append(API_DISCOVERY_PORT_MANAGEMENT) with patch.dict(API_DISCOVERY_RESPONSE, api_discovery): - device = await setup_axis_integration(hass) + config_entry = await setup_axis_integration(hass) + device = hass.data[AXIS_DOMAIN][config_entry.unique_id] device.api.vapix.ports = {"0": AsyncMock(), "1": AsyncMock()} device.api.vapix.ports["0"].name = "Doorbell" @@ -112,26 +123,28 @@ async def test_switches_with_port_management(hass): assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 - relay_0 = hass.states.get(f"switch.{NAME}_doorbell") - assert relay_0.state == "off" - assert relay_0.name == f"{NAME} Doorbell" - - relay_1 = hass.states.get(f"switch.{NAME}_relay_1") - assert relay_1.state == "on" + relay_1 = hass.states.get(f"{SWITCH_DOMAIN}.{NAME}_relay_1") + assert relay_1.state == STATE_ON assert relay_1.name == f"{NAME} Relay 1" + entity_id = f"{SWITCH_DOMAIN}.{NAME}_doorbell" + + relay_0 = hass.states.get(entity_id) + assert relay_0.state == STATE_OFF + assert relay_0.name == f"{NAME} Doorbell" + await hass.services.async_call( SWITCH_DOMAIN, - "turn_on", - {"entity_id": f"switch.{NAME}_doorbell"}, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) device.api.vapix.ports["0"].close.assert_called_once() await hass.services.async_call( SWITCH_DOMAIN, - "turn_off", - {"entity_id": f"switch.{NAME}_doorbell"}, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) device.api.vapix.ports["0"].open.assert_called_once() diff --git a/tests/components/blebox/conftest.py b/tests/components/blebox/conftest.py index ece02d50b39..e43fb9fc4b4 100644 --- a/tests/components/blebox/conftest.py +++ b/tests/components/blebox/conftest.py @@ -1,5 +1,4 @@ """PyTest fixtures and test helpers.""" - from unittest import mock import blebox_uniapi @@ -11,6 +10,7 @@ from homeassistant.setup import async_setup_component from tests.async_mock import AsyncMock, PropertyMock, patch from tests.common import MockConfigEntry +from tests.components.light.conftest import mock_light_profiles # noqa def patch_product_identify(path=None, **kwargs): diff --git a/tests/components/blink/test_config_flow.py b/tests/components/blink/test_config_flow.py index 72a4a5272ed..36e3fbd95ea 100644 --- a/tests/components/blink/test_config_flow.py +++ b/tests/components/blink/test_config_flow.py @@ -31,6 +31,7 @@ async def test_form(hass): result["flow_id"], {"username": "blink@example.com", "password": "example"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "blink" @@ -45,7 +46,6 @@ async def test_form(hass): "client_id": None, "region_id": None, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -88,11 +88,11 @@ async def test_form_2fa(hass): result3 = await hass.config_entries.flow.async_configure( result2["flow_id"], {"pin": "1234"} ) + await hass.async_block_till_done() assert result3["type"] == "create_entry" assert result3["title"] == "blink" assert result3["result"].unique_id == "blink@example.com" - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/blueprint/__init__.py b/tests/components/blueprint/__init__.py new file mode 100644 index 00000000000..b67346b1c2f --- /dev/null +++ b/tests/components/blueprint/__init__.py @@ -0,0 +1 @@ +"""Tests for the blueprint integration.""" diff --git a/tests/components/blueprint/test_importer.py b/tests/components/blueprint/test_importer.py new file mode 100644 index 00000000000..263f82ab230 --- /dev/null +++ b/tests/components/blueprint/test_importer.py @@ -0,0 +1,137 @@ +"""Test blueprint importing.""" +import json +from pathlib import Path + +import pytest + +from homeassistant.components.blueprint import importer +from homeassistant.exceptions import HomeAssistantError + +from tests.common import load_fixture + + +@pytest.fixture(scope="session") +def community_post(): + """Topic JSON with a codeblock marked as auto syntax.""" + return load_fixture("blueprint/community_post.json") + + +def test_get_community_post_import_url(): + """Test variations of generating import forum url.""" + assert ( + importer._get_community_post_import_url( + "https://community.home-assistant.io/t/test-topic/123" + ) + == "https://community.home-assistant.io/t/test-topic/123.json" + ) + + assert ( + importer._get_community_post_import_url( + "https://community.home-assistant.io/t/test-topic/123/2" + ) + == "https://community.home-assistant.io/t/test-topic/123.json" + ) + + +def test_get_github_import_url(): + """Test getting github import url.""" + assert ( + importer._get_github_import_url( + "https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml" + ) + == "https://raw.githubusercontent.com/balloob/home-assistant-config/main/blueprints/automation/motion_light.yaml" + ) + + assert ( + importer._get_github_import_url( + "https://raw.githubusercontent.com/balloob/home-assistant-config/main/blueprints/automation/motion_light.yaml" + ) + == "https://raw.githubusercontent.com/balloob/home-assistant-config/main/blueprints/automation/motion_light.yaml" + ) + + +def test_extract_blueprint_from_community_topic(community_post): + """Test extracting blueprint.""" + imported_blueprint = importer._extract_blueprint_from_community_topic( + "http://example.com", json.loads(community_post) + ) + assert imported_blueprint is not None + assert imported_blueprint.url == "http://example.com" + assert imported_blueprint.blueprint.domain == "automation" + assert imported_blueprint.blueprint.placeholders == { + "service_to_call", + "trigger_event", + } + + +def test_extract_blueprint_from_community_topic_invalid_yaml(): + """Test extracting blueprint with invalid YAML.""" + with pytest.raises(HomeAssistantError): + importer._extract_blueprint_from_community_topic( + "http://example.com", + { + "post_stream": { + "posts": [ + {"cooked": 'invalid: yaml: 2'} + ] + } + }, + ) + + +def test__extract_blueprint_from_community_topic_wrong_lang(): + """Test extracting blueprint with invalid YAML.""" + assert ( + importer._extract_blueprint_from_community_topic( + "http://example.com", + { + "post_stream": { + "posts": [ + {"cooked": 'invalid yaml + 2'} + ] + } + }, + ) + is None + ) + + +async def test_fetch_blueprint_from_community_url(hass, aioclient_mock, community_post): + """Test fetching blueprint from url.""" + aioclient_mock.get( + "https://community.home-assistant.io/t/test-topic/123.json", text=community_post + ) + imported_blueprint = await importer.fetch_blueprint_from_url( + hass, "https://community.home-assistant.io/t/test-topic/123/2" + ) + assert isinstance(imported_blueprint, importer.ImportedBlueprint) + assert imported_blueprint.blueprint.domain == "automation" + assert imported_blueprint.blueprint.placeholders == { + "service_to_call", + "trigger_event", + } + + +@pytest.mark.parametrize( + "url", + ( + "https://raw.githubusercontent.com/balloob/home-assistant-config/main/blueprints/automation/motion_light.yaml", + "https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml", + ), +) +async def test_fetch_blueprint_from_github_url(hass, aioclient_mock, url): + """Test fetching blueprint from url.""" + aioclient_mock.get( + "https://raw.githubusercontent.com/balloob/home-assistant-config/main/blueprints/automation/motion_light.yaml", + text=Path( + hass.config.path("blueprints/automation/test_event_service.yaml") + ).read_text(), + ) + + imported_blueprint = await importer.fetch_blueprint_from_url(hass, url) + assert isinstance(imported_blueprint, importer.ImportedBlueprint) + assert imported_blueprint.blueprint.domain == "automation" + assert imported_blueprint.blueprint.placeholders == { + "service_to_call", + "trigger_event", + } diff --git a/tests/components/blueprint/test_init.py b/tests/components/blueprint/test_init.py new file mode 100644 index 00000000000..5552d0625b0 --- /dev/null +++ b/tests/components/blueprint/test_init.py @@ -0,0 +1 @@ +"""Tests for the blueprint init.""" diff --git a/tests/components/blueprint/test_models.py b/tests/components/blueprint/test_models.py new file mode 100644 index 00000000000..56fe13599d7 --- /dev/null +++ b/tests/components/blueprint/test_models.py @@ -0,0 +1,154 @@ +"""Test blueprint models.""" +import logging + +import pytest + +from homeassistant.components.blueprint import errors, models +from homeassistant.util.yaml import Placeholder + +from tests.async_mock import patch + + +@pytest.fixture +def blueprint_1(): + """Blueprint fixture.""" + return models.Blueprint( + { + "blueprint": { + "name": "Hello", + "domain": "automation", + "input": {"test-placeholder": None}, + }, + "example": Placeholder("test-placeholder"), + } + ) + + +@pytest.fixture +def domain_bps(hass): + """Domain blueprints fixture.""" + return models.DomainBlueprints(hass, "automation", logging.getLogger(__name__)) + + +def test_blueprint_model_init(): + """Test constructor validation.""" + with pytest.raises(errors.InvalidBlueprint): + models.Blueprint({}) + + with pytest.raises(errors.InvalidBlueprint): + models.Blueprint( + {"blueprint": {"name": "Hello", "domain": "automation"}}, + expected_domain="not-automation", + ) + + with pytest.raises(errors.InvalidBlueprint): + models.Blueprint( + { + "blueprint": { + "name": "Hello", + "domain": "automation", + "input": {"something": None}, + }, + "trigger": {"platform": Placeholder("non-existing")}, + } + ) + + +def test_blueprint_properties(blueprint_1): + """Test properties.""" + assert blueprint_1.metadata == { + "name": "Hello", + "domain": "automation", + "input": {"test-placeholder": None}, + } + assert blueprint_1.domain == "automation" + assert blueprint_1.name == "Hello" + assert blueprint_1.placeholders == {"test-placeholder"} + + +def test_blueprint_update_metadata(): + """Test properties.""" + bp = models.Blueprint( + { + "blueprint": { + "name": "Hello", + "domain": "automation", + }, + } + ) + + bp.update_metadata(source_url="http://bla.com") + assert bp.metadata["source_url"] == "http://bla.com" + + +def test_blueprint_inputs(blueprint_1): + """Test blueprint inputs.""" + inputs = models.BlueprintInputs( + blueprint_1, + {"use_blueprint": {"path": "bla", "input": {"test-placeholder": 1}}}, + ) + inputs.validate() + assert inputs.inputs == {"test-placeholder": 1} + assert inputs.async_substitute() == {"example": 1} + + +def test_blueprint_inputs_validation(blueprint_1): + """Test blueprint input validation.""" + inputs = models.BlueprintInputs( + blueprint_1, + {"use_blueprint": {"path": "bla", "input": {"non-existing-placeholder": 1}}}, + ) + with pytest.raises(errors.MissingPlaceholder): + inputs.validate() + + +async def test_domain_blueprints_get_blueprint_errors(hass, domain_bps): + """Test domain blueprints.""" + assert hass.data["blueprint"]["automation"] is domain_bps + + with pytest.raises(errors.FailedToLoad), patch( + "homeassistant.util.yaml.load_yaml", side_effect=FileNotFoundError + ): + await domain_bps.async_get_blueprint("non-existing-path") + + with patch( + "homeassistant.util.yaml.load_yaml", return_value={"blueprint": "invalid"} + ): + assert await domain_bps.async_get_blueprint("non-existing-path") is None + + +async def test_domain_blueprints_caching(domain_bps): + """Test domain blueprints cache blueprints.""" + obj = object() + with patch.object(domain_bps, "_load_blueprint", return_value=obj): + assert await domain_bps.async_get_blueprint("something") is obj + + # Now we hit cache + assert await domain_bps.async_get_blueprint("something") is obj + + obj_2 = object() + domain_bps.async_reset_cache() + + # Now we call this method again. + with patch.object(domain_bps, "_load_blueprint", return_value=obj_2): + assert await domain_bps.async_get_blueprint("something") is obj_2 + + +async def test_domain_blueprints_inputs_from_config(domain_bps, blueprint_1): + """Test DomainBlueprints.async_inputs_from_config.""" + with pytest.raises(errors.InvalidBlueprintInputs): + await domain_bps.async_inputs_from_config({"not-referencing": "use_blueprint"}) + + with pytest.raises(errors.MissingPlaceholder), patch.object( + domain_bps, "async_get_blueprint", return_value=blueprint_1 + ): + await domain_bps.async_inputs_from_config( + {"use_blueprint": {"path": "bla.yaml", "input": {}}} + ) + + with patch.object(domain_bps, "async_get_blueprint", return_value=blueprint_1): + inputs = await domain_bps.async_inputs_from_config( + {"use_blueprint": {"path": "bla.yaml", "input": {"test-placeholder": None}}} + ) + assert inputs.blueprint is blueprint_1 + assert inputs.inputs == {"test-placeholder": None} diff --git a/tests/components/blueprint/test_schemas.py b/tests/components/blueprint/test_schemas.py new file mode 100644 index 00000000000..bf50bdad975 --- /dev/null +++ b/tests/components/blueprint/test_schemas.py @@ -0,0 +1,71 @@ +"""Test schemas.""" +import logging + +import pytest +import voluptuous as vol + +from homeassistant.components.blueprint import schemas + +_LOGGER = logging.getLogger(__name__) + + +@pytest.mark.parametrize( + "blueprint", + ( + # Test allow extra + { + "trigger": "Test allow extra", + "blueprint": {"name": "Test Name", "domain": "automation"}, + }, + # Bare minimum + {"blueprint": {"name": "Test Name", "domain": "automation"}}, + # Empty triggers + {"blueprint": {"name": "Test Name", "domain": "automation", "input": {}}}, + # No definition of input + { + "blueprint": { + "name": "Test Name", + "domain": "automation", + "input": { + "some_placeholder": None, + }, + } + }, + ), +) +def test_blueprint_schema(blueprint): + """Test different schemas.""" + try: + schemas.BLUEPRINT_SCHEMA(blueprint) + except vol.Invalid: + _LOGGER.exception("%s", blueprint) + assert False, "Expected schema to be valid" + + +@pytest.mark.parametrize( + "blueprint", + ( + # no domain + {"blueprint": {}}, + # non existing key in blueprint + { + "blueprint": { + "name": "Example name", + "domain": "automation", + "non_existing": None, + } + }, + # non existing key in input + { + "blueprint": { + "name": "Example name", + "domain": "automation", + "input": {"some_placeholder": {"non_existing": "bla"}}, + } + }, + ), +) +def test_blueprint_schema_invalid(blueprint): + """Test different schemas.""" + with pytest.raises(vol.Invalid): + schemas.BLUEPRINT_SCHEMA(blueprint) diff --git a/tests/components/blueprint/test_websocket_api.py b/tests/components/blueprint/test_websocket_api.py new file mode 100644 index 00000000000..54fcc0a5891 --- /dev/null +++ b/tests/components/blueprint/test_websocket_api.py @@ -0,0 +1,82 @@ +"""Test websocket API.""" +from pathlib import Path + +import pytest + +from homeassistant.components import automation +from homeassistant.setup import async_setup_component + + +@pytest.fixture(autouse=True) +async def setup_bp(hass): + """Fixture to set up the blueprint component.""" + assert await async_setup_component(hass, "blueprint", {}) + + # Trigger registration of automation blueprints + automation.async_get_blueprints(hass) + + +async def test_list_blueprints(hass, hass_ws_client): + """Test listing blueprints.""" + client = await hass_ws_client(hass) + await client.send_json({"id": 5, "type": "blueprint/list"}) + + msg = await client.receive_json() + + assert msg["id"] == 5 + assert msg["success"] + blueprints = msg["result"] + assert blueprints.get("automation") == { + "test_event_service.yaml": { + "metadata": { + "domain": "automation", + "input": {"service_to_call": None, "trigger_event": None}, + "name": "Call service based on event", + }, + }, + "in_folder/in_folder_blueprint.yaml": { + "metadata": { + "domain": "automation", + "input": {"action": None, "trigger": None}, + "name": "In Folder Blueprint", + } + }, + } + + +async def test_import_blueprint(hass, aioclient_mock, hass_ws_client): + """Test listing blueprints.""" + raw_data = Path( + hass.config.path("blueprints/automation/test_event_service.yaml") + ).read_text() + + aioclient_mock.get( + "https://raw.githubusercontent.com/balloob/home-assistant-config/main/blueprints/automation/motion_light.yaml", + text=raw_data, + ) + + client = await hass_ws_client(hass) + await client.send_json( + { + "id": 5, + "type": "blueprint/import", + "url": "https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml", + } + ) + + msg = await client.receive_json() + + assert msg["id"] == 5 + assert msg["success"] + assert msg["result"] == { + "suggested_filename": "balloob-motion_light", + "url": "https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml", + "raw_data": raw_data, + "blueprint": { + "metadata": { + "domain": "automation", + "input": {"service_to_call": None, "trigger_event": None}, + "name": "Call service based on event", + }, + }, + } diff --git a/tests/components/bond/conftest.py b/tests/components/bond/conftest.py new file mode 100644 index 00000000000..7ab1805cb73 --- /dev/null +++ b/tests/components/bond/conftest.py @@ -0,0 +1,2 @@ +"""bond conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/bond/test_config_flow.py b/tests/components/bond/test_config_flow.py index cd98dd8090a..b87891a1896 100644 --- a/tests/components/bond/test_config_flow.py +++ b/tests/components/bond/test_config_flow.py @@ -29,6 +29,7 @@ async def test_user_form(hass: core.HomeAssistant): result["flow_id"], {CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "test-bond-id" @@ -36,7 +37,6 @@ async def test_user_form(hass: core.HomeAssistant): CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -165,6 +165,7 @@ async def test_zeroconf_form(hass: core.HomeAssistant): result["flow_id"], {CONF_ACCESS_TOKEN: "test-token"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "test-bond-id" @@ -172,7 +173,6 @@ async def test_zeroconf_form(hass: core.HomeAssistant): CONF_HOST: "test-host", CONF_ACCESS_TOKEN: "test-token", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/broadlink/test_config_flow.py b/tests/components/broadlink/test_config_flow.py index bc0eba069a8..c19d831cf3a 100644 --- a/tests/components/broadlink/test_config_flow.py +++ b/tests/components/broadlink/test_config_flow.py @@ -334,7 +334,7 @@ async def test_flow_auth_os_error(hass): async def test_flow_reset_works(hass): - """Test we finish a config flow after a factory reset.""" + """Test we finish a config flow after a manual unlock.""" device = get_device("Living Room") mock_api = device.get_mock_api() mock_api.auth.side_effect = blke.AuthenticationError() diff --git a/tests/components/canary/conftest.py b/tests/components/canary/conftest.py index 01527a193c0..ed0e7f80f8d 100644 --- a/tests/components/canary/conftest.py +++ b/tests/components/canary/conftest.py @@ -5,6 +5,12 @@ from pytest import fixture from tests.async_mock import MagicMock, patch +@fixture(autouse=True) +def mock_ffmpeg(hass): + """Mock ffmpeg is loaded.""" + hass.config.components.add("ffmpeg") + + @fixture def canary(hass): """Mock the CanaryApi for easier testing.""" diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index 86b61d8f687..0e9f6c13e3d 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -1,5 +1,6 @@ """The tests for the Cast Media player platform.""" # pylint: disable=protected-access +import json from typing import Optional from uuid import UUID @@ -15,12 +16,25 @@ from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.typing import HomeAssistantType from homeassistant.setup import async_setup_component -from tests.async_mock import AsyncMock, MagicMock, Mock, patch +from tests.async_mock import ANY, AsyncMock, MagicMock, Mock, patch from tests.common import MockConfigEntry, assert_setup_component +from tests.components.media_player import common + + +@pytest.fixture() +def mz_mock(): + """Mock pychromecast MultizoneManager.""" + return MagicMock() + + +@pytest.fixture() +def quick_play_mock(): + """Mock pychromecast quick_play.""" + return MagicMock() @pytest.fixture(autouse=True) -def cast_mock(): +def cast_mock(mz_mock, quick_play_mock): """Mock pychromecast.""" pycast_mock = MagicMock() pycast_mock.start_discovery.return_value = (None, Mock()) @@ -35,10 +49,14 @@ def cast_mock(): ), patch( "homeassistant.components.cast.discovery.pychromecast", pycast_mock ), patch( - "homeassistant.components.cast.media_player.MultizoneManager", MagicMock() + "homeassistant.components.cast.media_player.MultizoneManager", + return_value=mz_mock, ), patch( "homeassistant.components.cast.media_player.zeroconf.async_get_instance", AsyncMock(), + ), patch( + "homeassistant.components.cast.media_player.quick_play", + quick_play_mock, ): yield @@ -133,8 +151,6 @@ async def async_setup_media_player_cast(hass: HomeAssistantType, info: Chromecas chromecast = get_fake_chromecast(info) zconf = get_fake_zconf(host=info.host, port=info.port) - cast.CastStatusListener = MagicMock() - with patch( "homeassistant.components.cast.discovery.pychromecast.get_chromecast_from_service", return_value=chromecast, @@ -153,27 +169,40 @@ async def async_setup_media_player_cast(hass: HomeAssistantType, info: Chromecas ) await hass.async_block_till_done() - await cast.async_setup_entry(hass, MockConfigEntry(), None) - discovery_callback = cast_listener.call_args[0][0] - def discover_chromecast(service_name: str, info: ChromecastInfo) -> None: - """Discover a chromecast device.""" - listener.services[info.uuid] = ( - {service_name}, - info.uuid, - info.model_name, - info.friendly_name, - ) - discovery_callback(info.uuid, service_name) + service_name = "the-service" + listener.services[info.uuid] = ( + {service_name}, + info.uuid, + info.model_name, + info.friendly_name, + ) + discovery_callback(info.uuid, service_name) - discover_chromecast("the-service", info) await hass.async_block_till_done() await hass.async_block_till_done() assert get_chromecast.call_count == 1 - assert cast.CastStatusListener.call_count == 1 - entity = cast.CastStatusListener.call_args[0][0] - return chromecast, entity + return chromecast + + +def get_status_callbacks(chromecast_mock, mz_mock=None): + """Get registered status callbacks from the chromecast mock.""" + status_listener = chromecast_mock.register_status_listener.call_args[0][0] + cast_status_cb = status_listener.new_cast_status + + connection_listener = chromecast_mock.register_connection_listener.call_args[0][0] + conn_status_cb = connection_listener.new_connection_status + + mc = chromecast_mock.socket_client.media_controller + media_status_cb = mc.register_status_listener.call_args[0][0].new_media_status + + if not mz_mock: + return cast_status_cb, conn_status_cb, media_status_cb + + mz_listener = mz_mock.register_listener.call_args[0][1] + group_media_status_cb = mz_listener.multizone_new_media_status + return cast_status_cb, conn_status_cb, media_status_cb, group_media_status_cb async def test_start_discovery_called_once(hass): @@ -358,78 +387,429 @@ async def test_update_cast_chromecasts(hass): assert add_dev1.call_count == 1 -async def test_entity_media_states(hass: HomeAssistantType): - """Test various entity media states.""" +async def test_entity_availability(hass: HomeAssistantType): + """Test handling of connection status.""" + entity_id = "media_player.speaker" + info = get_fake_chromecast_info() + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + state = hass.states.get(entity_id) + assert state.state == "unavailable" + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.state == "unknown" + + connection_status = MagicMock() + connection_status.status = "DISCONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.state == "unavailable" + + +async def test_entity_cast_status(hass: HomeAssistantType): + """Test handling of cast status.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + info = get_fake_chromecast_info() full_info = attr.evolve( info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID ) - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + cast_status_cb, conn_status_cb, _ = get_status_callbacks(chromecast) - entity._available = True - entity.schedule_update_ha_state() + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" assert state.state == "unknown" - assert entity.unique_id == full_info.uuid + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + cast_status = MagicMock() + cast_status.volume_level = 0.5 + cast_status.volume_muted = False + cast_status_cb(cast_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("volume_level") == 0.5 + assert not state.attributes.get("is_volume_muted") + + cast_status = MagicMock() + cast_status.volume_level = 0.2 + cast_status.volume_muted = True + cast_status_cb(cast_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("volume_level") == 0.2 + assert state.attributes.get("is_volume_muted") + + +async def test_entity_play_media(hass: HomeAssistantType): + """Test playing media.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + # Play_media + await common.async_play_media(hass, "audio", "best.mp3", entity_id) + chromecast.media_controller.play_media.assert_called_once_with("best.mp3", "audio") + + +async def test_entity_play_media_cast(hass: HomeAssistantType, quick_play_mock): + """Test playing media with cast special features.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + # Play_media - cast with app ID + await common.async_play_media(hass, "cast", '{"app_id": "abc123"}', entity_id) + chromecast.start_app.assert_called_once_with("abc123") + + # Play_media - cast with app name (quick play) + await common.async_play_media(hass, "cast", '{"app_name": "youtube"}', entity_id) + quick_play_mock.assert_called_once_with(ANY, "youtube", {}) + + +async def test_entity_play_media_cast_invalid(hass, caplog, quick_play_mock): + """Test playing media.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + # play_media - media_type cast with invalid JSON + with pytest.raises(json.decoder.JSONDecodeError): + await common.async_play_media(hass, "cast", '{"app_id": "abc123"', entity_id) + assert "Invalid JSON in media_content_id" in caplog.text + chromecast.start_app.assert_not_called() + quick_play_mock.assert_not_called() + + # Play_media - media_type cast with extra keys + await common.async_play_media( + hass, "cast", '{"app_id": "abc123", "extra": "data"}', entity_id + ) + assert "Extra keys dict_keys(['extra']) were ignored" in caplog.text + chromecast.start_app.assert_called_once_with("abc123") + quick_play_mock.assert_not_called() + + # Play_media - media_type cast with unsupported app + quick_play_mock.side_effect = NotImplementedError() + await common.async_play_media(hass, "cast", '{"app_name": "unknown"}', entity_id) + quick_play_mock.assert_called_once_with(ANY, "unknown", {}) + assert "App unknown not supported" in caplog.text + + +async def test_entity_play_media_sign_URL(hass: HomeAssistantType): + """Test playing media.""" + entity_id = "media_player.speaker" + + await async_process_ha_core_config( + hass, + {"external_url": "http://example.com:8123"}, + ) + + info = get_fake_chromecast_info() + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + # Play_media + await common.async_play_media(hass, "audio", "/best.mp3", entity_id) + chromecast.media_controller.play_media.assert_called_once_with(ANY, "audio") + assert chromecast.media_controller.play_media.call_args[0][0].startswith( + "http://example.com:8123/best.mp3?authSig=" + ) + + +async def test_entity_media_content_type(hass: HomeAssistantType): + """Test various content types.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + media_status = MagicMock(images=None) + media_status.media_is_movie = False + media_status.media_is_musictrack = False + media_status.media_is_tvshow = False + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("media_content_type") is None + + media_status.media_is_tvshow = True + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("media_content_type") == "tvshow" + + media_status.media_is_tvshow = False + media_status.media_is_musictrack = True + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("media_content_type") == "music" + + media_status.media_is_musictrack = True + media_status.media_is_movie = True + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("media_content_type") == "movie" + + +async def test_entity_control(hass: HomeAssistantType): + """Test various device and media controls.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + # Turn on + await common.async_turn_on(hass, entity_id) + chromecast.play_media.assert_called_once_with( + "https://www.home-assistant.io/images/cast/splash.png", ANY + ) + chromecast.quit_app.reset_mock() + + # Turn off + await common.async_turn_off(hass, entity_id) + chromecast.quit_app.assert_called_once_with() + + # Mute + await common.async_mute_volume(hass, True, entity_id) + chromecast.set_volume_muted.assert_called_once_with(True) + + # Volume + await common.async_set_volume_level(hass, 0.33, entity_id) + chromecast.set_volume.assert_called_once_with(0.33) + + # Media play + await common.async_media_play(hass, entity_id) + chromecast.media_controller.play.assert_called_once_with() + + # Media pause + await common.async_media_pause(hass, entity_id) + chromecast.media_controller.pause.assert_called_once_with() + + # Media previous + await common.async_media_previous_track(hass, entity_id) + chromecast.media_controller.queue_prev.assert_not_called() + + # Media next + await common.async_media_next_track(hass, entity_id) + chromecast.media_controller.queue_next.assert_not_called() + + # Media seek + await common.async_media_seek(hass, 123, entity_id) + chromecast.media_controller.seek.assert_not_called() + + # Enable support for queue and seek + media_status = MagicMock(images=None) + media_status.supports_queue_next = True + media_status.supports_seek = True + media_status_cb(media_status) + await hass.async_block_till_done() + + # Media previous + await common.async_media_previous_track(hass, entity_id) + chromecast.media_controller.queue_prev.assert_called_once_with() + + # Media next + await common.async_media_next_track(hass, entity_id) + chromecast.media_controller.queue_next.assert_called_once_with() + + # Media seek + await common.async_media_seek(hass, 123, entity_id) + chromecast.media_controller.seek.assert_called_once_with(123) + + +async def test_entity_media_states(hass: HomeAssistantType): + """Test various entity media states.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) media_status = MagicMock(images=None) media_status.player_is_playing = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "playing" media_status.player_is_playing = False media_status.player_is_paused = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "paused" media_status.player_is_paused = False media_status.player_is_idle = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "idle" media_status.player_is_idle = False chromecast.is_idle = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "off" chromecast.is_idle = False - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "unknown" async def test_url_replace(hass: HomeAssistantType): """Test functionality of replacing URL for HTTPS.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + info = get_fake_chromecast_info() full_info = attr.evolve( info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID ) - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) - entity._available = True - entity.schedule_update_ha_state() + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" assert state.state == "unknown" - assert entity.unique_id == full_info.uuid + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) class FakeHTTPImage: url = "http://example.com/test.png" @@ -439,112 +819,128 @@ async def test_url_replace(hass: HomeAssistantType): media_status = MagicMock(images=[FakeHTTPImage()]) media_status.player_is_playing = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.attributes.get("entity_picture") == "//example.com/test.png" media_status.images = [FakeHTTPSImage()] - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.attributes.get("entity_picture") == "https://example.com/test.png" -async def test_group_media_states(hass: HomeAssistantType): +async def test_group_media_states(hass, mz_mock): """Test media states are read from group if entity has no state.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + info = get_fake_chromecast_info() full_info = attr.evolve( info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID ) - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb, group_media_status_cb = get_status_callbacks( + chromecast, mz_mock + ) - entity._available = True - entity.schedule_update_ha_state() + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" assert state.state == "unknown" - assert entity.unique_id == full_info.uuid + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) group_media_status = MagicMock(images=None) player_media_status = MagicMock(images=None) # Player has no state, group is playing -> Should report 'playing' group_media_status.player_is_playing = True - entity.multizone_new_media_status(str(FakeGroupUUID), group_media_status) + group_media_status_cb(str(FakeGroupUUID), group_media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "playing" # Player is paused, group is playing -> Should report 'paused' player_media_status.player_is_playing = False player_media_status.player_is_paused = True - entity.new_media_status(player_media_status) + media_status_cb(player_media_status) await hass.async_block_till_done() await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "paused" # Player is in unknown state, group is playing -> Should report 'playing' player_media_status.player_state = "UNKNOWN" - entity.new_media_status(player_media_status) + media_status_cb(player_media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "playing" -async def test_group_media_control(hass: HomeAssistantType): +async def test_group_media_control(hass, mz_mock): """Test media states are read from group if entity has no state.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + info = get_fake_chromecast_info() full_info = attr.evolve( info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID ) - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) - entity._available = True - entity.async_write_ha_state() + _, conn_status_cb, media_status_cb, group_media_status_cb = get_status_callbacks( + chromecast, mz_mock + ) - state = hass.states.get("media_player.speaker") + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" assert state.state == "unknown" - assert entity.unique_id == full_info.uuid + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) group_media_status = MagicMock(images=None) player_media_status = MagicMock(images=None) # Player has no state, group is playing -> Should forward calls to group group_media_status.player_is_playing = True - entity.multizone_new_media_status(str(FakeGroupUUID), group_media_status) - entity.media_play() - grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + group_media_status_cb(str(FakeGroupUUID), group_media_status) + await common.async_media_play(hass, entity_id) + grp_media = mz_mock.get_multizone_mediacontroller(str(FakeGroupUUID)) assert grp_media.play.called assert not chromecast.media_controller.play.called # Player is paused, group is playing -> Should not forward player_media_status.player_is_playing = False player_media_status.player_is_paused = True - entity.new_media_status(player_media_status) - entity.media_pause() - grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + media_status_cb(player_media_status) + await common.async_media_pause(hass, entity_id) + grp_media = mz_mock.get_multizone_mediacontroller(str(FakeGroupUUID)) assert not grp_media.pause.called assert chromecast.media_controller.pause.called # Player is in unknown state, group is playing -> Should forward to group player_media_status.player_state = "UNKNOWN" - entity.new_media_status(player_media_status) - entity.media_stop() - grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + media_status_cb(player_media_status) + await common.async_media_stop(hass, entity_id) + grp_media = mz_mock.get_multizone_mediacontroller(str(FakeGroupUUID)) assert grp_media.stop.called assert not chromecast.media_controller.stop.called # Verify play_media is not forwarded - entity.play_media(None, None) + await common.async_play_media(hass, "music", "best.mp3", entity_id) assert not grp_media.play_media.called assert chromecast.media_controller.play_media.called @@ -552,27 +948,28 @@ async def test_group_media_control(hass: HomeAssistantType): async def test_failed_cast_on_idle(hass, caplog): """Test no warning when unless player went idle with reason "ERROR".""" info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = False media_status.idle_reason = "ERROR" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert "Failed to cast media" not in caplog.text media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "Other" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert "Failed to cast media" not in caplog.text media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert "Failed to cast media http://example.com:8123/tts.mp3." in caplog.text @@ -586,13 +983,14 @@ async def test_failed_cast_other_url(hass, caplog): ) info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert "Failed to cast media http://example.com:8123/tts.mp3." in caplog.text @@ -608,13 +1006,14 @@ async def test_failed_cast_internal_url(hass, caplog): ) info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.local:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert ( "Failed to cast media http://example.local:8123/tts.mp3 from internal_url" in caplog.text @@ -635,13 +1034,14 @@ async def test_failed_cast_external_url(hass, caplog): ) info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert ( "Failed to cast media http://example.com:8123/tts.mp3 from external_url" in caplog.text @@ -658,13 +1058,14 @@ async def test_failed_cast_tts_base_url(hass, caplog): ) info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.local:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert ( "Failed to cast media http://example.local:8123/tts.mp3 from tts.base_url" in caplog.text @@ -675,7 +1076,7 @@ async def test_disconnect_on_stop(hass: HomeAssistantType): """Test cast device disconnects socket on stop.""" info = get_fake_chromecast_info() - chromecast, _ = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) await hass.async_block_till_done() diff --git a/tests/components/cloud/test_client.py b/tests/components/cloud/test_client.py index aaabca71885..752394b5d0f 100644 --- a/tests/components/cloud/test_client.py +++ b/tests/components/cloud/test_client.py @@ -1,4 +1,7 @@ """Test the cloud.iot module.""" +from datetime import timedelta + +import aiohttp from aiohttp import web import pytest @@ -8,10 +11,12 @@ from homeassistant.components.cloud.const import PREF_ENABLE_ALEXA, PREF_ENABLE_ from homeassistant.const import CONTENT_TYPE_JSON from homeassistant.core import State from homeassistant.setup import async_setup_component +from homeassistant.util import dt as dt_util from . import mock_cloud, mock_cloud_prefs -from tests.async_mock import AsyncMock, MagicMock, patch +from tests.async_mock import AsyncMock, MagicMock, Mock, patch +from tests.common import async_fire_time_changed from tests.components.alexa import test_smart_home as test_alexa @@ -260,3 +265,25 @@ async def test_set_username(hass): assert len(prefs.async_set_username.mock_calls) == 1 assert prefs.async_set_username.mock_calls[0][1][0] == "mock-username" + + +async def test_login_recovers_bad_internet(hass, caplog): + """Test Alexa can recover bad auth.""" + prefs = Mock( + alexa_enabled=True, + google_enabled=False, + async_set_username=AsyncMock(return_value=None), + ) + client = CloudClient(hass, prefs, None, {}, {}) + client.cloud = Mock() + client._alexa_config = Mock( + async_enable_proactive_mode=Mock(side_effect=aiohttp.ClientError) + ) + await client.logged_in() + assert len(client._alexa_config.async_enable_proactive_mode.mock_calls) == 1 + assert "Unable to activate Alexa Report State" in caplog.text + + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) + await hass.async_block_till_done() + + assert len(client._alexa_config.async_enable_proactive_mode.mock_calls) == 2 diff --git a/tests/components/cloud/test_system_health.py b/tests/components/cloud/test_system_health.py new file mode 100644 index 00000000000..b69ab462ddb --- /dev/null +++ b/tests/components/cloud/test_system_health.py @@ -0,0 +1,60 @@ +"""Test cloud system health.""" +import asyncio + +from aiohttp import ClientError + +from homeassistant.setup import async_setup_component +from homeassistant.util.dt import utcnow + +from tests.async_mock import Mock +from tests.common import get_system_health_info + + +async def test_cloud_system_health(hass, aioclient_mock): + """Test cloud system health.""" + aioclient_mock.get("https://cloud.bla.com/status", text="") + aioclient_mock.get("https://cert-server", text="") + aioclient_mock.get( + "https://cognito-idp.us-east-1.amazonaws.com/AAAA/.well-known/jwks.json", + exc=ClientError, + ) + hass.config.components.add("cloud") + assert await async_setup_component(hass, "system_health", {}) + now = utcnow() + + hass.data["cloud"] = Mock( + region="us-east-1", + user_pool_id="AAAA", + relayer="wss://cloud.bla.com/websocket_api", + acme_directory_server="https://cert-server", + is_logged_in=True, + remote=Mock(is_connected=False), + expiration_date=now, + is_connected=True, + client=Mock( + prefs=Mock( + remote_enabled=True, + alexa_enabled=True, + google_enabled=False, + ) + ), + ) + + info = await get_system_health_info(hass, "cloud") + + for key, val in info.items(): + if asyncio.iscoroutine(val): + info[key] = await val + + assert info == { + "logged_in": True, + "subscription_expiration": now, + "relayer_connected": True, + "remote_enabled": True, + "remote_connected": False, + "alexa_enabled": True, + "google_enabled": False, + "can_reach_cert_server": "ok", + "can_reach_cloud_auth": {"type": "failed", "error": "unreachable"}, + "can_reach_cloud": "ok", + } diff --git a/tests/components/color_extractor/__init__.py b/tests/components/color_extractor/__init__.py new file mode 100644 index 00000000000..94a6ae1e565 --- /dev/null +++ b/tests/components/color_extractor/__init__.py @@ -0,0 +1 @@ +"""Tests for the color_extractor component.""" diff --git a/tests/components/color_extractor/test_service.py b/tests/components/color_extractor/test_service.py new file mode 100644 index 00000000000..31b623f1c76 --- /dev/null +++ b/tests/components/color_extractor/test_service.py @@ -0,0 +1,319 @@ +"""Tests for color_extractor component service calls.""" +import base64 +import io + +import aiohttp +import pytest +from voluptuous.error import MultipleInvalid + +from homeassistant.components.color_extractor import ( + ATTR_PATH, + ATTR_URL, + DOMAIN, + SERVICE_TURN_ON, +) +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, + ATTR_BRIGHTNESS_PCT, + ATTR_RGB_COLOR, + DOMAIN as LIGHT_DOMAIN, + SERVICE_TURN_OFF as LIGHT_SERVICE_TURN_OFF, +) +from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON +from homeassistant.setup import async_setup_component +import homeassistant.util.color as color_util + +from tests.async_mock import Mock, mock_open, patch +from tests.common import load_fixture + +LIGHT_ENTITY = "light.kitchen_lights" +CLOSE_THRESHOLD = 10 + + +def _close_enough(actual_rgb, testing_rgb): + """Validate the given RGB value is in acceptable tolerance.""" + # Convert the given RGB values to hue / saturation and then back again + # as it wasn't reading the same RGB value set against it. + actual_hs = color_util.color_RGB_to_hs(*actual_rgb) + actual_rgb = color_util.color_hs_to_RGB(*actual_hs) + + testing_hs = color_util.color_RGB_to_hs(*testing_rgb) + testing_rgb = color_util.color_hs_to_RGB(*testing_hs) + + actual_red, actual_green, actual_blue = actual_rgb + testing_red, testing_green, testing_blue = testing_rgb + + r_diff = abs(actual_red - testing_red) + g_diff = abs(actual_green - testing_green) + b_diff = abs(actual_blue - testing_blue) + + return ( + r_diff <= CLOSE_THRESHOLD + and g_diff <= CLOSE_THRESHOLD + and b_diff <= CLOSE_THRESHOLD + ) + + +@pytest.fixture(autouse=True) +async def setup_light(hass): + """Configure our light component to work against for testing.""" + assert await async_setup_component( + hass, LIGHT_DOMAIN, {LIGHT_DOMAIN: {"platform": "demo"}} + ) + await hass.async_block_till_done() + + state = hass.states.get(LIGHT_ENTITY) + assert state + + # Validate starting values + assert state.state == STATE_ON + assert state.attributes.get(ATTR_BRIGHTNESS) == 180 + assert state.attributes.get(ATTR_RGB_COLOR) == (255, 63, 111) + + await hass.services.async_call( + LIGHT_DOMAIN, + LIGHT_SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: LIGHT_ENTITY}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get(LIGHT_ENTITY) + + assert state + assert state.state == STATE_OFF + + +async def test_missing_url_and_path(hass): + """Test that nothing happens when url and path are missing.""" + # Load our color_extractor component + await async_setup_component( + hass, + DOMAIN, + {}, + ) + await hass.async_block_till_done() + + # Validate pre service call + state = hass.states.get(LIGHT_ENTITY) + assert state + assert state.state == STATE_OFF + + # Missing url and path attributes, should cause error log + service_data = { + ATTR_ENTITY_ID: LIGHT_ENTITY, + } + + with pytest.raises(MultipleInvalid): + await hass.services.async_call( + DOMAIN, SERVICE_TURN_ON, service_data, blocking=True + ) + await hass.async_block_till_done() + + # check light is still off, unchanged due to bad parameters on service call + state = hass.states.get(LIGHT_ENTITY) + assert state + assert state.state == STATE_OFF + + +async def _async_load_color_extractor_url(hass, service_data): + # Load our color_extractor component + await async_setup_component( + hass, + DOMAIN, + {}, + ) + await hass.async_block_till_done() + + # Validate pre service call + state = hass.states.get(LIGHT_ENTITY) + assert state + assert state.state == STATE_OFF + + # Call the shared service, our above mock should return the base64 decoded fixture 1x1 pixel + assert await hass.services.async_call( + DOMAIN, SERVICE_TURN_ON, service_data, blocking=True + ) + + await hass.async_block_till_done() + + +async def test_url_success(hass, aioclient_mock): + """Test that a successful image GET translate to light RGB.""" + service_data = { + ATTR_URL: "http://example.com/images/logo.png", + ATTR_ENTITY_ID: LIGHT_ENTITY, + # Standard light service data which we pass + ATTR_BRIGHTNESS_PCT: 50, + } + + # Mock the HTTP Response with a base64 encoded 1x1 pixel + aioclient_mock.get( + url=service_data[ATTR_URL], + content=base64.b64decode(load_fixture("color_extractor_url.txt")), + ) + + # Allow access to this URL using the proper mechanism + hass.config.allowlist_external_urls.add("http://example.com/images/") + + await _async_load_color_extractor_url(hass, service_data) + + state = hass.states.get(LIGHT_ENTITY) + assert state + + # Ensure we turned it on + assert state.state == STATE_ON + + # Brightness has changed, optional service call field + assert state.attributes[ATTR_BRIGHTNESS] == 128 + + # Ensure the RGB values are correct + assert _close_enough(state.attributes[ATTR_RGB_COLOR], (50, 100, 150)) + + +async def test_url_not_allowed(hass, aioclient_mock): + """Test that a not allowed external URL fails to turn light on.""" + service_data = { + ATTR_URL: "http://denied.com/images/logo.png", + ATTR_ENTITY_ID: LIGHT_ENTITY, + } + + await _async_load_color_extractor_url(hass, service_data) + + # Light has not been modified due to failure + state = hass.states.get(LIGHT_ENTITY) + assert state + assert state.state == STATE_OFF + + +async def test_url_exception(hass, aioclient_mock): + """Test that a HTTPError fails to turn light on.""" + service_data = { + ATTR_URL: "http://example.com/images/logo.png", + ATTR_ENTITY_ID: LIGHT_ENTITY, + } + + # Don't let the URL not being allowed sway our exception test + hass.config.allowlist_external_urls.add("http://example.com/images/") + + # Mock the HTTP Response with an HTTPError + aioclient_mock.get(url=service_data[ATTR_URL], exc=aiohttp.ClientError) + + await _async_load_color_extractor_url(hass, service_data) + + # Light has not been modified due to failure + state = hass.states.get(LIGHT_ENTITY) + assert state + assert state.state == STATE_OFF + + +async def test_url_error(hass, aioclient_mock): + """Test that a HTTP Error (non 200) doesn't turn light on.""" + service_data = { + ATTR_URL: "http://example.com/images/logo.png", + ATTR_ENTITY_ID: LIGHT_ENTITY, + } + + # Don't let the URL not being allowed sway our exception test + hass.config.allowlist_external_urls.add("http://example.com/images/") + + # Mock the HTTP Response with a 400 Bad Request error + aioclient_mock.get(url=service_data[ATTR_URL], status=400) + + await _async_load_color_extractor_url(hass, service_data) + + # Light has not been modified due to failure + state = hass.states.get(LIGHT_ENTITY) + assert state + assert state.state == STATE_OFF + + +@patch( + "builtins.open", + mock_open(read_data=base64.b64decode(load_fixture("color_extractor_file.txt"))), + create=True, +) +def _get_file_mock(file_path): + """Convert file to BytesIO for testing due to PIL UnidentifiedImageError.""" + _file = None + + with open(file_path) as file_handler: + _file = io.BytesIO(file_handler.read()) + + _file.name = "color_extractor.jpg" + _file.seek(0) + + return _file + + +@patch("os.path.isfile", Mock(return_value=True)) +@patch("os.access", Mock(return_value=True)) +async def test_file(hass): + """Test that the file only service reads a file and translates to light RGB.""" + service_data = { + ATTR_PATH: "/opt/image.png", + ATTR_ENTITY_ID: LIGHT_ENTITY, + # Standard light service data which we pass + ATTR_BRIGHTNESS_PCT: 100, + } + + # Add our /opt/ path to the allowed list of paths + hass.config.allowlist_external_dirs.add("/opt/") + + await async_setup_component(hass, DOMAIN, {}) + await hass.async_block_till_done() + + # Verify pre service check + state = hass.states.get(LIGHT_ENTITY) + assert state + assert state.state == STATE_OFF + + # Mock the file handler read with our 1x1 base64 encoded fixture image + with patch("homeassistant.components.color_extractor._get_file", _get_file_mock): + await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, service_data) + await hass.async_block_till_done() + + state = hass.states.get(LIGHT_ENTITY) + + assert state + + # Ensure we turned it on + assert state.state == STATE_ON + + # And set the brightness + assert state.attributes[ATTR_BRIGHTNESS] == 255 + + # Ensure the RGB values are correct + assert _close_enough(state.attributes[ATTR_RGB_COLOR], (25, 75, 125)) + + +@patch("os.path.isfile", Mock(return_value=True)) +@patch("os.access", Mock(return_value=True)) +async def test_file_denied_dir(hass): + """Test that the file only service fails to read an image in a dir not explicitly allowed.""" + service_data = { + ATTR_PATH: "/path/to/a/dir/not/allowed/image.png", + ATTR_ENTITY_ID: LIGHT_ENTITY, + # Standard light service data which we pass + ATTR_BRIGHTNESS_PCT: 100, + } + + await async_setup_component(hass, DOMAIN, {}) + await hass.async_block_till_done() + + # Verify pre service check + state = hass.states.get(LIGHT_ENTITY) + assert state + assert state.state == STATE_OFF + + # Mock the file handler read with our 1x1 base64 encoded fixture image + with patch("homeassistant.components.color_extractor._get_file", _get_file_mock): + await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, service_data) + await hass.async_block_till_done() + + state = hass.states.get(LIGHT_ENTITY) + + assert state + + # Ensure it's still off due to access error (dir not explicitly allowed) + assert state.state == STATE_OFF diff --git a/tests/components/config/test_entity_registry.py b/tests/components/config/test_entity_registry.py index d63d10437cc..a506135c16d 100644 --- a/tests/components/config/test_entity_registry.py +++ b/tests/components/config/test_entity_registry.py @@ -7,7 +7,7 @@ from homeassistant.components.config import entity_registry from homeassistant.const import ATTR_ICON from homeassistant.helpers.entity_registry import RegistryEntry -from tests.common import MockEntity, MockEntityPlatform, mock_registry +from tests.common import MockConfigEntry, MockEntity, MockEntityPlatform, mock_registry @pytest.fixture @@ -39,6 +39,7 @@ async def test_list_entities(hass, client): { "config_entry_id": None, "device_id": None, + "area_id": None, "disabled_by": None, "entity_id": "test_domain.name", "name": "Hello World", @@ -48,6 +49,7 @@ async def test_list_entities(hass, client): { "config_entry_id": None, "device_id": None, + "area_id": None, "disabled_by": None, "entity_id": "test_domain.no_name", "name": None, @@ -84,6 +86,7 @@ async def test_get_entity(hass, client): assert msg["result"] == { "config_entry_id": None, "device_id": None, + "area_id": None, "disabled_by": None, "platform": "test_platform", "entity_id": "test_domain.name", @@ -107,6 +110,7 @@ async def test_get_entity(hass, client): assert msg["result"] == { "config_entry_id": None, "device_id": None, + "area_id": None, "disabled_by": None, "platform": "test_platform", "entity_id": "test_domain.no_name", @@ -143,7 +147,7 @@ async def test_update_entity(hass, client): assert state.name == "before update" assert state.attributes[ATTR_ICON] == "icon:before update" - # UPDATE NAME & ICON + # UPDATE NAME & ICON & AREA await client.send_json( { "id": 6, @@ -151,23 +155,27 @@ async def test_update_entity(hass, client): "entity_id": "test_domain.world", "name": "after update", "icon": "icon:after update", + "area_id": "mock-area-id", } ) msg = await client.receive_json() assert msg["result"] == { - "config_entry_id": None, - "device_id": None, - "disabled_by": None, - "platform": "test_platform", - "entity_id": "test_domain.world", - "name": "after update", - "icon": "icon:after update", - "original_name": None, - "original_icon": None, - "capabilities": None, - "unique_id": "1234", + "entity_entry": { + "config_entry_id": None, + "device_id": None, + "area_id": "mock-area-id", + "disabled_by": None, + "platform": "test_platform", + "entity_id": "test_domain.world", + "name": "after update", + "icon": "icon:after update", + "original_name": None, + "original_icon": None, + "capabilities": None, + "unique_id": "1234", + } } state = hass.states.get("test_domain.world") @@ -202,17 +210,75 @@ async def test_update_entity(hass, client): msg = await client.receive_json() assert msg["result"] == { - "config_entry_id": None, - "device_id": None, - "disabled_by": None, - "platform": "test_platform", - "entity_id": "test_domain.world", - "name": "after update", - "icon": "icon:after update", - "original_name": None, - "original_icon": None, - "capabilities": None, - "unique_id": "1234", + "entity_entry": { + "config_entry_id": None, + "device_id": None, + "area_id": "mock-area-id", + "disabled_by": None, + "platform": "test_platform", + "entity_id": "test_domain.world", + "name": "after update", + "icon": "icon:after update", + "original_name": None, + "original_icon": None, + "capabilities": None, + "unique_id": "1234", + }, + "reload_delay": 30, + } + + +async def test_update_entity_require_restart(hass, client): + """Test updating entity.""" + config_entry = MockConfigEntry(domain="test_platform") + config_entry.add_to_hass(hass) + mock_registry( + hass, + { + "test_domain.world": RegistryEntry( + config_entry_id=config_entry.entry_id, + entity_id="test_domain.world", + unique_id="1234", + # Using component.async_add_entities is equal to platform "domain" + platform="test_platform", + ) + }, + ) + platform = MockEntityPlatform(hass) + entity = MockEntity(unique_id="1234") + await platform.async_add_entities([entity]) + + state = hass.states.get("test_domain.world") + assert state is not None + + # UPDATE DISABLED_BY TO NONE + await client.send_json( + { + "id": 8, + "type": "config/entity_registry/update", + "entity_id": "test_domain.world", + "disabled_by": None, + } + ) + + msg = await client.receive_json() + + assert msg["result"] == { + "entity_entry": { + "config_entry_id": config_entry.entry_id, + "device_id": None, + "area_id": None, + "disabled_by": None, + "platform": "test_platform", + "entity_id": "test_domain.world", + "name": None, + "icon": None, + "original_name": None, + "original_icon": None, + "capabilities": None, + "unique_id": "1234", + }, + "require_restart": True, } @@ -250,17 +316,20 @@ async def test_update_entity_no_changes(hass, client): msg = await client.receive_json() assert msg["result"] == { - "config_entry_id": None, - "device_id": None, - "disabled_by": None, - "platform": "test_platform", - "entity_id": "test_domain.world", - "name": "name of entity", - "icon": None, - "original_name": None, - "original_icon": None, - "capabilities": None, - "unique_id": "1234", + "entity_entry": { + "config_entry_id": None, + "device_id": None, + "area_id": None, + "disabled_by": None, + "platform": "test_platform", + "entity_id": "test_domain.world", + "name": "name of entity", + "icon": None, + "original_name": None, + "original_icon": None, + "capabilities": None, + "unique_id": "1234", + } } state = hass.states.get("test_domain.world") @@ -327,23 +396,94 @@ async def test_update_entity_id(hass, client): msg = await client.receive_json() assert msg["result"] == { - "config_entry_id": None, - "device_id": None, - "disabled_by": None, - "platform": "test_platform", - "entity_id": "test_domain.planet", - "name": None, - "icon": None, - "original_name": None, - "original_icon": None, - "capabilities": None, - "unique_id": "1234", + "entity_entry": { + "config_entry_id": None, + "device_id": None, + "area_id": None, + "disabled_by": None, + "platform": "test_platform", + "entity_id": "test_domain.planet", + "name": None, + "icon": None, + "original_name": None, + "original_icon": None, + "capabilities": None, + "unique_id": "1234", + } } assert hass.states.get("test_domain.world") is None assert hass.states.get("test_domain.planet") is not None +async def test_update_existing_entity_id(hass, client): + """Test update entity id to an already registered entity id.""" + mock_registry( + hass, + { + "test_domain.world": RegistryEntry( + entity_id="test_domain.world", + unique_id="1234", + # Using component.async_add_entities is equal to platform "domain" + platform="test_platform", + ), + "test_domain.planet": RegistryEntry( + entity_id="test_domain.planet", + unique_id="2345", + # Using component.async_add_entities is equal to platform "domain" + platform="test_platform", + ), + }, + ) + platform = MockEntityPlatform(hass) + entities = [MockEntity(unique_id="1234"), MockEntity(unique_id="2345")] + await platform.async_add_entities(entities) + + await client.send_json( + { + "id": 6, + "type": "config/entity_registry/update", + "entity_id": "test_domain.world", + "new_entity_id": "test_domain.planet", + } + ) + + msg = await client.receive_json() + + assert not msg["success"] + + +async def test_update_invalid_entity_id(hass, client): + """Test update entity id to an invalid entity id.""" + mock_registry( + hass, + { + "test_domain.world": RegistryEntry( + entity_id="test_domain.world", + unique_id="1234", + # Using component.async_add_entities is equal to platform "domain" + platform="test_platform", + ) + }, + ) + platform = MockEntityPlatform(hass) + entities = [MockEntity(unique_id="1234"), MockEntity(unique_id="2345")] + await platform.async_add_entities(entities) + + await client.send_json( + { + "id": 6, + "type": "config/entity_registry/update", + "entity_id": "test_domain.world", + "new_entity_id": "another_domain.planet", + } + ) + + msg = await client.receive_json() + + assert not msg["success"] + + async def test_remove_entity(hass, client): """Test removing entity.""" registry = mock_registry( @@ -371,3 +511,20 @@ async def test_remove_entity(hass, client): assert msg["success"] assert len(registry.entities) == 0 + + +async def test_remove_non_existing_entity(hass, client): + """Test removing non existing entity.""" + mock_registry(hass, {}) + + await client.send_json( + { + "id": 6, + "type": "config/entity_registry/remove", + "entity_id": "test_domain.world", + } + ) + + msg = await client.receive_json() + + assert not msg["success"] diff --git a/tests/components/control4/test_config_flow.py b/tests/components/control4/test_config_flow.py index f87c5af3484..8c68039920d 100644 --- a/tests/components/control4/test_config_flow.py +++ b/tests/components/control4/test_config_flow.py @@ -75,6 +75,7 @@ async def test_form(hass): CONF_PASSWORD: "test-password", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "control4_model_00AA00AA00AA" @@ -84,7 +85,6 @@ async def test_form(hass): CONF_PASSWORD: "test-password", "controller_unique_id": "control4_model_00AA00AA00AA", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/coolmaster/test_config_flow.py b/tests/components/coolmaster/test_config_flow.py index b758a37db1d..27e44949585 100644 --- a/tests/components/coolmaster/test_config_flow.py +++ b/tests/components/coolmaster/test_config_flow.py @@ -32,6 +32,7 @@ async def test_form(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], _flow_data() ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "1.1.1.1" @@ -40,7 +41,6 @@ async def test_form(hass): "port": 10102, "supported_modes": AVAILABLE_MODES, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/deconz/conftest.py b/tests/components/deconz/conftest.py new file mode 100644 index 00000000000..4c45d3c912b --- /dev/null +++ b/tests/components/deconz/conftest.py @@ -0,0 +1,2 @@ +"""deconz conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/demo/conftest.py b/tests/components/demo/conftest.py new file mode 100644 index 00000000000..666224fb737 --- /dev/null +++ b/tests/components/demo/conftest.py @@ -0,0 +1,2 @@ +"""demo conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/device_tracker/test_device_trigger.py b/tests/components/device_tracker/test_device_trigger.py new file mode 100644 index 00000000000..963dae3127d --- /dev/null +++ b/tests/components/device_tracker/test_device_trigger.py @@ -0,0 +1,205 @@ +"""The tests for Device Tracker device triggers.""" +import pytest +import voluptuous_serialize + +import homeassistant.components.automation as automation +from homeassistant.components.device_tracker import DOMAIN, device_trigger +import homeassistant.components.zone as zone +from homeassistant.helpers import config_validation as cv, device_registry +from homeassistant.setup import async_setup_component + +from tests.common import ( + MockConfigEntry, + assert_lists_same, + async_get_device_automations, + async_mock_service, + mock_device_registry, + mock_registry, +) + +AWAY_LATITUDE = 32.881011 +AWAY_LONGITUDE = -117.234758 + +HOME_LATITUDE = 32.880837 +HOME_LONGITUDE = -117.237561 + + +@pytest.fixture +def device_reg(hass): + """Return an empty, loaded, registry.""" + return mock_device_registry(hass) + + +@pytest.fixture +def entity_reg(hass): + """Return an empty, loaded, registry.""" + return mock_registry(hass) + + +@pytest.fixture +def calls(hass): + """Track calls to a mock service.""" + return async_mock_service(hass, "test", "automation") + + +@pytest.fixture(autouse=True) +def setup_zone(hass): + """Create test zone.""" + hass.loop.run_until_complete( + async_setup_component( + hass, + zone.DOMAIN, + { + "zone": { + "name": "test", + "latitude": HOME_LATITUDE, + "longitude": HOME_LONGITUDE, + "radius": 250, + } + }, + ) + ) + + +async def test_get_triggers(hass, device_reg, entity_reg): + """Test we get the expected triggers from a device_tracker.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_reg.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id) + expected_triggers = [ + { + "platform": "device", + "domain": DOMAIN, + "type": "leaves", + "device_id": device_entry.id, + "entity_id": f"{DOMAIN}.test_5678", + }, + { + "platform": "device", + "domain": DOMAIN, + "type": "enters", + "device_id": device_entry.id, + "entity_id": f"{DOMAIN}.test_5678", + }, + ] + triggers = await async_get_device_automations(hass, "trigger", device_entry.id) + assert_lists_same(triggers, expected_triggers) + + +async def test_if_fires_on_zone_change(hass, calls): + """Test for enter and leave triggers firing.""" + hass.states.async_set( + "device_tracker.entity", + "state", + {"latitude": AWAY_LATITUDE, "longitude": AWAY_LONGITUDE}, + ) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": "device_tracker.entity", + "type": "enters", + "zone": "zone.test", + }, + "action": { + "service": "test.automation", + "data_template": { + "some": ( + "enter - {{ trigger.platform}} - " + "{{ trigger.entity_id}} - {{ trigger.from_state.attributes.longitude|round(3)}} - " + "{{ trigger.to_state.attributes.longitude|round(3)}}" + ) + }, + }, + }, + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": "device_tracker.entity", + "type": "leaves", + "zone": "zone.test", + }, + "action": { + "service": "test.automation", + "data_template": { + "some": ( + "leave - {{ trigger.platform}} - " + "{{ trigger.entity_id}} - {{ trigger.from_state.attributes.longitude|round(3)}} - " + "{{ trigger.to_state.attributes.longitude|round(3)}}" + ) + }, + }, + }, + ] + }, + ) + + # Fake that the entity is entering. + hass.states.async_set( + "device_tracker.entity", + "state", + {"latitude": HOME_LATITUDE, "longitude": HOME_LONGITUDE}, + ) + await hass.async_block_till_done() + assert len(calls) == 1 + assert calls[0].data["some"] == "enter - device - {} - -117.235 - -117.238".format( + "device_tracker.entity" + ) + + # Fake that the entity is leaving. + hass.states.async_set( + "device_tracker.entity", + "state", + {"latitude": AWAY_LATITUDE, "longitude": AWAY_LONGITUDE}, + ) + await hass.async_block_till_done() + assert len(calls) == 2 + assert calls[1].data["some"] == "leave - device - {} - -117.238 - -117.235".format( + "device_tracker.entity" + ) + + +async def test_get_trigger_capabilities(hass, device_reg, entity_reg): + """Test we get the expected capabilities from a device_tracker trigger.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_reg.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id) + capabilities = await device_trigger.async_get_trigger_capabilities( + hass, + { + "platform": "device", + "domain": DOMAIN, + "type": "enters", + "device_id": device_entry.id, + "entity_id": f"{DOMAIN}.test_5678", + }, + ) + assert capabilities and "extra_fields" in capabilities + + assert voluptuous_serialize.convert( + capabilities["extra_fields"], custom_serializer=cv.custom_serializer + ) == [ + { + "name": "zone", + "required": True, + "type": "select", + "options": [("zone.test", "test"), ("zone.home", "test home")], + } + ] diff --git a/tests/components/devolo_home_control/test_config_flow.py b/tests/components/devolo_home_control/test_config_flow.py index 89e87c78c64..ad99f13e8f6 100644 --- a/tests/components/devolo_home_control/test_config_flow.py +++ b/tests/components/devolo_home_control/test_config_flow.py @@ -33,17 +33,16 @@ async def test_form(hass): result["flow_id"], {"username": "test-username", "password": "test-password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "devolo Home Control" assert result2["data"] == { "username": "test-username", "password": "test-password", - "home_control_url": "https://homecontrol.mydevolo.com", "mydevolo_url": "https://www.mydevolo.com", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -114,20 +113,18 @@ async def test_form_advanced_options(hass): { "username": "test-username", "password": "test-password", - "home_control_url": "https://test_url.test", "mydevolo_url": "https://test_mydevolo_url.test", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "devolo Home Control" assert result2["data"] == { "username": "test-username", "password": "test-password", - "home_control_url": "https://test_url.test", "mydevolo_url": "https://test_mydevolo_url.test", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/dexcom/test_config_flow.py b/tests/components/dexcom/test_config_flow.py index 6f6d8abe8f9..c79e7ca0075 100644 --- a/tests/components/dexcom/test_config_flow.py +++ b/tests/components/dexcom/test_config_flow.py @@ -32,11 +32,11 @@ async def test_form(hass): result["flow_id"], CONFIG, ) + await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["title"] == CONFIG[CONF_USERNAME] assert result2["data"] == CONFIG - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/directv/test_config_flow.py b/tests/components/directv/test_config_flow.py index df3c606f687..09b76cfb550 100644 --- a/tests/components/directv/test_config_flow.py +++ b/tests/components/directv/test_config_flow.py @@ -3,7 +3,7 @@ from aiohttp import ClientError as HTTPClientError 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 0d806d668a0..b56070f0e7e 100644 --- a/tests/components/directv/test_init.py +++ b/tests/components/directv/test_init.py @@ -6,22 +6,13 @@ from homeassistant.config_entries import ( 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: diff --git a/tests/components/doorbird/test_config_flow.py b/tests/components/doorbird/test_config_flow.py index f8a01899bd5..c52388b886c 100644 --- a/tests/components/doorbird/test_config_flow.py +++ b/tests/components/doorbird/test_config_flow.py @@ -62,6 +62,7 @@ async def test_user_form(hass): result["flow_id"], VALID_CONFIG, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "1.2.3.4" @@ -71,7 +72,6 @@ async def test_user_form(hass): "password": "password", "username": "friend", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -108,6 +108,7 @@ async def test_form_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data=import_config, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "1.2.3.4" @@ -124,7 +125,6 @@ async def test_form_import(hass): # It is not possible to import options at this time # so they end up in the config entry data and are # used a fallback when they are not in options - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -176,6 +176,7 @@ async def test_form_import_with_zeroconf_already_discovered(hass): context={"source": config_entries.SOURCE_IMPORT}, data=import_config, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "1.2.3.4" @@ -192,7 +193,6 @@ async def test_form_import_with_zeroconf_already_discovered(hass): # It is not possible to import options at this time # so they end up in the config entry data and are # used a fallback when they are not in options - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -274,6 +274,7 @@ async def test_form_zeroconf_correct_oui(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], VALID_CONFIG ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "1.2.3.4" @@ -283,7 +284,6 @@ async def test_form_zeroconf_correct_oui(hass): "password": "password", "username": "friend", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/dsmr/test_config_flow.py b/tests/components/dsmr/test_config_flow.py index c6fb57c6ecb..039002ca7a7 100644 --- a/tests/components/dsmr/test_config_flow.py +++ b/tests/components/dsmr/test_config_flow.py @@ -4,7 +4,7 @@ from itertools import chain, repeat import serial -from homeassistant import config_entries, setup +from homeassistant import config_entries, data_entry_flow, setup from homeassistant.components.dsmr import DOMAIN from tests.async_mock import DEFAULT, AsyncMock, patch @@ -196,9 +196,49 @@ async def test_import_update(hass, dsmr_connection_send_validate_fixture): data=new_entry_data, ) - await hass.async_block_till_done() + await hass.async_block_till_done() assert result["type"] == "abort" assert result["reason"] == "already_configured" assert entry.data["precision"] == 3 + + +async def test_options_flow(hass): + """Test options flow.""" + await setup.async_setup_component(hass, "persistent_notification", {}) + + entry_data = { + "port": "/dev/ttyUSB0", + "dsmr_version": "2.2", + "precision": 4, + "reconnect_interval": 30, + } + + entry = MockConfigEntry( + domain=DOMAIN, + data=entry_data, + unique_id="/dev/ttyUSB0", + ) + entry.add_to_hass(hass) + + result = await hass.config_entries.options.async_init(entry.entry_id) + + assert result["type"] == "form" + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ + "time_between_update": 15, + }, + ) + + with patch( + "homeassistant.components.dsmr.async_setup_entry", return_value=True + ), patch("homeassistant.components.dsmr.async_unload_entry", return_value=True): + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + + await hass.async_block_till_done() + + assert entry.options == {"time_between_update": 15} diff --git a/tests/components/dsmr/test_sensor.py b/tests/components/dsmr/test_sensor.py index 49e9feb80f6..ceccc7d8c39 100644 --- a/tests/components/dsmr/test_sensor.py +++ b/tests/components/dsmr/test_sensor.py @@ -13,7 +13,11 @@ from itertools import chain, repeat from homeassistant.components.dsmr.const import DOMAIN from homeassistant.components.dsmr.sensor import DerivativeDSMREntity from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN -from homeassistant.const import ENERGY_KILO_WATT_HOUR, TIME_HOURS, VOLUME_CUBIC_METERS +from homeassistant.const import ( + ENERGY_KILO_WATT_HOUR, + VOLUME_CUBIC_METERS, + VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR, +) from homeassistant.setup import async_setup_component from tests.async_mock import DEFAULT, MagicMock @@ -74,6 +78,11 @@ async def test_default_setup(hass, dsmr_connection_fixture): "dsmr_version": "2.2", "precision": 4, "reconnect_interval": 30, + "serial_id": "1234", + "serial_id_gas": "5678", + } + entry_options = { + "time_between_update": 0, } telegram = { @@ -90,7 +99,7 @@ async def test_default_setup(hass, dsmr_connection_fixture): } mock_entry = MockConfigEntry( - domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data + domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data, options=entry_options ) mock_entry.add_to_hass(hass) @@ -98,6 +107,16 @@ async def test_default_setup(hass, dsmr_connection_fixture): await hass.config_entries.async_setup(mock_entry.entry_id) await hass.async_block_till_done() + registry = await hass.helpers.entity_registry.async_get_registry() + + entry = registry.async_get("sensor.power_consumption") + assert entry + assert entry.unique_id == "1234_Power_Consumption" + + entry = registry.async_get("sensor.gas_consumption") + assert entry + assert entry.unique_id == "5678_Gas_Consumption" + telegram_callback = connection_factory.call_args_list[0][0][2] # make sure entities have been created and return 'unknown' state @@ -129,13 +148,42 @@ async def test_default_setup(hass, dsmr_connection_fixture): assert gas_consumption.attributes.get("unit_of_measurement") == VOLUME_CUBIC_METERS +async def test_setup_only_energy(hass, dsmr_connection_fixture): + """Test the default setup.""" + entry_data = { + "port": "/dev/ttyUSB0", + "dsmr_version": "2.2", + "precision": 4, + "reconnect_interval": 30, + "serial_id": "1234", + } + + mock_entry = MockConfigEntry( + domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data + ) + + mock_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() + + registry = await hass.helpers.entity_registry.async_get_registry() + + entry = registry.async_get("sensor.power_consumption") + assert entry + assert entry.unique_id == "1234_Power_Consumption" + + entry = registry.async_get("sensor.gas_consumption") + assert not entry + + async def test_derivative(): """Test calculation of derivative value.""" from dsmr_parser.objects import MBusObject config = {"platform": "dsmr"} - entity = DerivativeDSMREntity("test", "1.0.0", config) + entity = DerivativeDSMREntity("test", "test_device", "5678", "1.0.0", config) await entity.async_update() assert entity.state is None, "initial state not unknown" @@ -166,7 +214,7 @@ async def test_derivative(): abs(entity.state - 0.033) < 0.00001 ), "state should be hourly usage calculated from first and second update" - assert entity.unit_of_measurement == f"{VOLUME_CUBIC_METERS}/{TIME_HOURS}" + assert entity.unit_of_measurement == VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR async def test_v4_meter(hass, dsmr_connection_fixture): @@ -184,6 +232,11 @@ async def test_v4_meter(hass, dsmr_connection_fixture): "dsmr_version": "4", "precision": 4, "reconnect_interval": 30, + "serial_id": "1234", + "serial_id_gas": "5678", + } + entry_options = { + "time_between_update": 0, } telegram = { @@ -197,7 +250,7 @@ async def test_v4_meter(hass, dsmr_connection_fixture): } mock_entry = MockConfigEntry( - domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data + domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data, options=entry_options ) mock_entry.add_to_hass(hass) @@ -239,6 +292,11 @@ async def test_v5_meter(hass, dsmr_connection_fixture): "dsmr_version": "5", "precision": 4, "reconnect_interval": 30, + "serial_id": "1234", + "serial_id_gas": "5678", + } + entry_options = { + "time_between_update": 0, } telegram = { @@ -252,7 +310,7 @@ async def test_v5_meter(hass, dsmr_connection_fixture): } mock_entry = MockConfigEntry( - domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data + domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data, options=entry_options ) mock_entry.add_to_hass(hass) @@ -294,6 +352,11 @@ async def test_belgian_meter(hass, dsmr_connection_fixture): "dsmr_version": "5B", "precision": 4, "reconnect_interval": 30, + "serial_id": "1234", + "serial_id_gas": "5678", + } + entry_options = { + "time_between_update": 0, } telegram = { @@ -307,7 +370,7 @@ async def test_belgian_meter(hass, dsmr_connection_fixture): } mock_entry = MockConfigEntry( - domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data + domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data, options=entry_options ) mock_entry.add_to_hass(hass) @@ -346,12 +409,17 @@ async def test_belgian_meter_low(hass, dsmr_connection_fixture): "dsmr_version": "5B", "precision": 4, "reconnect_interval": 30, + "serial_id": "1234", + "serial_id_gas": "5678", + } + entry_options = { + "time_between_update": 0, } telegram = {ELECTRICITY_ACTIVE_TARIFF: CosemObject([{"value": "0002", "unit": ""}])} mock_entry = MockConfigEntry( - domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data + domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data, options=entry_options ) mock_entry.add_to_hass(hass) @@ -383,6 +451,8 @@ async def test_tcp(hass, dsmr_connection_fixture): "dsmr_version": "2.2", "precision": 4, "reconnect_interval": 30, + "serial_id": "1234", + "serial_id_gas": "5678", } mock_entry = MockConfigEntry( @@ -407,6 +477,8 @@ async def test_connection_errors_retry(hass, dsmr_connection_fixture): "dsmr_version": "2.2", "precision": 4, "reconnect_interval": 0, + "serial_id": "1234", + "serial_id_gas": "5678", } # override the mock to have it fail the first time and succeed after @@ -442,6 +514,8 @@ async def test_reconnect(hass, dsmr_connection_fixture): "dsmr_version": "2.2", "precision": 4, "reconnect_interval": 0, + "serial_id": "1234", + "serial_id_gas": "5678", } # mock waiting coroutine while connection lasts diff --git a/tests/components/dynalite/conftest.py b/tests/components/dynalite/conftest.py new file mode 100644 index 00000000000..187e4f9cbaa --- /dev/null +++ b/tests/components/dynalite/conftest.py @@ -0,0 +1,2 @@ +"""dynalite conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/dyson/test_sensor.py b/tests/components/dyson/test_sensor.py index 5a6febc98cf..4acc52743bb 100644 --- a/tests/components/dyson/test_sensor.py +++ b/tests/components/dyson/test_sensor.py @@ -8,6 +8,7 @@ from libpurecool.dyson_pure_cool_link import DysonPureCoolLink from homeassistant.components import dyson as dyson_parent from homeassistant.components.dyson import sensor as dyson from homeassistant.const import ( + ATTR_UNIT_OF_MEASUREMENT, PERCENTAGE, STATE_OFF, TEMP_CELSIUS, @@ -67,6 +68,36 @@ def _get_with_state(): return device +def _get_purecool_device(): + """Return a valid device with filters life state values.""" + device = mock.Mock(spec=DysonPureCool) + load_mock_device(device) + device.name = "PureCool" + device.state.carbon_filter_state = "0096" + device.state.hepa_filter_state = "0056" + device.environmental_state.dust = 5 + device.environmental_state.humidity = 45 + device.environmental_state.temperature = 295 + device.environmental_state.volatil_organic_compounds = 2 + + return device + + +def _get_purecool_humidify_device(): + """Return a valid device with filters life state values.""" + device = mock.Mock(spec=DysonPureCool) + load_mock_device(device) + device.name = "PureCool_Humidify" + device.state.carbon_filter_state = "INV" + device.state.hepa_filter_state = "0075" + device.environmental_state.dust = 5 + device.environmental_state.humidity = 45 + device.environmental_state.temperature = 295 + device.environmental_state.volatil_organic_compounds = 2 + + return device + + def _get_with_standby_monitoring(): """Return a valid device with state but with standby monitoring disable.""" device = mock.Mock() @@ -110,7 +141,10 @@ class DysonTest(unittest.TestCase): device_fan = _get_device_without_state() device_non_fan = _get_with_state() - self.hass.data[dyson.DYSON_DEVICES] = [device_fan, device_non_fan] + self.hass.data[dyson.DYSON_DEVICES] = [ + device_fan, + device_non_fan, + ] dyson.setup_platform(self.hass, None, _add_device, mock.MagicMock()) def test_dyson_filter_life_sensor(self): @@ -272,4 +306,46 @@ async def test_purecool_component_setup_only_once(devices, login, hass): discovery.load_platform(hass, "sensor", dyson_parent.DOMAIN, {}, config) await hass.async_block_till_done() - assert len(hass.data[dyson.DYSON_SENSOR_DEVICES]) == 2 + assert len(hass.data[dyson.DYSON_SENSOR_DEVICES]) == 4 + + +@patch("libpurecool.dyson.DysonAccount.login", return_value=True) +@patch( + "libpurecool.dyson.DysonAccount.devices", + return_value=[_get_purecool_device()], +) +async def test_dyson_purecool_filter_state_sensor(devices, login, hass): + """Test filter sensor with values.""" + config = _get_config() + await async_setup_component(hass, dyson_parent.DOMAIN, config) + await hass.async_block_till_done() + + state = hass.states.get("sensor.purecool_hepa_filter_remaining_life") + assert state is not None + assert state.state == "56" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE + assert state.name == "PureCool HEPA Filter Remaining Life" + + state = hass.states.get("sensor.purecool_carbon_filter_remaining_life") + assert state is not None + assert state.state == "96" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE + assert state.name == "PureCool Carbon Filter Remaining Life" + + +@patch("libpurecool.dyson.DysonAccount.login", return_value=True) +@patch( + "libpurecool.dyson.DysonAccount.devices", + return_value=[_get_purecool_humidify_device()], +) +async def test_dyson_purecool_humidify_filter_state_sensor(devices, login, hass): + """Test filter sensor with values.""" + config = _get_config() + await async_setup_component(hass, dyson_parent.DOMAIN, config) + await hass.async_block_till_done() + + state = hass.states.get("sensor.purecool_humidify_combi_filter_remaining_life") + assert state is not None + assert state.state == "75" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE + assert state.name == "PureCool_Humidify Combi Filter Remaining Life" diff --git a/tests/components/elgato/conftest.py b/tests/components/elgato/conftest.py new file mode 100644 index 00000000000..f2ac45155fb --- /dev/null +++ b/tests/components/elgato/conftest.py @@ -0,0 +1,2 @@ +"""elgato conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/elkm1/test_config_flow.py b/tests/components/elkm1/test_config_flow.py index 0a959cf1b97..346d0b65ad2 100644 --- a/tests/components/elkm1/test_config_flow.py +++ b/tests/components/elkm1/test_config_flow.py @@ -3,14 +3,24 @@ from homeassistant import config_entries, setup from homeassistant.components.elkm1.const import DOMAIN -from tests.async_mock import AsyncMock, MagicMock, PropertyMock, patch +from tests.async_mock import MagicMock, patch def mock_elk(invalid_auth=None, sync_complete=None): """Mock m1lib Elk.""" + + def handler_callbacks(type_, callback): + nonlocal invalid_auth, sync_complete + + if type_ == "login": + if invalid_auth is not None: + callback(not invalid_auth) + elif type_ == "sync_complete": + if sync_complete: + callback() + mocked_elk = MagicMock() - type(mocked_elk).invalid_auth = PropertyMock(return_value=invalid_auth) - type(mocked_elk).sync_complete = AsyncMock() + mocked_elk.add_handler.side_effect = handler_callbacks return mocked_elk @@ -23,7 +33,7 @@ async def test_form_user_with_secure_elk(hass): assert result["type"] == "form" assert result["errors"] == {} - mocked_elk = mock_elk(invalid_auth=False) + mocked_elk = mock_elk(invalid_auth=False, sync_complete=True) with patch( "homeassistant.components.elkm1.config_flow.elkm1.Elk", @@ -45,6 +55,7 @@ async def test_form_user_with_secure_elk(hass): "prefix": "", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "ElkM1" @@ -56,7 +67,6 @@ async def test_form_user_with_secure_elk(hass): "temperature_unit": "°F", "username": "test-username", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -70,7 +80,7 @@ async def test_form_user_with_non_secure_elk(hass): assert result["type"] == "form" assert result["errors"] == {} - mocked_elk = mock_elk(invalid_auth=False) + mocked_elk = mock_elk(invalid_auth=None, sync_complete=True) with patch( "homeassistant.components.elkm1.config_flow.elkm1.Elk", @@ -90,6 +100,7 @@ async def test_form_user_with_non_secure_elk(hass): "prefix": "guest_house", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "guest_house" @@ -101,7 +112,6 @@ async def test_form_user_with_non_secure_elk(hass): "password": "", "temperature_unit": "°F", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -115,7 +125,7 @@ async def test_form_user_with_serial_elk(hass): assert result["type"] == "form" assert result["errors"] == {} - mocked_elk = mock_elk(invalid_auth=False) + mocked_elk = mock_elk(invalid_auth=None, sync_complete=True) with patch( "homeassistant.components.elkm1.config_flow.elkm1.Elk", @@ -135,6 +145,7 @@ async def test_form_user_with_serial_elk(hass): "prefix": "", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "ElkM1" @@ -146,7 +157,6 @@ async def test_form_user_with_serial_elk(hass): "password": "", "temperature_unit": "°C", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -157,15 +167,15 @@ async def test_form_cannot_connect(hass): DOMAIN, context={"source": config_entries.SOURCE_USER} ) - mocked_elk = mock_elk(invalid_auth=False) + mocked_elk = mock_elk(invalid_auth=None, sync_complete=None) with patch( "homeassistant.components.elkm1.config_flow.elkm1.Elk", return_value=mocked_elk, ), patch( - "homeassistant.components.elkm1.config_flow.async_wait_for_elk_to_sync", - return_value=False, - ): # async_wait_for_elk_to_sync is being patched to avoid making the test wait 45s + "homeassistant.components.elkm1.config_flow.VALIDATE_TIMEOUT", + 0, + ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -188,7 +198,7 @@ async def test_form_invalid_auth(hass): DOMAIN, context={"source": config_entries.SOURCE_USER} ) - mocked_elk = mock_elk(invalid_auth=True) + mocked_elk = mock_elk(invalid_auth=True, sync_complete=True) with patch( "homeassistant.components.elkm1.config_flow.elkm1.Elk", @@ -214,7 +224,7 @@ async def test_form_import(hass): """Test we get the form with import source.""" await setup.async_setup_component(hass, "persistent_notification", {}) - mocked_elk = mock_elk(invalid_auth=False) + mocked_elk = mock_elk(invalid_auth=False, sync_complete=True) with patch( "homeassistant.components.elkm1.config_flow.elkm1.Elk", return_value=mocked_elk, @@ -253,6 +263,7 @@ async def test_form_import(hass): }, }, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "ohana" @@ -274,6 +285,5 @@ async def test_form_import(hass): "username": "friend", "zone": {"enabled": True, "exclude": [[15, 15], [28, 208]], "include": []}, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/epson/__init__.py b/tests/components/epson/__init__.py new file mode 100644 index 00000000000..545400bf3e6 --- /dev/null +++ b/tests/components/epson/__init__.py @@ -0,0 +1 @@ +"""Tests for the epson integration.""" diff --git a/tests/components/epson/test_config_flow.py b/tests/components/epson/test_config_flow.py new file mode 100644 index 00000000000..6faaa285a2a --- /dev/null +++ b/tests/components/epson/test_config_flow.py @@ -0,0 +1,94 @@ +"""Test the epson config flow.""" +from homeassistant import config_entries, setup +from homeassistant.components.epson.const import DOMAIN +from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, STATE_UNAVAILABLE + +from tests.async_mock import patch + + +async def test_form(hass): + """Test we get the form.""" + await setup.async_setup_component(hass, "persistent_notification", {}) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + assert result["type"] == "form" + assert result["errors"] == {} + assert result["step_id"] == config_entries.SOURCE_USER + + with patch( + "homeassistant.components.epson.Projector.get_property", + return_value="04", + ), patch( + "homeassistant.components.epson.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.epson.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_HOST: "1.1.1.1", CONF_NAME: "test-epson", CONF_PORT: 80}, + ) + assert result2["type"] == "create_entry" + assert result2["title"] == "test-epson" + assert result2["data"] == {CONF_HOST: "1.1.1.1", CONF_PORT: 80} + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_form_cannot_connect(hass): + """Test we handle cannot connect error.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + + with patch( + "homeassistant.components.epson.Projector.get_property", + return_value=STATE_UNAVAILABLE, + ): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_HOST: "1.1.1.1", CONF_NAME: "test-epson", CONF_PORT: 80}, + ) + + assert result2["type"] == "form" + assert result2["errors"] == {"base": "cannot_connect"} + + +async def test_import(hass): + """Test config.yaml import.""" + with patch( + "homeassistant.components.epson.Projector.get_property", + return_value="04", + ), patch("homeassistant.components.epson.async_setup", return_value=True), patch( + "homeassistant.components.epson.async_setup_entry", + return_value=True, + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_IMPORT}, + data={CONF_HOST: "1.1.1.1", CONF_NAME: "test-epson", CONF_PORT: 80}, + ) + assert result["type"] == "create_entry" + assert result["title"] == "test-epson" + assert result["data"] == {CONF_HOST: "1.1.1.1", CONF_PORT: 80} + + +async def test_import_cannot_connect(hass): + """Test we handle cannot connect error with import.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_IMPORT} + ) + + with patch( + "homeassistant.components.epson.Projector.get_property", + return_value=STATE_UNAVAILABLE, + ): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_HOST: "1.1.1.1", CONF_NAME: "test-epson", CONF_PORT: 80}, + ) + + assert result2["type"] == "form" + assert result2["errors"] == {"base": "cannot_connect"} diff --git a/tests/components/everlights/conftest.py b/tests/components/everlights/conftest.py new file mode 100644 index 00000000000..31915934b31 --- /dev/null +++ b/tests/components/everlights/conftest.py @@ -0,0 +1,2 @@ +"""everlights conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/flick_electric/test_config_flow.py b/tests/components/flick_electric/test_config_flow.py index c8fe6298764..f18daed875f 100644 --- a/tests/components/flick_electric/test_config_flow.py +++ b/tests/components/flick_electric/test_config_flow.py @@ -43,11 +43,11 @@ async def test_form(hass): result["flow_id"], CONF, ) + await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["title"] == "Flick Electric: test-username" assert result2["data"] == CONF - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/flume/test_config_flow.py b/tests/components/flume/test_config_flow.py index bf95700c2de..0afea0a9742 100644 --- a/tests/components/flume/test_config_flow.py +++ b/tests/components/flume/test_config_flow.py @@ -51,6 +51,7 @@ async def test_form(hass): CONF_CLIENT_SECRET: "client_secret", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "test-username" @@ -60,7 +61,6 @@ async def test_form(hass): CONF_CLIENT_ID: "client_id", CONF_CLIENT_SECRET: "client_secret", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -92,6 +92,7 @@ async def test_form_import(hass): CONF_CLIENT_SECRET: "client_secret", }, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "test-username" @@ -101,7 +102,6 @@ async def test_form_import(hass): CONF_CLIENT_ID: "client_id", CONF_CLIENT_SECRET: "client_secret", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/flunearyou/test_config_flow.py b/tests/components/flunearyou/test_config_flow.py index a43fb7aa52f..3681768ccdf 100644 --- a/tests/components/flunearyou/test_config_flow.py +++ b/tests/components/flunearyou/test_config_flow.py @@ -3,7 +3,7 @@ from pyflunearyou.errors import FluNearYouError 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"} diff --git a/tests/components/gree/test_init.py b/tests/components/gree/test_init.py index 1ea0727b220..ef693c9538a 100644 --- a/tests/components/gree/test_init.py +++ b/tests/components/gree/test_init.py @@ -8,7 +8,7 @@ from tests.async_mock import patch from tests.common import MockConfigEntry -async def test_setup_simple(hass): +async def test_setup_simple(hass, discovery, device): """Test gree integration is setup.""" await async_setup_component(hass, GREE_DOMAIN, {}) await hass.async_block_till_done() @@ -17,7 +17,7 @@ async def test_setup_simple(hass): assert len(hass.config_entries.flow.async_progress()) == 0 -async def test_unload_config_entry(hass): +async def test_unload_config_entry(hass, discovery, device): """Test that the async_unload_entry works.""" # As we have currently no configuration, we just to pass the domain here. entry = MockConfigEntry(domain=GREE_DOMAIN) diff --git a/tests/components/griddy/test_config_flow.py b/tests/components/griddy/test_config_flow.py index 309864dbc11..0b2656dcf09 100644 --- a/tests/components/griddy/test_config_flow.py +++ b/tests/components/griddy/test_config_flow.py @@ -29,11 +29,11 @@ async def test_form(hass): result["flow_id"], {"loadzone": "LZ_HOUSTON"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Load Zone LZ_HOUSTON" assert result2["data"] == {"loadzone": "LZ_HOUSTON"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/group/conftest.py b/tests/components/group/conftest.py new file mode 100644 index 00000000000..6fe34aca91c --- /dev/null +++ b/tests/components/group/conftest.py @@ -0,0 +1,2 @@ +"""group conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/group/test_init.py b/tests/components/group/test_init.py index 0004719b28d..77f137c6ee1 100644 --- a/tests/components/group/test_init.py +++ b/tests/components/group/test_init.py @@ -1,7 +1,6 @@ """The tests for the Group components.""" # pylint: disable=protected-access from collections import OrderedDict -import unittest import homeassistant.components.group as group from homeassistant.const import ( @@ -18,307 +17,375 @@ from homeassistant.const import ( ) from homeassistant.core import CoreState from homeassistant.helpers.event import TRACK_STATE_CHANGE_CALLBACKS -from homeassistant.setup import async_setup_component, setup_component +from homeassistant.setup import async_setup_component from tests.async_mock import patch -from tests.common import assert_setup_component, get_test_home_assistant +from tests.common import assert_setup_component from tests.components.group import common -class TestComponentsGroup(unittest.TestCase): - """Test Group component.""" +async def test_setup_group_with_mixed_groupable_states(hass): + """Try to set up a group with mixed groupable states.""" - # pylint: disable=invalid-name - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - for domain in ["device_tracker", "light", "group", "sensor"]: - setup_component(self.hass, domain, {}) - self.addCleanup(self.hass.stop) + hass.states.async_set("light.Bowl", STATE_ON) + hass.states.async_set("device_tracker.Paulus", STATE_HOME) - def test_setup_group_with_mixed_groupable_states(self): - """Try to set up a group with mixed groupable states.""" - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.states.set("device_tracker.Paulus", STATE_HOME) - group.Group.create_group( - self.hass, "person_and_light", ["light.Bowl", "device_tracker.Paulus"] - ) + assert await async_setup_component(hass, "group", {}) - assert ( - STATE_ON == self.hass.states.get(f"{group.DOMAIN}.person_and_light").state - ) + await group.Group.async_create_group( + hass, "person_and_light", ["light.Bowl", "device_tracker.Paulus"] + ) - def test_setup_group_with_a_non_existing_state(self): - """Try to set up a group with a non existing state.""" - self.hass.states.set("light.Bowl", STATE_ON) + await hass.async_block_till_done() - grp = group.Group.create_group( - self.hass, "light_and_nothing", ["light.Bowl", "non.existing"] - ) + assert STATE_ON == hass.states.get(f"{group.DOMAIN}.person_and_light").state - assert STATE_ON == grp.state - def test_setup_group_with_non_groupable_states(self): - """Test setup with groups which are not groupable.""" - self.hass.states.set("cast.living_room", "Plex") - self.hass.states.set("cast.bedroom", "Netflix") +async def test_setup_group_with_a_non_existing_state(hass): + """Try to set up a group with a non existing state.""" + hass.states.async_set("light.Bowl", STATE_ON) - grp = group.Group.create_group( - self.hass, "chromecasts", ["cast.living_room", "cast.bedroom"] - ) + assert await async_setup_component(hass, "group", {}) - assert grp.state is None + grp = await group.Group.async_create_group( + hass, "light_and_nothing", ["light.Bowl", "non.existing"] + ) - def test_setup_empty_group(self): - """Try to set up an empty group.""" - grp = group.Group.create_group(self.hass, "nothing", []) + assert STATE_ON == grp.state - assert grp.state is None - def test_monitor_group(self): - """Test if the group keeps track of states.""" - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling"], False - ) +async def test_setup_group_with_non_groupable_states(hass): + """Test setup with groups which are not groupable.""" + hass.states.async_set("cast.living_room", "Plex") + hass.states.async_set("cast.bedroom", "Netflix") - # Test if group setup in our init mode is ok - assert test_group.entity_id in self.hass.states.entity_ids() + assert await async_setup_component(hass, "group", {}) - group_state = self.hass.states.get(test_group.entity_id) - assert STATE_ON == group_state.state - assert group_state.attributes.get(group.ATTR_AUTO) + grp = await group.Group.async_create_group( + hass, "chromecasts", ["cast.living_room", "cast.bedroom"] + ) - def test_group_turns_off_if_all_off(self): - """Test if turn off if the last device that was on turns off.""" - self.hass.states.set("light.Bowl", STATE_OFF) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling"], False - ) + assert grp.state is None - self.hass.block_till_done() - group_state = self.hass.states.get(test_group.entity_id) - assert STATE_OFF == group_state.state +async def test_setup_empty_group(hass): + """Try to set up an empty group.""" + grp = await group.Group.async_create_group(hass, "nothing", []) - def test_group_turns_on_if_all_are_off_and_one_turns_on(self): - """Test if turn on if all devices were turned off and one turns on.""" - self.hass.states.set("light.Bowl", STATE_OFF) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling"], False - ) + assert grp.state is None - # Turn one on - self.hass.states.set("light.Ceiling", STATE_ON) - self.hass.block_till_done() - group_state = self.hass.states.get(test_group.entity_id) - assert STATE_ON == group_state.state +async def test_monitor_group(hass): + """Test if the group keeps track of states.""" + hass.states.async_set("light.Bowl", STATE_ON) + hass.states.async_set("light.Ceiling", STATE_OFF) - def test_allgroup_stays_off_if_all_are_off_and_one_turns_on(self): - """Group with all: true, stay off if one device turns on.""" - self.hass.states.set("light.Bowl", STATE_OFF) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling"], False, mode=True - ) + assert await async_setup_component(hass, "group", {}) - # Turn one on - self.hass.states.set("light.Ceiling", STATE_ON) - self.hass.block_till_done() + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling"], False + ) - group_state = self.hass.states.get(test_group.entity_id) - assert STATE_OFF == group_state.state + # Test if group setup in our init mode is ok + assert test_group.entity_id in hass.states.async_entity_ids() - def test_allgroup_turn_on_if_last_turns_on(self): - """Group with all: true, turn on if all devices are on.""" - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling"], False, mode=True - ) + group_state = hass.states.get(test_group.entity_id) + assert STATE_ON == group_state.state + assert group_state.attributes.get(group.ATTR_AUTO) - # Turn one on - self.hass.states.set("light.Ceiling", STATE_ON) - self.hass.block_till_done() - group_state = self.hass.states.get(test_group.entity_id) - assert STATE_ON == group_state.state +async def test_group_turns_off_if_all_off(hass): + """Test if turn off if the last device that was on turns off.""" + hass.states.async_set("light.Bowl", STATE_OFF) + hass.states.async_set("light.Ceiling", STATE_OFF) - def test_expand_entity_ids(self): - """Test expand_entity_ids method.""" - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling"], False - ) + assert await async_setup_component(hass, "group", {}) - assert sorted(["light.ceiling", "light.bowl"]) == sorted( - group.expand_entity_ids(self.hass, [test_group.entity_id]) - ) + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling"], False + ) - def test_expand_entity_ids_does_not_return_duplicates(self): - """Test that expand_entity_ids does not return duplicates.""" - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling"], False - ) + await hass.async_block_till_done() - assert ["light.bowl", "light.ceiling"] == sorted( - group.expand_entity_ids(self.hass, [test_group.entity_id, "light.Ceiling"]) - ) + group_state = hass.states.get(test_group.entity_id) + assert STATE_OFF == group_state.state - assert ["light.bowl", "light.ceiling"] == sorted( - group.expand_entity_ids(self.hass, ["light.bowl", test_group.entity_id]) - ) - def test_expand_entity_ids_recursive(self): - """Test expand_entity_ids method with a group that contains itself.""" - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, - "init_group", - ["light.Bowl", "light.Ceiling", "group.init_group"], - False, - ) +async def test_group_turns_on_if_all_are_off_and_one_turns_on(hass): + """Test if turn on if all devices were turned off and one turns on.""" + hass.states.async_set("light.Bowl", STATE_OFF) + hass.states.async_set("light.Ceiling", STATE_OFF) - assert sorted(["light.ceiling", "light.bowl"]) == sorted( - group.expand_entity_ids(self.hass, [test_group.entity_id]) - ) + assert await async_setup_component(hass, "group", {}) - def test_expand_entity_ids_ignores_non_strings(self): - """Test that non string elements in lists are ignored.""" - assert [] == group.expand_entity_ids(self.hass, [5, True]) + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling"], False + ) - def test_get_entity_ids(self): - """Test get_entity_ids method.""" - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling"], False - ) + # Turn one on + hass.states.async_set("light.Ceiling", STATE_ON) + await hass.async_block_till_done() - assert ["light.bowl", "light.ceiling"] == sorted( - group.get_entity_ids(self.hass, test_group.entity_id) - ) + group_state = hass.states.get(test_group.entity_id) + assert STATE_ON == group_state.state - def test_get_entity_ids_with_domain_filter(self): - """Test if get_entity_ids works with a domain_filter.""" - self.hass.states.set("switch.AC", STATE_OFF) - mixed_group = group.Group.create_group( - self.hass, "mixed_group", ["light.Bowl", "switch.AC"], False - ) +async def test_allgroup_stays_off_if_all_are_off_and_one_turns_on(hass): + """Group with all: true, stay off if one device turns on.""" + hass.states.async_set("light.Bowl", STATE_OFF) + hass.states.async_set("light.Ceiling", STATE_OFF) - assert ["switch.ac"] == group.get_entity_ids( - self.hass, mixed_group.entity_id, domain_filter="switch" - ) + assert await async_setup_component(hass, "group", {}) - def test_get_entity_ids_with_non_existing_group_name(self): - """Test get_entity_ids with a non existing group.""" - assert [] == group.get_entity_ids(self.hass, "non_existing") + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling"], False, mode=True + ) - def test_get_entity_ids_with_non_group_state(self): - """Test get_entity_ids with a non group state.""" - assert [] == group.get_entity_ids(self.hass, "switch.AC") + # Turn one on + hass.states.async_set("light.Ceiling", STATE_ON) + await hass.async_block_till_done() - def test_group_being_init_before_first_tracked_state_is_set_to_on(self): - """Test if the groups turn on. + group_state = hass.states.get(test_group.entity_id) + assert STATE_OFF == group_state.state - If no states existed and now a state it is tracking is being added - as ON. - """ - test_group = group.Group.create_group( - self.hass, "test group", ["light.not_there_1"] - ) - self.hass.states.set("light.not_there_1", STATE_ON) +async def test_allgroup_turn_on_if_last_turns_on(hass): + """Group with all: true, turn on if all devices are on.""" + hass.states.async_set("light.Bowl", STATE_ON) + hass.states.async_set("light.Ceiling", STATE_OFF) - self.hass.block_till_done() + assert await async_setup_component(hass, "group", {}) - group_state = self.hass.states.get(test_group.entity_id) - assert STATE_ON == group_state.state + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling"], False, mode=True + ) - def test_group_being_init_before_first_tracked_state_is_set_to_off(self): - """Test if the group turns off. + # Turn one on + hass.states.async_set("light.Ceiling", STATE_ON) + await hass.async_block_till_done() - If no states existed and now a state it is tracking is being added - as OFF. - """ - test_group = group.Group.create_group( - self.hass, "test group", ["light.not_there_1"] - ) + group_state = hass.states.get(test_group.entity_id) + assert STATE_ON == group_state.state - self.hass.states.set("light.not_there_1", STATE_OFF) - self.hass.block_till_done() +async def test_expand_entity_ids(hass): + """Test expand_entity_ids method.""" + hass.states.async_set("light.Bowl", STATE_ON) + hass.states.async_set("light.Ceiling", STATE_OFF) - group_state = self.hass.states.get(test_group.entity_id) - assert STATE_OFF == group_state.state + assert await async_setup_component(hass, "group", {}) - def test_groups_get_unique_names(self): - """Two groups with same name should both have a unique entity id.""" - grp1 = group.Group.create_group(self.hass, "Je suis Charlie") - grp2 = group.Group.create_group(self.hass, "Je suis Charlie") + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling"], False + ) - assert grp1.entity_id != grp2.entity_id + assert sorted(["light.ceiling", "light.bowl"]) == sorted( + group.expand_entity_ids(hass, [test_group.entity_id]) + ) - def test_expand_entity_ids_expands_nested_groups(self): - """Test if entity ids epands to nested groups.""" - group.Group.create_group(self.hass, "light", ["light.test_1", "light.test_2"]) - group.Group.create_group( - self.hass, "switch", ["switch.test_1", "switch.test_2"] - ) - group.Group.create_group( - self.hass, "group_of_groups", ["group.light", "group.switch"] - ) - assert [ - "light.test_1", - "light.test_2", - "switch.test_1", - "switch.test_2", - ] == sorted(group.expand_entity_ids(self.hass, ["group.group_of_groups"])) +async def test_expand_entity_ids_does_not_return_duplicates(hass): + """Test that expand_entity_ids does not return duplicates.""" + hass.states.async_set("light.Bowl", STATE_ON) + hass.states.async_set("light.Ceiling", STATE_OFF) - def test_set_assumed_state_based_on_tracked(self): - """Test assumed state.""" - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.states.set("light.Ceiling", STATE_OFF) - test_group = group.Group.create_group( - self.hass, "init_group", ["light.Bowl", "light.Ceiling", "sensor.no_exist"] - ) + assert await async_setup_component(hass, "group", {}) - state = self.hass.states.get(test_group.entity_id) - assert not state.attributes.get(ATTR_ASSUMED_STATE) + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling"], False + ) - self.hass.states.set("light.Bowl", STATE_ON, {ATTR_ASSUMED_STATE: True}) - self.hass.block_till_done() + assert ["light.bowl", "light.ceiling"] == sorted( + group.expand_entity_ids(hass, [test_group.entity_id, "light.Ceiling"]) + ) - state = self.hass.states.get(test_group.entity_id) - assert state.attributes.get(ATTR_ASSUMED_STATE) + assert ["light.bowl", "light.ceiling"] == sorted( + group.expand_entity_ids(hass, ["light.bowl", test_group.entity_id]) + ) - self.hass.states.set("light.Bowl", STATE_ON) - self.hass.block_till_done() - state = self.hass.states.get(test_group.entity_id) - assert not state.attributes.get(ATTR_ASSUMED_STATE) +async def test_expand_entity_ids_recursive(hass): + """Test expand_entity_ids method with a group that contains itself.""" + hass.states.async_set("light.Bowl", STATE_ON) + hass.states.async_set("light.Ceiling", STATE_OFF) - def test_group_updated_after_device_tracker_zone_change(self): - """Test group state when device tracker in group changes zone.""" - self.hass.states.set("device_tracker.Adam", STATE_HOME) - self.hass.states.set("device_tracker.Eve", STATE_NOT_HOME) - self.hass.block_till_done() - group.Group.create_group( - self.hass, "peeps", ["device_tracker.Adam", "device_tracker.Eve"] - ) - self.hass.states.set("device_tracker.Adam", "cool_state_not_home") - self.hass.block_till_done() - assert STATE_NOT_HOME == self.hass.states.get(f"{group.DOMAIN}.peeps").state + assert await async_setup_component(hass, "group", {}) + + test_group = await group.Group.async_create_group( + hass, + "init_group", + ["light.Bowl", "light.Ceiling", "group.init_group"], + False, + ) + + assert sorted(["light.ceiling", "light.bowl"]) == sorted( + group.expand_entity_ids(hass, [test_group.entity_id]) + ) + + +async def test_expand_entity_ids_ignores_non_strings(hass): + """Test that non string elements in lists are ignored.""" + assert [] == group.expand_entity_ids(hass, [5, True]) + + +async def test_get_entity_ids(hass): + """Test get_entity_ids method.""" + hass.states.async_set("light.Bowl", STATE_ON) + hass.states.async_set("light.Ceiling", STATE_OFF) + + assert await async_setup_component(hass, "group", {}) + + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling"], False + ) + + assert ["light.bowl", "light.ceiling"] == sorted( + group.get_entity_ids(hass, test_group.entity_id) + ) + + +async def test_get_entity_ids_with_domain_filter(hass): + """Test if get_entity_ids works with a domain_filter.""" + hass.states.async_set("switch.AC", STATE_OFF) + + assert await async_setup_component(hass, "group", {}) + + mixed_group = await group.Group.async_create_group( + hass, "mixed_group", ["light.Bowl", "switch.AC"], False + ) + + assert ["switch.ac"] == group.get_entity_ids( + hass, mixed_group.entity_id, domain_filter="switch" + ) + + +async def test_get_entity_ids_with_non_existing_group_name(hass): + """Test get_entity_ids with a non existing group.""" + assert [] == group.get_entity_ids(hass, "non_existing") + + +async def test_get_entity_ids_with_non_group_state(hass): + """Test get_entity_ids with a non group state.""" + assert [] == group.get_entity_ids(hass, "switch.AC") + + +async def test_group_being_init_before_first_tracked_state_is_set_to_on(hass): + """Test if the groups turn on. + + If no states existed and now a state it is tracking is being added + as ON. + """ + + assert await async_setup_component(hass, "group", {}) + + test_group = await group.Group.async_create_group( + hass, "test group", ["light.not_there_1"] + ) + + hass.states.async_set("light.not_there_1", STATE_ON) + + await hass.async_block_till_done() + + group_state = hass.states.get(test_group.entity_id) + assert STATE_ON == group_state.state + + +async def test_group_being_init_before_first_tracked_state_is_set_to_off(hass): + """Test if the group turns off. + + If no states existed and now a state it is tracking is being added + as OFF. + """ + assert await async_setup_component(hass, "group", {}) + test_group = await group.Group.async_create_group( + hass, "test group", ["light.not_there_1"] + ) + + hass.states.async_set("light.not_there_1", STATE_OFF) + + await hass.async_block_till_done() + + group_state = hass.states.get(test_group.entity_id) + assert STATE_OFF == group_state.state + + +async def test_groups_get_unique_names(hass): + """Two groups with same name should both have a unique entity id.""" + + assert await async_setup_component(hass, "group", {}) + + grp1 = await group.Group.async_create_group(hass, "Je suis Charlie") + grp2 = await group.Group.async_create_group(hass, "Je suis Charlie") + + assert grp1.entity_id != grp2.entity_id + + +async def test_expand_entity_ids_expands_nested_groups(hass): + """Test if entity ids epands to nested groups.""" + + assert await async_setup_component(hass, "group", {}) + + await group.Group.async_create_group( + hass, "light", ["light.test_1", "light.test_2"] + ) + await group.Group.async_create_group( + hass, "switch", ["switch.test_1", "switch.test_2"] + ) + await group.Group.async_create_group( + hass, "group_of_groups", ["group.light", "group.switch"] + ) + + assert [ + "light.test_1", + "light.test_2", + "switch.test_1", + "switch.test_2", + ] == sorted(group.expand_entity_ids(hass, ["group.group_of_groups"])) + + +async def test_set_assumed_state_based_on_tracked(hass): + """Test assumed state.""" + hass.states.async_set("light.Bowl", STATE_ON) + hass.states.async_set("light.Ceiling", STATE_OFF) + + assert await async_setup_component(hass, "group", {}) + + test_group = await group.Group.async_create_group( + hass, "init_group", ["light.Bowl", "light.Ceiling", "sensor.no_exist"] + ) + + state = hass.states.get(test_group.entity_id) + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + hass.states.async_set("light.Bowl", STATE_ON, {ATTR_ASSUMED_STATE: True}) + await hass.async_block_till_done() + + state = hass.states.get(test_group.entity_id) + assert state.attributes.get(ATTR_ASSUMED_STATE) + + hass.states.async_set("light.Bowl", STATE_ON) + await hass.async_block_till_done() + + state = hass.states.get(test_group.entity_id) + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + +async def test_group_updated_after_device_tracker_zone_change(hass): + """Test group state when device tracker in group changes zone.""" + hass.states.async_set("device_tracker.Adam", STATE_HOME) + hass.states.async_set("device_tracker.Eve", STATE_NOT_HOME) + await hass.async_block_till_done() + + assert await async_setup_component(hass, "group", {}) + assert await async_setup_component(hass, "device_tracker", {}) + + await group.Group.async_create_group( + hass, "peeps", ["device_tracker.Adam", "device_tracker.Eve"] + ) + + hass.states.async_set("device_tracker.Adam", "cool_state_not_home") + await hass.async_block_till_done() + assert STATE_NOT_HOME == hass.states.get(f"{group.DOMAIN}.peeps").state async def test_is_on(hass): diff --git a/tests/components/group/test_notify.py b/tests/components/group/test_notify.py index 62b395dcf4d..05a23fa4e7a 100644 --- a/tests/components/group/test_notify.py +++ b/tests/components/group/test_notify.py @@ -1,98 +1,83 @@ """The tests for the notify.group platform.""" -import asyncio from os import path -import unittest from homeassistant import config as hass_config import homeassistant.components.demo.notify as demo from homeassistant.components.group import SERVICE_RELOAD import homeassistant.components.group.notify as group import homeassistant.components.notify as notify -from homeassistant.setup import async_setup_component, setup_component +from homeassistant.setup import async_setup_component from tests.async_mock import MagicMock, patch -from tests.common import assert_setup_component, get_test_home_assistant -class TestNotifyGroup(unittest.TestCase): - """Test the notify.group platform.""" +async def test_send_message_with_data(hass): + """Test sending a message with to a notify group.""" + service1 = demo.DemoNotificationService(hass) + service2 = demo.DemoNotificationService(hass) - def setUp(self): # pylint: disable=invalid-name - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.events = [] - self.service1 = demo.DemoNotificationService(self.hass) - self.service2 = demo.DemoNotificationService(self.hass) + service1.send_message = MagicMock(autospec=True) + service2.send_message = MagicMock(autospec=True) - self.service1.send_message = MagicMock(autospec=True) - self.service2.send_message = MagicMock(autospec=True) + def mock_get_service(hass, config, discovery_info=None): + if config["name"] == "demo1": + return service1 + return service2 - def mock_get_service(hass, config, discovery_info=None): - if config["name"] == "demo1": - return self.service1 - return self.service2 + assert await async_setup_component( + hass, + "group", + {}, + ) + await hass.async_block_till_done() - with assert_setup_component(2, notify.DOMAIN), patch.object( - demo, "get_service", mock_get_service - ): - setup_component( - self.hass, - notify.DOMAIN, + with patch.object(demo, "get_service", mock_get_service): + await async_setup_component( + hass, + notify.DOMAIN, + { + "notify": [ + {"name": "demo1", "platform": "demo"}, + {"name": "demo2", "platform": "demo"}, + ] + }, + ) + await hass.async_block_till_done() + + service = await group.async_get_service( + hass, + { + "services": [ + {"service": "demo1"}, { - "notify": [ - {"name": "demo1", "platform": "demo"}, - {"name": "demo2", "platform": "demo"}, - ] + "service": "demo2", + "data": { + "target": "unnamed device", + "data": {"test": "message"}, + }, }, - ) + ] + }, + ) - self.service = asyncio.run_coroutine_threadsafe( - group.async_get_service( - self.hass, - { - "services": [ - {"service": "demo1"}, - { - "service": "demo2", - "data": { - "target": "unnamed device", - "data": {"test": "message"}, - }, - }, - ] - }, - ), - self.hass.loop, - ).result() + """Test sending a message with to a notify group.""" + await service.async_send_message( + "Hello", title="Test notification", data={"hello": "world"} + ) - assert self.service is not None - self.addCleanup(self.tear_down_cleanup) + await hass.async_block_till_done() - def tear_down_cleanup(self): - """Stop everything that was started.""" - self.hass.stop() - - def test_send_message_with_data(self): - """Test sending a message with to a notify group.""" - asyncio.run_coroutine_threadsafe( - self.service.async_send_message( - "Hello", title="Test notification", data={"hello": "world"} - ), - self.hass.loop, - ).result() - self.hass.block_till_done() - - assert self.service1.send_message.mock_calls[0][1][0] == "Hello" - assert self.service1.send_message.mock_calls[0][2] == { - "title": "Test notification", - "data": {"hello": "world"}, - } - assert self.service2.send_message.mock_calls[0][1][0] == "Hello" - assert self.service2.send_message.mock_calls[0][2] == { - "target": ["unnamed device"], - "title": "Test notification", - "data": {"hello": "world", "test": "message"}, - } + assert service1.send_message.mock_calls[0][1][0] == "Hello" + assert service1.send_message.mock_calls[0][2] == { + "title": "Test notification", + "data": {"hello": "world"}, + } + assert service2.send_message.mock_calls[0][1][0] == "Hello" + assert service2.send_message.mock_calls[0][2] == { + "target": ["unnamed device"], + "title": "Test notification", + "data": {"hello": "world", "test": "message"}, + } async def test_reload_notify(hass): diff --git a/tests/components/harmony/test_config_flow.py b/tests/components/harmony/test_config_flow.py index d6bd4022d9e..994188eb62a 100644 --- a/tests/components/harmony/test_config_flow.py +++ b/tests/components/harmony/test_config_flow.py @@ -56,11 +56,11 @@ async def test_user_form(hass): result["flow_id"], {"host": "1.2.3.4", "name": "friend"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "friend" assert result2["data"] == {"host": "1.2.3.4", "name": "friend"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -90,6 +90,7 @@ async def test_form_import(hass): "unique_id": "555234534543", }, ) + await hass.async_block_till_done() assert result["result"].unique_id == "555234534543" assert result["type"] == "create_entry" @@ -103,7 +104,6 @@ async def test_form_import(hass): # It is not possible to import options at this time # so they end up in the config entry data and are # used a fallback when they are not in options - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -147,11 +147,11 @@ async def test_form_ssdp(hass): result["flow_id"], {}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Harmony Hub" assert result2["data"] == {"host": "192.168.1.12", "name": "Harmony Hub"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/hassio/test_handler.py b/tests/components/hassio/test_handler.py index 311fc6c7e8c..33fb00b4485 100644 --- a/tests/components/hassio/test_handler.py +++ b/tests/components/hassio/test_handler.py @@ -80,6 +80,39 @@ async def test_api_host_info(hassio_handler, aioclient_mock): assert data["operating_system"] == "Debian GNU/Linux 10 (buster)" +async def test_api_supervisor_info(hassio_handler, aioclient_mock): + """Test setup with API Supervisor info.""" + aioclient_mock.get( + "http://127.0.0.1/supervisor/info", + json={ + "result": "ok", + "data": {"supported": True, "version": "2020.11.1", "channel": "stable"}, + }, + ) + + data = await hassio_handler.get_supervisor_info() + assert aioclient_mock.call_count == 1 + assert data["supported"] + assert data["version"] == "2020.11.1" + assert data["channel"] == "stable" + + +async def test_api_os_info(hassio_handler, aioclient_mock): + """Test setup with API OS info.""" + aioclient_mock.get( + "http://127.0.0.1/os/info", + json={ + "result": "ok", + "data": {"board": "odroid-n2", "version": "2020.11.1"}, + }, + ) + + data = await hassio_handler.get_os_info() + assert aioclient_mock.call_count == 1 + assert data["board"] == "odroid-n2" + assert data["version"] == "2020.11.1" + + async def test_api_host_info_error(hassio_handler, aioclient_mock): """Test setup with API Home Assistant info error.""" aioclient_mock.get( diff --git a/tests/components/hassio/test_init.py b/tests/components/hassio/test_init.py index 62b4a4adbd2..214551bc3b7 100644 --- a/tests/components/hassio/test_init.py +++ b/tests/components/hassio/test_init.py @@ -44,6 +44,14 @@ def mock_all(aioclient_mock): "http://127.0.0.1/core/info", json={"result": "ok", "data": {"version_latest": "1.0.0"}}, ) + aioclient_mock.get( + "http://127.0.0.1/os/info", + json={"result": "ok", "data": {"version_latest": "1.0.0"}}, + ) + aioclient_mock.get( + "http://127.0.0.1/supervisor/info", + json={"result": "ok", "data": {"version_latest": "1.0.0"}}, + ) aioclient_mock.get( "http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}} ) @@ -55,7 +63,7 @@ async def test_setup_api_ping(hass, aioclient_mock): result = await async_setup_component(hass, "hassio", {}) assert result - assert aioclient_mock.call_count == 7 + assert aioclient_mock.call_count == 9 assert hass.components.hassio.get_core_info()["version_latest"] == "1.0.0" assert hass.components.hassio.is_hassio() @@ -94,7 +102,7 @@ async def test_setup_api_push_api_data(hass, aioclient_mock): ) assert result - assert aioclient_mock.call_count == 7 + assert aioclient_mock.call_count == 9 assert not aioclient_mock.mock_calls[1][2]["ssl"] assert aioclient_mock.mock_calls[1][2]["port"] == 9999 assert aioclient_mock.mock_calls[1][2]["watchdog"] @@ -110,7 +118,7 @@ async def test_setup_api_push_api_data_server_host(hass, aioclient_mock): ) assert result - assert aioclient_mock.call_count == 7 + assert aioclient_mock.call_count == 9 assert not aioclient_mock.mock_calls[1][2]["ssl"] assert aioclient_mock.mock_calls[1][2]["port"] == 9999 assert not aioclient_mock.mock_calls[1][2]["watchdog"] @@ -122,7 +130,7 @@ async def test_setup_api_push_api_data_default(hass, aioclient_mock, hass_storag result = await async_setup_component(hass, "hassio", {"http": {}, "hassio": {}}) assert result - assert aioclient_mock.call_count == 7 + assert aioclient_mock.call_count == 9 assert not aioclient_mock.mock_calls[1][2]["ssl"] assert aioclient_mock.mock_calls[1][2]["port"] == 8123 refresh_token = aioclient_mock.mock_calls[1][2]["refresh_token"] @@ -169,7 +177,7 @@ async def test_setup_api_existing_hassio_user(hass, aioclient_mock, hass_storage result = await async_setup_component(hass, "hassio", {"http": {}, "hassio": {}}) assert result - assert aioclient_mock.call_count == 7 + assert aioclient_mock.call_count == 9 assert not aioclient_mock.mock_calls[1][2]["ssl"] assert aioclient_mock.mock_calls[1][2]["port"] == 8123 assert aioclient_mock.mock_calls[1][2]["refresh_token"] == token.token @@ -183,7 +191,7 @@ async def test_setup_core_push_timezone(hass, aioclient_mock): result = await async_setup_component(hass, "hassio", {"hassio": {}}) assert result - assert aioclient_mock.call_count == 7 + assert aioclient_mock.call_count == 9 assert aioclient_mock.mock_calls[2][2]["timezone"] == "testzone" with patch("homeassistant.util.dt.set_default_time_zone"): @@ -200,7 +208,7 @@ async def test_setup_hassio_no_additional_data(hass, aioclient_mock): result = await async_setup_component(hass, "hassio", {"hassio": {}}) assert result - assert aioclient_mock.call_count == 7 + assert aioclient_mock.call_count == 9 assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456" diff --git a/tests/components/hassio/test_system_health.py b/tests/components/hassio/test_system_health.py new file mode 100644 index 00000000000..cd6cb2d939f --- /dev/null +++ b/tests/components/hassio/test_system_health.py @@ -0,0 +1,113 @@ +"""Test hassio system health.""" +import asyncio +import os + +from aiohttp import ClientError + +from homeassistant.setup import async_setup_component + +from .test_init import MOCK_ENVIRON + +from tests.async_mock import patch +from tests.common import get_system_health_info + + +async def test_hassio_system_health(hass, aioclient_mock): + """Test hassio system health.""" + aioclient_mock.get("http://127.0.0.1/info", json={"result": "ok", "data": {}}) + aioclient_mock.get("http://127.0.0.1/host/info", json={"result": "ok", "data": {}}) + aioclient_mock.get("http://127.0.0.1/os/info", json={"result": "ok", "data": {}}) + aioclient_mock.get("http://127.0.0.1/supervisor/ping", text="") + aioclient_mock.get("https://version.home-assistant.io/stable.json", text="") + aioclient_mock.get( + "http://127.0.0.1/supervisor/info", json={"result": "ok", "data": {}} + ) + + hass.config.components.add("hassio") + with patch.dict(os.environ, MOCK_ENVIRON): + assert await async_setup_component(hass, "system_health", {}) + + hass.data["hassio_info"] = { + "channel": "stable", + "supervisor": "2020.11.1", + "docker": "19.0.3", + "hassos": True, + } + hass.data["hassio_host_info"] = { + "operating_system": "Home Assistant OS 5.9", + "disk_total": "32.0", + "disk_used": "30.0", + } + hass.data["hassio_os_info"] = {"board": "odroid-n2"} + hass.data["hassio_supervisor_info"] = { + "healthy": True, + "supported": True, + "addons": [{"name": "Awesome Addon", "version": "1.0.0"}], + } + + info = await get_system_health_info(hass, "hassio") + + for key, val in info.items(): + if asyncio.iscoroutine(val): + info[key] = await val + + assert info == { + "board": "odroid-n2", + "disk_total": "32.0 GB", + "disk_used": "30.0 GB", + "docker_version": "19.0.3", + "healthy": True, + "host_os": "Home Assistant OS 5.9", + "installed_addons": "Awesome Addon (1.0.0)", + "supervisor_api": "ok", + "supervisor_version": "2020.11.1", + "supported": True, + "update_channel": "stable", + "version_api": "ok", + } + + +async def test_hassio_system_health_with_issues(hass, aioclient_mock): + """Test hassio system health.""" + aioclient_mock.get("http://127.0.0.1/info", json={"result": "ok", "data": {}}) + aioclient_mock.get("http://127.0.0.1/host/info", json={"result": "ok", "data": {}}) + aioclient_mock.get("http://127.0.0.1/os/info", json={"result": "ok", "data": {}}) + aioclient_mock.get("http://127.0.0.1/supervisor/ping", text="") + aioclient_mock.get("https://version.home-assistant.io/stable.json", exc=ClientError) + aioclient_mock.get( + "http://127.0.0.1/supervisor/info", json={"result": "ok", "data": {}} + ) + + hass.config.components.add("hassio") + with patch.dict(os.environ, MOCK_ENVIRON): + assert await async_setup_component(hass, "system_health", {}) + + hass.data["hassio_info"] = {"channel": "stable"} + hass.data["hassio_host_info"] = {} + hass.data["hassio_os_info"] = {} + hass.data["hassio_supervisor_info"] = { + "healthy": False, + "supported": False, + } + + info = await get_system_health_info(hass, "hassio") + + for key, val in info.items(): + if asyncio.iscoroutine(val): + info[key] = await val + + assert info["healthy"] == { + "error": "Unhealthy", + "more_info": "/hassio/system", + "type": "failed", + } + assert info["supported"] == { + "error": "Unsupported", + "more_info": "/hassio/system", + "type": "failed", + } + assert info["version_api"] == { + "error": "unreachable", + "more_info": "/hassio/system", + "type": "failed", + } diff --git a/tests/components/hlk_sw16/test_config_flow.py b/tests/components/hlk_sw16/test_config_flow.py index 7b7468047be..ea637c805cd 100644 --- a/tests/components/hlk_sw16/test_config_flow.py +++ b/tests/components/hlk_sw16/test_config_flow.py @@ -77,6 +77,7 @@ async def test_form(hass): result["flow_id"], conf, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "127.0.0.1:8080" @@ -84,7 +85,6 @@ async def test_form(hass): "host": "127.0.0.1", "port": 8080, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -139,6 +139,7 @@ async def test_import(hass): result["flow_id"], conf, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "127.0.0.1:8080" @@ -146,7 +147,6 @@ async def test_import(hass): "host": "127.0.0.1", "port": 8080, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/homeassistant/triggers/test_time.py b/tests/components/homeassistant/triggers/test_time.py index 91fd57beed3..673d0231912 100644 --- a/tests/components/homeassistant/triggers/test_time.py +++ b/tests/components/homeassistant/triggers/test_time.py @@ -3,8 +3,8 @@ from datetime import timedelta import pytest -import homeassistant.components.automation as automation -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF +from homeassistant.components import automation, sensor +from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, SERVICE_TURN_OFF from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util @@ -391,3 +391,104 @@ async def test_untrack_time_change(hass): ) assert len(mock_track_time_change.mock_calls) == 3 + + +async def test_if_fires_using_at_sensor(hass, calls): + """Test for firing at sensor time.""" + now = dt_util.now() + + trigger_dt = now.replace(hour=5, minute=0, second=0, microsecond=0) + timedelta(2) + + hass.states.async_set( + "sensor.next_alarm", + trigger_dt.isoformat(), + {ATTR_DEVICE_CLASS: sensor.DEVICE_CLASS_TIMESTAMP}, + ) + + time_that_will_not_match_right_away = trigger_dt - timedelta(minutes=1) + + some_data = "{{ trigger.platform }}-{{ trigger.now.day }}-{{ trigger.now.hour }}-{{trigger.entity_id}}" + with patch( + "homeassistant.util.dt.utcnow", + return_value=dt_util.as_utc(time_that_will_not_match_right_away), + ): + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: { + "trigger": {"platform": "time", "at": "sensor.next_alarm"}, + "action": { + "service": "test.automation", + "data_template": {"some": some_data}, + }, + } + }, + ) + await hass.async_block_till_done() + + async_fire_time_changed(hass, trigger_dt + timedelta(seconds=1)) + await hass.async_block_till_done() + + assert len(calls) == 1 + assert ( + calls[0].data["some"] + == f"time-{trigger_dt.day}-{trigger_dt.hour}-sensor.next_alarm" + ) + + trigger_dt += timedelta(days=1, hours=1) + + hass.states.async_set( + "sensor.next_alarm", + trigger_dt.isoformat(), + {ATTR_DEVICE_CLASS: sensor.DEVICE_CLASS_TIMESTAMP}, + ) + await hass.async_block_till_done() + + async_fire_time_changed(hass, trigger_dt + timedelta(seconds=1)) + await hass.async_block_till_done() + + assert len(calls) == 2 + assert ( + calls[1].data["some"] + == f"time-{trigger_dt.day}-{trigger_dt.hour}-sensor.next_alarm" + ) + + for broken in ("unknown", "unavailable", "invalid-ts"): + hass.states.async_set( + "sensor.next_alarm", + trigger_dt.isoformat(), + {ATTR_DEVICE_CLASS: sensor.DEVICE_CLASS_TIMESTAMP}, + ) + await hass.async_block_till_done() + hass.states.async_set( + "sensor.next_alarm", + broken, + {ATTR_DEVICE_CLASS: sensor.DEVICE_CLASS_TIMESTAMP}, + ) + await hass.async_block_till_done() + + async_fire_time_changed(hass, trigger_dt + timedelta(seconds=1)) + await hass.async_block_till_done() + + # We should not have listened to anything + assert len(calls) == 2 + + # Now without device class + hass.states.async_set( + "sensor.next_alarm", + trigger_dt.isoformat(), + {ATTR_DEVICE_CLASS: sensor.DEVICE_CLASS_TIMESTAMP}, + ) + await hass.async_block_till_done() + hass.states.async_set( + "sensor.next_alarm", + trigger_dt.isoformat(), + ) + await hass.async_block_till_done() + + async_fire_time_changed(hass, trigger_dt + timedelta(seconds=1)) + await hass.async_block_till_done() + + # We should not have listened to anything + assert len(calls) == 2 diff --git a/tests/components/homekit/test_config_flow.py b/tests/components/homekit/test_config_flow.py index e161d746c3c..60dc293c4fd 100644 --- a/tests/components/homekit/test_config_flow.py +++ b/tests/components/homekit/test_config_flow.py @@ -62,6 +62,7 @@ async def test_user_form(hass): result["flow_id"], {}, ) + await hass.async_block_till_done() assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result3["title"][:11] == "HASS Bridge" @@ -77,7 +78,6 @@ async def test_user_form(hass): "name": bridge_name, "port": 12345, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -111,6 +111,7 @@ async def test_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data={CONF_NAME: "othername", CONF_PORT: 56789}, ) + await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["title"] == "othername:56789" @@ -118,7 +119,6 @@ async def test_import(hass): "name": "othername", "port": 56789, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 2 diff --git a/tests/components/homekit/test_homekit.py b/tests/components/homekit/test_homekit.py index ccf1749636e..8b79c3f6c58 100644 --- a/tests/components/homekit/test_homekit.py +++ b/tests/components/homekit/test_homekit.py @@ -747,7 +747,7 @@ async def test_homekit_too_many_accessories(hass, hk_driver, caplog): ): await homekit.async_start() await hass.async_block_till_done() - assert "would exceeded" in caplog.text + assert "would exceed" in caplog.text async def test_homekit_finds_linked_batteries( diff --git a/tests/components/homekit/test_type_covers.py b/tests/components/homekit/test_type_covers.py index cd193b61646..48b20e8e0b8 100644 --- a/tests/components/homekit/test_type_covers.py +++ b/tests/components/homekit/test_type_covers.py @@ -14,7 +14,9 @@ from homeassistant.components.cover import ( SUPPORT_STOP, ) from homeassistant.components.homekit.const import ( + ATTR_OBSTRUCTION_DETECTED, ATTR_VALUE, + CONF_LINKED_OBSTRUCTION_SENSOR, HK_DOOR_CLOSED, HK_DOOR_CLOSING, HK_DOOR_OPEN, @@ -27,6 +29,8 @@ from homeassistant.const import ( SERVICE_SET_COVER_TILT_POSITION, STATE_CLOSED, STATE_CLOSING, + STATE_OFF, + STATE_ON, STATE_OPEN, STATE_OPENING, STATE_UNAVAILABLE, @@ -76,20 +80,25 @@ async def test_garage_door_open_close(hass, hk_driver, cls, events): assert acc.char_current_state.value == HK_DOOR_OPEN assert acc.char_target_state.value == HK_DOOR_OPEN - hass.states.async_set(entity_id, STATE_CLOSED) + hass.states.async_set(entity_id, STATE_CLOSED, {ATTR_OBSTRUCTION_DETECTED: False}) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_CLOSED assert acc.char_target_state.value == HK_DOOR_CLOSED + assert acc.char_obstruction_detected.value is False - hass.states.async_set(entity_id, STATE_OPEN) + hass.states.async_set(entity_id, STATE_OPEN, {ATTR_OBSTRUCTION_DETECTED: True}) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_OPEN assert acc.char_target_state.value == HK_DOOR_OPEN + assert acc.char_obstruction_detected.value is True - hass.states.async_set(entity_id, STATE_UNAVAILABLE) + hass.states.async_set( + entity_id, STATE_UNAVAILABLE, {ATTR_OBSTRUCTION_DETECTED: False} + ) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_OPEN assert acc.char_target_state.value == HK_DOOR_OPEN + assert acc.char_obstruction_detected.value is False hass.states.async_set(entity_id, STATE_UNKNOWN) await hass.async_block_till_done() @@ -528,3 +537,53 @@ async def test_windowcovering_restore(hass, hk_driver, cls, events): assert acc.char_current_position is not None assert acc.char_target_position is not None assert acc.char_position_state is not None + + +async def test_garage_door_with_linked_obstruction_sensor(hass, hk_driver, cls, events): + """Test if accessory and HA are updated accordingly with a linked obstruction sensor.""" + linked_obstruction_sensor_entity_id = "binary_sensor.obstruction" + entity_id = "cover.garage_door" + + hass.states.async_set(linked_obstruction_sensor_entity_id, STATE_OFF) + hass.states.async_set(entity_id, None) + await hass.async_block_till_done() + acc = cls.garage( + hass, + hk_driver, + "Garage Door", + entity_id, + 2, + {CONF_LINKED_OBSTRUCTION_SENSOR: linked_obstruction_sensor_entity_id}, + ) + await acc.run_handler() + await hass.async_block_till_done() + + assert acc.aid == 2 + assert acc.category == 4 # GarageDoorOpener + + assert acc.char_current_state.value == HK_DOOR_OPEN + assert acc.char_target_state.value == HK_DOOR_OPEN + + hass.states.async_set(entity_id, STATE_CLOSED) + await hass.async_block_till_done() + assert acc.char_current_state.value == HK_DOOR_CLOSED + assert acc.char_target_state.value == HK_DOOR_CLOSED + assert acc.char_obstruction_detected.value is False + + hass.states.async_set(entity_id, STATE_OPEN) + hass.states.async_set(linked_obstruction_sensor_entity_id, STATE_ON) + await hass.async_block_till_done() + assert acc.char_current_state.value == HK_DOOR_OPEN + assert acc.char_target_state.value == HK_DOOR_OPEN + assert acc.char_obstruction_detected.value is True + + hass.states.async_set(entity_id, STATE_CLOSED) + hass.states.async_set(linked_obstruction_sensor_entity_id, STATE_OFF) + await hass.async_block_till_done() + assert acc.char_current_state.value == HK_DOOR_CLOSED + assert acc.char_target_state.value == HK_DOOR_CLOSED + assert acc.char_obstruction_detected.value is False + + hass.states.async_remove(entity_id) + hass.states.async_remove(linked_obstruction_sensor_entity_id) + await hass.async_block_till_done() diff --git a/tests/components/homekit_controller/conftest.py b/tests/components/homekit_controller/conftest.py index 3b023e0da51..cb75fc205e2 100644 --- a/tests/components/homekit_controller/conftest.py +++ b/tests/components/homekit_controller/conftest.py @@ -8,13 +8,14 @@ import pytest import homeassistant.util.dt as dt_util import tests.async_mock +from tests.components.light.conftest import mock_light_profiles # noqa @pytest.fixture def utcnow(request): """Freeze time at a known point.""" now = dt_util.utcnow() - start_dt = datetime.datetime(now.year + 1, 1, 1, 0, 0, 0) + start_dt = datetime.datetime(now.year + 1, 1, 1, 0, 0, 0, tzinfo=now.tzinfo) with mock.patch("homeassistant.util.dt.utcnow") as dt_utcnow: dt_utcnow.return_value = start_dt yield dt_utcnow diff --git a/tests/components/homematicip_cloud/conftest.py b/tests/components/homematicip_cloud/conftest.py index 3ada7e7de0a..9764ee74e22 100644 --- a/tests/components/homematicip_cloud/conftest.py +++ b/tests/components/homematicip_cloud/conftest.py @@ -24,6 +24,7 @@ from .helper import AUTH_TOKEN, HAPID, HAPPIN, HomeFactory from tests.async_mock import AsyncMock, MagicMock, Mock, patch from tests.common import MockConfigEntry +from tests.components.light.conftest import mock_light_profiles # noqa @pytest.fixture(name="mock_connection") @@ -55,7 +56,7 @@ def hmip_config_entry_fixture() -> config_entries.ConfigEntry: config_entry = MockConfigEntry( version=1, domain=HMIPC_DOMAIN, - title=HAPID, + title="Home Test SN", unique_id=HAPID, data=entry_data, source=SOURCE_IMPORT, diff --git a/tests/components/homematicip_cloud/helper.py b/tests/components/homematicip_cloud/helper.py index dbbf0249c0c..ca7d8862756 100644 --- a/tests/components/homematicip_cloud/helper.py +++ b/tests/components/homematicip_cloud/helper.py @@ -136,9 +136,9 @@ class HomeTemplate(Home): def __init__(self, connection=None, home_name="", test_devices=[], test_groups=[]): """Init template with connection.""" super().__init__(connection=connection) - self.label = "Access Point" self.name = home_name - self.model_type = "HmIP-HAP" + self.label = "Home" + self.model_type = "HomematicIP Home" self.init_json_state = None self.test_devices = test_devices self.test_groups = test_groups @@ -196,7 +196,7 @@ class HomeTemplate(Home): and sets required attributes. """ mock_home = Mock( - spec=AsyncHome, wraps=self, label="Access Point", modelType="HmIP-HAP" + spec=AsyncHome, wraps=self, label="Home", modelType="HomematicIP Home" ) mock_home.__dict__.update(self.__dict__) diff --git a/tests/components/homematicip_cloud/test_binary_sensor.py b/tests/components/homematicip_cloud/test_binary_sensor.py index 6d6ba84e243..420977cd40c 100644 --- a/tests/components/homematicip_cloud/test_binary_sensor.py +++ b/tests/components/homematicip_cloud/test_binary_sensor.py @@ -38,12 +38,10 @@ async def test_manually_configured_platform(hass): assert not hass.data.get(HMIPC_DOMAIN) -async def test_hmip_access_point_cloud_connection_sensor( - hass, default_mock_hap_factory -): +async def test_hmip_home_cloud_connection_sensor(hass, default_mock_hap_factory): """Test HomematicipCloudConnectionSensor.""" - entity_id = "binary_sensor.access_point_cloud_connection" - entity_name = "Access Point Cloud Connection" + entity_id = "binary_sensor.cloud_connection" + entity_name = "Cloud Connection" device_model = None mock_hap = await default_mock_hap_factory.async_get_mock_hap( test_devices=[entity_name] @@ -55,7 +53,7 @@ async def test_hmip_access_point_cloud_connection_sensor( assert ha_state.state == STATE_ON - await async_manipulate_test_data(hass, hmip_device, "connected", False) + await async_manipulate_test_data(hass, mock_hap.home, "connected", False) ha_state = hass.states.get(entity_id) assert ha_state.state == STATE_OFF @@ -540,3 +538,28 @@ async def test_hmip_security_sensor_group(hass, default_mock_hap_factory): ) ha_state = hass.states.get(entity_id) assert ha_state.state == STATE_ON + + +async def test_hmip_wired_multi_contact_interface(hass, default_mock_hap_factory): + """Test HomematicipMultiContactInterface.""" + entity_id = "binary_sensor.wired_eingangsmodul_32_fach_channel5" + entity_name = "Wired Eingangsmodul – 32-fach Channel5" + device_model = "HmIPW-DRI32" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=["Wired Eingangsmodul – 32-fach"] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + + assert ha_state.state == STATE_OFF + await async_manipulate_test_data( + hass, hmip_device, "windowState", WindowState.OPEN, channel=5 + ) + ha_state = hass.states.get(entity_id) + assert ha_state.state == STATE_ON + + await async_manipulate_test_data(hass, hmip_device, "windowState", None, channel=5) + ha_state = hass.states.get(entity_id) + assert ha_state.state == STATE_OFF diff --git a/tests/components/homematicip_cloud/test_device.py b/tests/components/homematicip_cloud/test_device.py index c47f0bf25ea..31e62a1a719 100644 --- a/tests/components/homematicip_cloud/test_device.py +++ b/tests/components/homematicip_cloud/test_device.py @@ -22,7 +22,7 @@ async def test_hmip_load_all_supported_devices(hass, default_mock_hap_factory): test_devices=None, test_groups=None ) - assert len(mock_hap.hmip_device_by_entity_id) == 192 + assert len(mock_hap.hmip_device_by_entity_id) == 233 async def test_hmip_remove_device(hass, default_mock_hap_factory): @@ -240,3 +240,32 @@ async def test_hmip_reset_energy_counter_services(hass, default_mock_hap_factory ) assert hmip_device.mock_calls[-1][0] == "reset_energy_counter" assert len(hmip_device._connection.mock_calls) == 4 # pylint: disable=W0212 + + +async def test_hmip_multi_area_device(hass, default_mock_hap_factory): + """Test multi area device. Check if devices are created and referenced.""" + entity_id = "binary_sensor.wired_eingangsmodul_32_fach_channel5" + entity_name = "Wired Eingangsmodul – 32-fach Channel5" + device_model = "HmIPW-DRI32" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=["Wired Eingangsmodul – 32-fach"] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + assert ha_state + + # get the entity + entity_registry = await er.async_get_registry(hass) + entity = entity_registry.async_get(ha_state.entity_id) + assert entity + + # get the device + device_registry = await dr.async_get_registry(hass) + device = device_registry.async_get(entity.device_id) + assert device.name == "Wired Eingangsmodul – 32-fach" + + # get the hap + hap_device = device_registry.async_get(device.via_device_id) + assert hap_device.name == "Home" diff --git a/tests/components/homematicip_cloud/test_init.py b/tests/components/homematicip_cloud/test_init.py index 37b293a3452..46059f12d00 100644 --- a/tests/components/homematicip_cloud/test_init.py +++ b/tests/components/homematicip_cloud/test_init.py @@ -145,6 +145,7 @@ async def test_unload_entry(hass): instance.home.id = "1" instance.home.modelType = "mock-type" instance.home.name = "mock-name" + instance.home.label = "mock-label" instance.home.currentAPVersion = "mock-ap-version" instance.async_reset = AsyncMock(return_value=True) @@ -158,7 +159,7 @@ async def test_unload_entry(hass): assert config_entries[0].state == ENTRY_STATE_LOADED await hass.config_entries.async_unload(config_entries[0].entry_id) assert config_entries[0].state == ENTRY_STATE_NOT_LOADED - assert mock_hap.return_value.mock_calls[3][0] == "async_reset" + assert mock_hap.return_value.mock_calls[2][0] == "async_reset" # entry is unloaded assert hass.data[HMIPC_DOMAIN] == {} @@ -187,6 +188,7 @@ async def test_setup_services_and_unload_services(hass): instance.home.id = "1" instance.home.modelType = "mock-type" instance.home.name = "mock-name" + instance.home.label = "mock-label" instance.home.currentAPVersion = "mock-ap-version" instance.async_reset = AsyncMock(return_value=True) @@ -220,6 +222,7 @@ async def test_setup_two_haps_unload_one_by_one(hass): instance.home.id = "1" instance.home.modelType = "mock-type" instance.home.name = "mock-name" + instance.home.label = "mock-label" instance.home.currentAPVersion = "mock-ap-version" instance.async_reset = AsyncMock(return_value=True) diff --git a/tests/components/homematicip_cloud/test_sensor.py b/tests/components/homematicip_cloud/test_sensor.py index 20c5c41a5b5..34c119595b3 100644 --- a/tests/components/homematicip_cloud/test_sensor.py +++ b/tests/components/homematicip_cloud/test_sensor.py @@ -46,11 +46,11 @@ async def test_manually_configured_platform(hass): async def test_hmip_accesspoint_status(hass, default_mock_hap_factory): """Test HomematicipSwitch.""" - entity_id = "sensor.access_point_duty_cycle" - entity_name = "Access Point Duty Cycle" - device_model = None + entity_id = "sensor.home_control_access_point_duty_cycle" + entity_name = "HOME_CONTROL_ACCESS_POINT Duty Cycle" + device_model = "HmIP-HAP" mock_hap = await default_mock_hap_factory.async_get_mock_hap( - test_devices=[entity_name] + test_devices=["HOME_CONTROL_ACCESS_POINT"] ) ha_state, hmip_device = get_and_check_entity_basics( @@ -60,11 +60,6 @@ async def test_hmip_accesspoint_status(hass, default_mock_hap_factory): assert ha_state.state == "8.0" assert ha_state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE - await async_manipulate_test_data(hass, hmip_device, "dutyCycle", 17.3) - - ha_state = hass.states.get(entity_id) - assert ha_state.state == "17.3" - async def test_hmip_heating_thermostat(hass, default_mock_hap_factory): """Test HomematicipHeatingThermostat.""" diff --git a/tests/components/homematicip_cloud/test_switch.py b/tests/components/homematicip_cloud/test_switch.py index 85bfaaa4ec5..034ca33aece 100644 --- a/tests/components/homematicip_cloud/test_switch.py +++ b/tests/components/homematicip_cloud/test_switch.py @@ -220,3 +220,42 @@ async def test_hmip_multi_switch(hass, default_mock_hap_factory): await async_manipulate_test_data(hass, hmip_device, "on", False) ha_state = hass.states.get(entity_id) assert ha_state.state == STATE_OFF + + +async def test_hmip_wired_multi_switch(hass, default_mock_hap_factory): + """Test HomematicipMultiSwitch.""" + entity_id = "switch.fernseher_wohnzimmer" + entity_name = "Fernseher (Wohnzimmer)" + device_model = "HmIPW-DRS8" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=[ + "Wired Schaltaktor – 8-fach", + ] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + + assert ha_state.state == STATE_ON + service_call_counter = len(hmip_device.mock_calls) + + await hass.services.async_call( + "switch", "turn_off", {"entity_id": entity_id}, blocking=True + ) + assert len(hmip_device.mock_calls) == service_call_counter + 1 + assert hmip_device.mock_calls[-1][0] == "turn_off" + assert hmip_device.mock_calls[-1][1] == (1,) + await async_manipulate_test_data(hass, hmip_device, "on", False) + ha_state = hass.states.get(entity_id) + assert ha_state.state == STATE_OFF + + await hass.services.async_call( + "switch", "turn_on", {"entity_id": entity_id}, blocking=True + ) + assert len(hmip_device.mock_calls) == service_call_counter + 3 + assert hmip_device.mock_calls[-1][0] == "turn_on" + assert hmip_device.mock_calls[-1][1] == (1,) + await async_manipulate_test_data(hass, hmip_device, "on", True) + ha_state = hass.states.get(entity_id) + assert ha_state.state == STATE_ON diff --git a/tests/components/hue/conftest.py b/tests/components/hue/conftest.py index 094378f47c9..55b6443bdfa 100644 --- a/tests/components/hue/conftest.py +++ b/tests/components/hue/conftest.py @@ -12,6 +12,7 @@ from homeassistant.components import hue from homeassistant.components.hue import sensor_base as hue_sensor_base from tests.async_mock import AsyncMock, Mock, patch +from tests.components.light.conftest import mock_light_profiles # noqa @pytest.fixture(autouse=True) diff --git a/tests/components/hunterdouglas_powerview/test_config_flow.py b/tests/components/hunterdouglas_powerview/test_config_flow.py index 37fb150ddf7..84457a14a5e 100644 --- a/tests/components/hunterdouglas_powerview/test_config_flow.py +++ b/tests/components/hunterdouglas_powerview/test_config_flow.py @@ -46,13 +46,13 @@ async def test_user_form(hass): result["flow_id"], {"host": "1.2.3.4"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "AlexanderHD" assert result2["data"] == { "host": "1.2.3.4", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -89,13 +89,13 @@ async def test_form_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data={"host": "1.2.3.4"}, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "AlexanderHD" assert result["data"] == { "host": "1.2.3.4", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -141,13 +141,13 @@ async def test_form_homekit(hass): return_value=True, ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "PowerViewHub" assert result2["data"] == {"host": "1.2.3.4"} assert result2["result"].unique_id == "ABC123" - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/hyperion/conftest.py b/tests/components/hyperion/conftest.py new file mode 100644 index 00000000000..4eb59770fae --- /dev/null +++ b/tests/components/hyperion/conftest.py @@ -0,0 +1,2 @@ +"""hyperion conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/insteon/test_config_flow.py b/tests/components/insteon/test_config_flow.py index f4a3806a891..4e060b0d840 100644 --- a/tests/components/insteon/test_config_flow.py +++ b/tests/components/insteon/test_config_flow.py @@ -88,6 +88,7 @@ async def _device_form(hass, flow_id, connection, user_input): return_value=True, ) as mock_setup_entry: result = await hass.config_entries.flow.async_configure(flow_id, user_input) + await hass.async_block_till_done() return result, mock_setup, mock_setup_entry @@ -130,7 +131,6 @@ async def test_form_select_plm(hass: HomeAssistantType): assert result2["type"] == "create_entry" assert result2["data"] == MOCK_USER_INPUT_PLM - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -149,7 +149,6 @@ async def test_form_select_hub_v1(hass: HomeAssistantType): CONF_HUB_VERSION: 1, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -168,7 +167,6 @@ async def test_form_select_hub_v2(hass: HomeAssistantType): CONF_HUB_VERSION: 2, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/ipma/test_config_flow.py b/tests/components/ipma/test_config_flow.py index b45c4e89529..98c1667b2f6 100644 --- a/tests/components/ipma/test_config_flow.py +++ b/tests/components/ipma/test_config_flow.py @@ -1,9 +1,14 @@ """Tests for IPMA config flow.""" -from homeassistant.components.ipma import config_flow -from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE +from homeassistant.components.ipma import DOMAIN, config_flow +from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE +from homeassistant.helpers import entity_registry +from homeassistant.setup import async_setup_component + +from .test_weather import MockLocation from tests.async_mock import Mock, patch +from tests.common import MockConfigEntry, mock_registry async def test_show_config_form(): @@ -116,3 +121,53 @@ async def test_flow_entry_config_entry_already_exists(): assert len(config_form.mock_calls) == 1 assert len(config_entries.mock_calls) == 1 assert len(flow._errors) == 1 + + +async def test_config_entry_migration(hass): + """Tests config entry without mode in unique_id can be migrated.""" + ipma_entry = MockConfigEntry( + domain=DOMAIN, + title="Home", + data={CONF_LATITUDE: 0, CONF_LONGITUDE: 0, CONF_MODE: "daily"}, + ) + ipma_entry.add_to_hass(hass) + + ipma_entry2 = MockConfigEntry( + domain=DOMAIN, + title="Home", + data={CONF_LATITUDE: 0, CONF_LONGITUDE: 0, CONF_MODE: "hourly"}, + ) + ipma_entry2.add_to_hass(hass) + + mock_registry( + hass, + { + "weather.hometown": entity_registry.RegistryEntry( + entity_id="weather.hometown", + unique_id="0, 0", + platform="ipma", + config_entry_id=ipma_entry.entry_id, + ), + "weather.hometown_2": entity_registry.RegistryEntry( + entity_id="weather.hometown_2", + unique_id="0, 0, hourly", + platform="ipma", + config_entry_id=ipma_entry.entry_id, + ), + }, + ) + + with patch( + "homeassistant.components.ipma.weather.async_get_location", + return_value=MockLocation(), + ): + assert await async_setup_component(hass, DOMAIN, {}) + await hass.async_block_till_done() + + ent_reg = await entity_registry.async_get_registry(hass) + + weather_home = ent_reg.async_get("weather.hometown") + assert weather_home.unique_id == "0, 0, daily" + + weather_home2 = ent_reg.async_get("weather.hometown_2") + assert weather_home2.unique_id == "0, 0, hourly" diff --git a/tests/components/ipma/test_weather.py b/tests/components/ipma/test_weather.py index bfe7eefbb4c..02e46816bbc 100644 --- a/tests/components/ipma/test_weather.py +++ b/tests/components/ipma/test_weather.py @@ -24,7 +24,12 @@ from homeassistant.util.dt import now from tests.async_mock import patch from tests.common import MockConfigEntry -TEST_CONFIG = {"name": "HomeTown", "latitude": "40.00", "longitude": "-8.00"} +TEST_CONFIG = { + "name": "HomeTown", + "latitude": "40.00", + "longitude": "-8.00", + "mode": "daily", +} class MockLocation: diff --git a/tests/components/isy994/test_config_flow.py b/tests/components/isy994/test_config_flow.py index cbbc7427f9f..2fe19a0a9fd 100644 --- a/tests/components/isy994/test_config_flow.py +++ b/tests/components/isy994/test_config_flow.py @@ -93,11 +93,11 @@ async def test_form(hass: HomeAssistantType): result["flow_id"], MOCK_USER_INPUT, ) + await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["title"] == f"{MOCK_DEVICE_NAME} ({MOCK_HOSTNAME})" assert result2["result"].unique_id == MOCK_UUID assert result2["data"] == MOCK_USER_INPUT - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -310,11 +310,11 @@ async def test_form_ssdp(hass: HomeAssistantType): result["flow_id"], MOCK_USER_INPUT, ) + await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["title"] == f"{MOCK_DEVICE_NAME} ({MOCK_HOSTNAME})" assert result2["result"].unique_id == MOCK_UUID assert result2["data"] == MOCK_USER_INPUT - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/juicenet/test_config_flow.py b/tests/components/juicenet/test_config_flow.py index 4f00e9a1a76..3a7d2f06c43 100644 --- a/tests/components/juicenet/test_config_flow.py +++ b/tests/components/juicenet/test_config_flow.py @@ -35,11 +35,11 @@ async def test_form(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_ACCESS_TOKEN: "access_token"} ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "JuiceNet" assert result2["data"] == {CONF_ACCESS_TOKEN: "access_token"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -114,10 +114,10 @@ async def test_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data={CONF_ACCESS_TOKEN: "access_token"}, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "JuiceNet" assert result["data"] == {CONF_ACCESS_TOKEN: "access_token"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/kodi/test_config_flow.py b/tests/components/kodi/test_config_flow.py index 71c2bce1307..9b010f3ed42 100644 --- a/tests/components/kodi/test_config_flow.py +++ b/tests/components/kodi/test_config_flow.py @@ -51,6 +51,7 @@ async def test_user_flow(hass, user_flow): return_value=True, ) as mock_setup_entry: result = await hass.config_entries.flow.async_configure(user_flow, TEST_HOST) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == TEST_HOST["host"] @@ -63,7 +64,6 @@ async def test_user_flow(hass, user_flow): "timeout": DEFAULT_TIMEOUT, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -98,6 +98,7 @@ async def test_form_valid_auth(hass, user_flow): result = await hass.config_entries.flow.async_configure( result["flow_id"], TEST_CREDENTIALS ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == TEST_HOST["host"] @@ -109,7 +110,6 @@ async def test_form_valid_auth(hass, user_flow): "timeout": DEFAULT_TIMEOUT, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -148,6 +148,7 @@ async def test_form_valid_ws_port(hass, user_flow): result = await hass.config_entries.flow.async_configure( result["flow_id"], TEST_WS_PORT ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == TEST_HOST["host"] @@ -160,7 +161,6 @@ async def test_form_valid_ws_port(hass, user_flow): "timeout": DEFAULT_TIMEOUT, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -193,6 +193,7 @@ async def test_form_empty_ws_port(hass, user_flow): result = await hass.config_entries.flow.async_configure( result["flow_id"], {"ws_port": 0} ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == TEST_HOST["host"] @@ -205,7 +206,6 @@ async def test_form_empty_ws_port(hass, user_flow): "timeout": DEFAULT_TIMEOUT, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -436,6 +436,7 @@ async def test_discovery(hass): result = await hass.config_entries.flow.async_configure( flow_id=result["flow_id"], user_input={} ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "hostname" @@ -448,7 +449,6 @@ async def test_discovery(hass): "timeout": DEFAULT_TIMEOUT, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -592,12 +592,12 @@ async def test_form_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data=TEST_IMPORT, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == TEST_IMPORT["name"] assert result["data"] == TEST_IMPORT - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/light/conftest.py b/tests/components/light/conftest.py new file mode 100644 index 00000000000..67af99a3d6c --- /dev/null +++ b/tests/components/light/conftest.py @@ -0,0 +1,26 @@ +"""Light conftest.""" + +import pytest + +from homeassistant.components.light import Profiles + +from tests.async_mock import AsyncMock, patch + + +@pytest.fixture(autouse=True) +def mock_light_profiles(): + """Mock loading of profiles.""" + data = {} + + def mock_profiles_class(hass): + profiles = Profiles(hass) + profiles.data = data + profiles.async_initialize = AsyncMock() + return profiles + + with patch( + "homeassistant.components.light.Profiles", + SCHEMA=Profiles.SCHEMA, + side_effect=mock_profiles_class, + ): + yield data diff --git a/tests/components/light/test_init.py b/tests/components/light/test_init.py index e723ac77e03..afc125e6423 100644 --- a/tests/components/light/test_init.py +++ b/tests/components/light/test_init.py @@ -1,8 +1,4 @@ """The tests for the Light component.""" -# pylint: disable=protected-access -from io import StringIO -import os - import pytest import voluptuous as vol @@ -20,19 +16,11 @@ from homeassistant.const import ( ) from homeassistant.exceptions import Unauthorized from homeassistant.setup import async_setup_component +from homeassistant.util import color -import tests.async_mock as mock from tests.common import async_mock_service - -@pytest.fixture -def mock_storage(hass, hass_storage): - """Clean up user light files at the end.""" - yield - user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE) - - if os.path.isfile(user_light_file): - os.remove(user_light_file) +orig_Profiles = light.Profiles async def test_methods(hass): @@ -117,7 +105,7 @@ async def test_methods(hass): assert call.data[light.ATTR_TRANSITION] == "transition_val" -async def test_services(hass): +async def test_services(hass, mock_light_profiles): """Test the provided services.""" platform = getattr(hass.components, "test.light") @@ -292,6 +280,7 @@ async def test_services(hass): assert data == {} # One of the light profiles + mock_light_profiles["relax"] = (35.932, 69.412, 144, 0) prof_name, prof_h, prof_s, prof_bri, prof_t = "relax", 35.932, 69.412, 144, 0 # Test light profiles @@ -418,34 +407,13 @@ async def test_services(hass): assert data == {} -async def test_broken_light_profiles(hass, mock_storage): +async def test_light_profiles(hass, mock_light_profiles): """Test light profiles.""" platform = getattr(hass.components, "test.light") platform.init() - user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE) - - # Setup a wrong light file - with open(user_light_file, "w") as user_file: - user_file.write("id,x,y,brightness,transition\n") - user_file.write("I,WILL,NOT,WORK,EVER\n") - - assert not await async_setup_component( - hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}} - ) - - -async def test_light_profiles(hass, mock_storage): - """Test light profiles.""" - platform = getattr(hass.components, "test.light") - platform.init() - - user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE) - - with open(user_light_file, "w") as user_file: - user_file.write("id,x,y,brightness\n") - user_file.write("test,.4,.6,100\n") - user_file.write("test_off,0,0,0\n") + mock_light_profiles["test"] = color.color_xy_to_hs(0.4, 0.6) + (100, 0) + mock_light_profiles["test_off"] = 0, 0, 0, 0 assert await async_setup_component( hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}} @@ -484,80 +452,21 @@ async def test_light_profiles(hass, mock_storage): assert data == {light.ATTR_TRANSITION: 0} -async def test_light_profiles_with_transition(hass, mock_storage): - """Test light profiles with transition.""" +async def test_default_profiles_group(hass, mock_light_profiles): + """Test default turn-on light profile for all lights.""" platform = getattr(hass.components, "test.light") platform.init() - user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE) - - with open(user_light_file, "w") as user_file: - user_file.write("id,x,y,brightness,transition\n") - user_file.write("test,.4,.6,100,2\n") - user_file.write("test_off,0,0,0,0\n") - assert await async_setup_component( hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}} ) await hass.async_block_till_done() - ent1, _, _ = platform.ENTITIES - - await hass.services.async_call( - light.DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: ent1.entity_id, light.ATTR_PROFILE: "test"}, - blocking=True, + mock_light_profiles["group.all_lights.default"] = color.color_xy_to_hs(0.4, 0.6) + ( + 99, + 2, ) - _, data = ent1.last_call("turn_on") - assert light.is_on(hass, ent1.entity_id) - assert data == { - light.ATTR_HS_COLOR: (71.059, 100), - light.ATTR_BRIGHTNESS: 100, - light.ATTR_TRANSITION: 2, - } - - await hass.services.async_call( - light.DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: ent1.entity_id, light.ATTR_PROFILE: "test_off"}, - blocking=True, - ) - - _, data = ent1.last_call("turn_off") - assert not light.is_on(hass, ent1.entity_id) - assert data == {light.ATTR_TRANSITION: 0} - - -async def test_default_profiles_group(hass, mock_storage): - """Test default turn-on light profile for all lights.""" - platform = getattr(hass.components, "test.light") - platform.init() - - user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE) - real_isfile = os.path.isfile - real_open = open - - def _mock_isfile(path): - if path == user_light_file: - return True - return real_isfile(path) - - def _mock_open(path, *args, **kwargs): - if path == user_light_file: - return StringIO(profile_data) - return real_open(path, *args, **kwargs) - - profile_data = "id,x,y,brightness,transition\ngroup.all_lights.default,.4,.6,99,2\n" - with mock.patch("os.path.isfile", side_effect=_mock_isfile), mock.patch( - "builtins.open", side_effect=_mock_open - ): - assert await async_setup_component( - hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}} - ) - await hass.async_block_till_done() - ent, _, _ = platform.ENTITIES await hass.services.async_call( light.DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ent.entity_id}, blocking=True @@ -571,37 +480,24 @@ async def test_default_profiles_group(hass, mock_storage): } -async def test_default_profiles_light(hass, mock_storage): +async def test_default_profiles_light(hass, mock_light_profiles): """Test default turn-on light profile for a specific light.""" platform = getattr(hass.components, "test.light") platform.init() - user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE) - real_isfile = os.path.isfile - real_open = open - - def _mock_isfile(path): - if path == user_light_file: - return True - return real_isfile(path) - - def _mock_open(path, *args, **kwargs): - if path == user_light_file: - return StringIO(profile_data) - return real_open(path, *args, **kwargs) - - profile_data = ( - "id,x,y,brightness,transition\n" - + "group.all_lights.default,.3,.5,200,0\n" - + "light.ceiling_2.default,.6,.6,100,3\n" + assert await async_setup_component( + hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}} + ) + await hass.async_block_till_done() + + mock_light_profiles["group.all_lights.default"] = color.color_xy_to_hs(0.3, 0.5) + ( + 200, + 0, + ) + mock_light_profiles["light.ceiling_2.default"] = color.color_xy_to_hs(0.6, 0.6) + ( + 100, + 3, ) - with mock.patch("os.path.isfile", side_effect=_mock_isfile), mock.patch( - "builtins.open", side_effect=_mock_open - ): - assert await async_setup_component( - hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}} - ) - await hass.async_block_till_done() dev = next(filter(lambda x: x.entity_id == "light.ceiling_2", platform.ENTITIES)) await hass.services.async_call( @@ -775,3 +671,15 @@ def test_deprecated_base_class(caplog): CustomLight() assert "Light is deprecated, modify CustomLight" in caplog.text + + +async def test_profiles(hass): + """Test profiles loading.""" + profiles = orig_Profiles(hass) + await profiles.async_initialize() + assert profiles.data == { + "concentrate": (35.932, 69.412, 219, 0), + "energize": (43.333, 21.176, 203, 0), + "reading": (38.88, 49.02, 240, 0), + "relax": (35.932, 69.412, 144, 0), + } diff --git a/tests/components/litejet/conftest.py b/tests/components/litejet/conftest.py new file mode 100644 index 00000000000..68797f96ccf --- /dev/null +++ b/tests/components/litejet/conftest.py @@ -0,0 +1,2 @@ +"""litejet conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/logbook/test_init.py b/tests/components/logbook/test_init.py index 7c16faf2361..36d47115acc 100644 --- a/tests/components/logbook/test_init.py +++ b/tests/components/logbook/test_init.py @@ -3,7 +3,6 @@ import collections from datetime import datetime, timedelta import json -import unittest import pytest import voluptuous as vol @@ -41,264 +40,269 @@ from tests.async_mock import Mock, patch from tests.common import get_test_home_assistant, init_recorder_component, mock_platform from tests.components.recorder.common import trigger_db_commit +EMPTY_CONFIG = logbook.CONFIG_SCHEMA({logbook.DOMAIN: {}}) -class TestComponentLogbook(unittest.TestCase): - """Test the History component.""" - EMPTY_CONFIG = logbook.CONFIG_SCHEMA({logbook.DOMAIN: {}}) +@pytest.fixture +def hass_(): + """Set up things to be run when tests are started.""" + hass = get_test_home_assistant() + init_recorder_component(hass) # Force an in memory DB + with patch("homeassistant.components.http.start_http_server_and_save_config"): + assert setup_component(hass, logbook.DOMAIN, EMPTY_CONFIG) + yield hass + hass.stop() - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - init_recorder_component(self.hass) # Force an in memory DB - with patch("homeassistant.components.http.start_http_server_and_save_config"): - assert setup_component(self.hass, logbook.DOMAIN, self.EMPTY_CONFIG) - self.addCleanup(self.hass.stop) - def test_service_call_create_logbook_entry(self): - """Test if service call create log book entry.""" - calls = [] +def test_service_call_create_logbook_entry(hass_): + """Test if service call create log book entry.""" + calls = [] - @ha.callback - def event_listener(event): - """Append on event.""" - calls.append(event) + @ha.callback + def event_listener(event): + """Append on event.""" + calls.append(event) - self.hass.bus.listen(logbook.EVENT_LOGBOOK_ENTRY, event_listener) - self.hass.services.call( - logbook.DOMAIN, - "log", - { - logbook.ATTR_NAME: "Alarm", - logbook.ATTR_MESSAGE: "is triggered", - logbook.ATTR_DOMAIN: "switch", - logbook.ATTR_ENTITY_ID: "switch.test_switch", - }, - True, + hass_.bus.listen(logbook.EVENT_LOGBOOK_ENTRY, event_listener) + hass_.services.call( + logbook.DOMAIN, + "log", + { + logbook.ATTR_NAME: "Alarm", + logbook.ATTR_MESSAGE: "is triggered", + logbook.ATTR_DOMAIN: "switch", + logbook.ATTR_ENTITY_ID: "switch.test_switch", + }, + True, + ) + hass_.services.call( + logbook.DOMAIN, + "log", + { + logbook.ATTR_NAME: "This entry", + logbook.ATTR_MESSAGE: "has no domain or entity_id", + }, + True, + ) + # Logbook entry service call results in firing an event. + # Our service call will unblock when the event listeners have been + # scheduled. This means that they may not have been processed yet. + trigger_db_commit(hass_) + hass_.block_till_done() + hass_.data[recorder.DATA_INSTANCE].block_till_done() + + events = list( + logbook._get_events( + hass_, + dt_util.utcnow() - timedelta(hours=1), + dt_util.utcnow() + timedelta(hours=1), ) - self.hass.services.call( - logbook.DOMAIN, - "log", - { - logbook.ATTR_NAME: "This entry", - logbook.ATTR_MESSAGE: "has no domain or entity_id", - }, - True, - ) - # Logbook entry service call results in firing an event. - # Our service call will unblock when the event listeners have been - # scheduled. This means that they may not have been processed yet. - trigger_db_commit(self.hass) - self.hass.block_till_done() - self.hass.data[recorder.DATA_INSTANCE].block_till_done() + ) + assert len(events) == 2 - events = list( - logbook._get_events( - self.hass, - dt_util.utcnow() - timedelta(hours=1), - dt_util.utcnow() + timedelta(hours=1), - ) - ) - assert len(events) == 2 + assert len(calls) == 2 + first_call = calls[-2] - assert len(calls) == 2 - first_call = calls[-2] + assert first_call.data.get(logbook.ATTR_NAME) == "Alarm" + assert first_call.data.get(logbook.ATTR_MESSAGE) == "is triggered" + assert first_call.data.get(logbook.ATTR_DOMAIN) == "switch" + assert first_call.data.get(logbook.ATTR_ENTITY_ID) == "switch.test_switch" - assert first_call.data.get(logbook.ATTR_NAME) == "Alarm" - assert first_call.data.get(logbook.ATTR_MESSAGE) == "is triggered" - assert first_call.data.get(logbook.ATTR_DOMAIN) == "switch" - assert first_call.data.get(logbook.ATTR_ENTITY_ID) == "switch.test_switch" + last_call = calls[-1] - last_call = calls[-1] + assert last_call.data.get(logbook.ATTR_NAME) == "This entry" + assert last_call.data.get(logbook.ATTR_MESSAGE) == "has no domain or entity_id" + assert last_call.data.get(logbook.ATTR_DOMAIN) == "logbook" - assert last_call.data.get(logbook.ATTR_NAME) == "This entry" - assert last_call.data.get(logbook.ATTR_MESSAGE) == "has no domain or entity_id" - assert last_call.data.get(logbook.ATTR_DOMAIN) == "logbook" - def test_service_call_create_log_book_entry_no_message(self): - """Test if service call create log book entry without message.""" - calls = [] +def test_service_call_create_log_book_entry_no_message(hass_): + """Test if service call create log book entry without message.""" + calls = [] - @ha.callback - def event_listener(event): - """Append on event.""" - calls.append(event) + @ha.callback + def event_listener(event): + """Append on event.""" + calls.append(event) - self.hass.bus.listen(logbook.EVENT_LOGBOOK_ENTRY, event_listener) + hass_.bus.listen(logbook.EVENT_LOGBOOK_ENTRY, event_listener) - with pytest.raises(vol.Invalid): - self.hass.services.call(logbook.DOMAIN, "log", {}, True) + with pytest.raises(vol.Invalid): + hass_.services.call(logbook.DOMAIN, "log", {}, True) - # Logbook entry service call results in firing an event. - # Our service call will unblock when the event listeners have been - # scheduled. This means that they may not have been processed yet. - self.hass.block_till_done() + # Logbook entry service call results in firing an event. + # Our service call will unblock when the event listeners have been + # scheduled. This means that they may not have been processed yet. + hass_.block_till_done() - assert len(calls) == 0 + assert len(calls) == 0 - def test_humanify_filter_sensor(self): - """Test humanify filter too frequent sensor values.""" - entity_id = "sensor.bla" - pointA = dt_util.utcnow().replace(minute=2) - pointB = pointA.replace(minute=5) - pointC = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) - entity_attr_cache = logbook.EntityAttributeCache(self.hass) +def test_humanify_filter_sensor(hass_): + """Test humanify filter too frequent sensor values.""" + entity_id = "sensor.bla" - eventA = self.create_state_changed_event(pointA, entity_id, 10) - eventB = self.create_state_changed_event(pointB, entity_id, 20) - eventC = self.create_state_changed_event(pointC, entity_id, 30) + pointA = dt_util.utcnow().replace(minute=2) + pointB = pointA.replace(minute=5) + pointC = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(hass_) - entries = list( - logbook.humanify(self.hass, (eventA, eventB, eventC), entity_attr_cache, {}) - ) + eventA = create_state_changed_event(pointA, entity_id, 10) + eventB = create_state_changed_event(pointB, entity_id, 20) + eventC = create_state_changed_event(pointC, entity_id, 30) - assert len(entries) == 2 - self.assert_entry(entries[0], pointB, "bla", entity_id=entity_id) + entries = list( + logbook.humanify(hass_, (eventA, eventB, eventC), entity_attr_cache, {}) + ) - self.assert_entry(entries[1], pointC, "bla", entity_id=entity_id) + assert len(entries) == 2 + assert_entry(entries[0], pointB, "bla", entity_id=entity_id) - def test_home_assistant_start_stop_grouped(self): - """Test if HA start and stop events are grouped. + assert_entry(entries[1], pointC, "bla", entity_id=entity_id) - Events that are occurring in the same minute. - """ - entity_attr_cache = logbook.EntityAttributeCache(self.hass) - entries = list( - logbook.humanify( - self.hass, - ( - MockLazyEventPartialState(EVENT_HOMEASSISTANT_STOP), - MockLazyEventPartialState(EVENT_HOMEASSISTANT_START), - ), - entity_attr_cache, - {}, + +def test_home_assistant_start_stop_grouped(hass_): + """Test if HA start and stop events are grouped. + + Events that are occurring in the same minute. + """ + entity_attr_cache = logbook.EntityAttributeCache(hass_) + entries = list( + logbook.humanify( + hass_, + ( + MockLazyEventPartialState(EVENT_HOMEASSISTANT_STOP), + MockLazyEventPartialState(EVENT_HOMEASSISTANT_START), ), + entity_attr_cache, + {}, + ), + ) + + assert len(entries) == 1 + assert_entry( + entries[0], name="Home Assistant", message="restarted", domain=ha.DOMAIN + ) + + +def test_home_assistant_start(hass_): + """Test if HA start is not filtered or converted into a restart.""" + entity_id = "switch.bla" + pointA = dt_util.utcnow() + entity_attr_cache = logbook.EntityAttributeCache(hass_) + + entries = list( + logbook.humanify( + hass_, + ( + MockLazyEventPartialState(EVENT_HOMEASSISTANT_START), + create_state_changed_event(pointA, entity_id, 10), + ), + entity_attr_cache, + {}, ) + ) - assert len(entries) == 1 - self.assert_entry( - entries[0], name="Home Assistant", message="restarted", domain=ha.DOMAIN - ) + assert len(entries) == 2 + assert_entry(entries[0], name="Home Assistant", message="started", domain=ha.DOMAIN) + assert_entry(entries[1], pointA, "bla", entity_id=entity_id) - def test_home_assistant_start(self): - """Test if HA start is not filtered or converted into a restart.""" - entity_id = "switch.bla" - pointA = dt_util.utcnow() - entity_attr_cache = logbook.EntityAttributeCache(self.hass) - entries = list( - logbook.humanify( - self.hass, - ( - MockLazyEventPartialState(EVENT_HOMEASSISTANT_START), - self.create_state_changed_event(pointA, entity_id, 10), +def test_process_custom_logbook_entries(hass_): + """Test if custom log book entries get added as an entry.""" + name = "Nice name" + message = "has a custom entry" + entity_id = "sun.sun" + entity_attr_cache = logbook.EntityAttributeCache(hass_) + + entries = list( + logbook.humanify( + hass_, + ( + MockLazyEventPartialState( + logbook.EVENT_LOGBOOK_ENTRY, + { + logbook.ATTR_NAME: name, + logbook.ATTR_MESSAGE: message, + logbook.ATTR_ENTITY_ID: entity_id, + }, ), - entity_attr_cache, - {}, - ) + ), + entity_attr_cache, + {}, ) + ) - assert len(entries) == 2 - self.assert_entry( - entries[0], name="Home Assistant", message="started", domain=ha.DOMAIN - ) - self.assert_entry(entries[1], pointA, "bla", entity_id=entity_id) + assert len(entries) == 1 + assert_entry(entries[0], name=name, message=message, entity_id=entity_id) - def test_process_custom_logbook_entries(self): - """Test if custom log book entries get added as an entry.""" - name = "Nice name" - message = "has a custom entry" - entity_id = "sun.sun" - entity_attr_cache = logbook.EntityAttributeCache(self.hass) - entries = list( - logbook.humanify( - self.hass, - ( - MockLazyEventPartialState( - logbook.EVENT_LOGBOOK_ENTRY, - { - logbook.ATTR_NAME: name, - logbook.ATTR_MESSAGE: message, - logbook.ATTR_ENTITY_ID: entity_id, - }, - ), - ), - entity_attr_cache, - {}, - ) - ) +# pylint: disable=no-self-use +def assert_entry( + entry, when=None, name=None, message=None, domain=None, entity_id=None +): + """Assert an entry is what is expected.""" + return _assert_entry(entry, when, name, message, domain, entity_id) - assert len(entries) == 1 - self.assert_entry(entries[0], name=name, message=message, entity_id=entity_id) - # pylint: disable=no-self-use - def assert_entry( - self, entry, when=None, name=None, message=None, domain=None, entity_id=None - ): - """Assert an entry is what is expected.""" - return _assert_entry(entry, when, name, message, domain, entity_id) +def create_state_changed_event( + event_time_fired, + entity_id, + state, + attributes=None, + last_changed=None, + last_updated=None, +): + """Create state changed event.""" + old_state = ha.State( + entity_id, "old", attributes, last_changed, last_updated + ).as_dict() + new_state = ha.State( + entity_id, state, attributes, last_changed, last_updated + ).as_dict() - def create_state_changed_event( - self, - event_time_fired, - entity_id, - state, - attributes=None, - last_changed=None, - last_updated=None, - ): - """Create state changed event.""" - old_state = ha.State( - entity_id, "old", attributes, last_changed, last_updated - ).as_dict() - new_state = ha.State( - entity_id, state, attributes, last_changed, last_updated - ).as_dict() + return create_state_changed_event_from_old_new( + entity_id, event_time_fired, old_state, new_state + ) - return self.create_state_changed_event_from_old_new( - entity_id, event_time_fired, old_state, new_state - ) - # pylint: disable=no-self-use - def create_state_changed_event_from_old_new( - self, entity_id, event_time_fired, old_state, new_state - ): - """Create a state changed event from a old and new state.""" - attributes = {} - if new_state is not None: - attributes = new_state.get("attributes") - attributes_json = json.dumps(attributes, cls=JSONEncoder) - row = collections.namedtuple( - "Row", - [ - "event_type" - "event_data" - "time_fired" - "context_id" - "context_user_id" - "state" - "entity_id" - "domain" - "attributes" - "state_id", - "old_state_id", - ], - ) +# pylint: disable=no-self-use +def create_state_changed_event_from_old_new( + entity_id, event_time_fired, old_state, new_state +): + """Create a state changed event from a old and new state.""" + attributes = {} + if new_state is not None: + attributes = new_state.get("attributes") + attributes_json = json.dumps(attributes, cls=JSONEncoder) + row = collections.namedtuple( + "Row", + [ + "event_type" + "event_data" + "time_fired" + "context_id" + "context_user_id" + "state" + "entity_id" + "domain" + "attributes" + "state_id", + "old_state_id", + ], + ) - row.event_type = EVENT_STATE_CHANGED - row.event_data = "{}" - row.attributes = attributes_json - row.time_fired = event_time_fired - row.state = new_state and new_state.get("state") - row.entity_id = entity_id - row.domain = entity_id and ha.split_entity_id(entity_id)[0] - row.context_id = None - row.context_user_id = None - row.old_state_id = old_state and 1 - row.state_id = new_state and 1 - return logbook.LazyEventPartialState(row) + row.event_type = EVENT_STATE_CHANGED + row.event_data = "{}" + row.attributes = attributes_json + row.time_fired = event_time_fired + row.state = new_state and new_state.get("state") + row.entity_id = entity_id + row.domain = entity_id and ha.split_entity_id(entity_id)[0] + row.context_id = None + row.context_user_id = None + row.old_state_id = old_state and 1 + row.state_id = new_state and 1 + return logbook.LazyEventPartialState(row) async def test_logbook_view(hass, hass_client): diff --git a/tests/components/london_air/test_sensor.py b/tests/components/london_air/test_sensor.py index 066fc357a50..4ee28c54329 100644 --- a/tests/components/london_air/test_sensor.py +++ b/tests/components/london_air/test_sensor.py @@ -1,34 +1,51 @@ -"""The tests for the tube_state platform.""" -import unittest - -import requests_mock - +"""The tests for the london_air platform.""" from homeassistant.components.london_air.sensor import CONF_LOCATIONS, URL -from homeassistant.setup import setup_component +from homeassistant.const import HTTP_OK, HTTP_SERVICE_UNAVAILABLE +from homeassistant.setup import async_setup_component -from tests.common import get_test_home_assistant, load_fixture +from tests.common import load_fixture -VALID_CONFIG = {"platform": "london_air", CONF_LOCATIONS: ["Merton"]} +VALID_CONFIG = {"sensor": {"platform": "london_air", CONF_LOCATIONS: ["Merton"]}} -class TestLondonAirSensor(unittest.TestCase): - """Test the tube_state platform.""" +async def test_valid_state(hass, requests_mock): + """Test for operational london_air sensor with proper attributes.""" + requests_mock.get(URL, text=load_fixture("london_air.json"), status_code=HTTP_OK) + assert await async_setup_component(hass, "sensor", VALID_CONFIG) + await hass.async_block_till_done() - def setUp(self): - """Initialize values for this testcase class.""" - self.hass = get_test_home_assistant() - self.config = VALID_CONFIG - self.addCleanup(self.hass.stop) + state = hass.states.get("sensor.merton") + assert state is not None + assert state.state == "Low" + assert state.attributes["icon"] == "mdi:cloud-outline" + assert state.attributes["updated"] == "2017-08-03 03:00:00" + assert state.attributes["sites"] == 2 + assert state.attributes["friendly_name"] == "Merton" - @requests_mock.Mocker() - def test_setup(self, mock_req): - """Test for operational tube_state sensor with proper attributes.""" - mock_req.get(URL, text=load_fixture("london_air.json")) - assert setup_component(self.hass, "sensor", {"sensor": self.config}) - self.hass.block_till_done() + sites = state.attributes["data"] + assert sites is not None + assert len(sites) == 2 + assert sites[0]["site_code"] == "ME2" + assert sites[0]["site_type"] == "Roadside" + assert sites[0]["site_name"] == "Merton Road" + assert sites[0]["pollutants_status"] == "Low" - state = self.hass.states.get("sensor.merton") - assert state.state == "Low" - assert state.attributes.get("updated") == "2017-08-03 03:00:00" - assert state.attributes.get("sites") == 2 - assert state.attributes.get("data")[0]["site_code"] == "ME2" + pollutants = sites[0]["pollutants"] + assert pollutants is not None + assert len(pollutants) == 1 + assert pollutants[0]["code"] == "PM10" + assert pollutants[0]["quality"] == "Low" + assert int(pollutants[0]["index"]) == 2 + assert pollutants[0]["summary"] == "PM10 is Low" + + +async def test_api_failure(hass, requests_mock): + """Test for failure in the API.""" + requests_mock.get(URL, status_code=HTTP_SERVICE_UNAVAILABLE) + assert await async_setup_component(hass, "sensor", VALID_CONFIG) + await hass.async_block_till_done() + + state = hass.states.get("sensor.merton") + assert state is not None + assert state.attributes["updated"] is None + assert state.attributes["sites"] == 0 diff --git a/tests/components/lovelace/test_dashboard.py b/tests/components/lovelace/test_dashboard.py index fb8c909eac5..b5157dd7c46 100644 --- a/tests/components/lovelace/test_dashboard.py +++ b/tests/components/lovelace/test_dashboard.py @@ -6,11 +6,7 @@ from homeassistant.components.lovelace import const, dashboard from homeassistant.setup import async_setup_component from tests.async_mock import patch -from tests.common import ( - assert_setup_component, - async_capture_events, - get_system_health_info, -) +from tests.common import assert_setup_component, async_capture_events async def test_lovelace_from_storage(hass, hass_ws_client, hass_storage): @@ -160,48 +156,6 @@ async def test_lovelace_from_yaml(hass, hass_ws_client): assert len(events) == 1 -async def test_system_health_info_autogen(hass): - """Test system health info endpoint.""" - assert await async_setup_component(hass, "lovelace", {}) - info = await get_system_health_info(hass, "lovelace") - assert info == {"dashboards": 1, "mode": "auto-gen", "resources": 0} - - -async def test_system_health_info_storage(hass, hass_storage): - """Test system health info endpoint.""" - hass_storage[dashboard.CONFIG_STORAGE_KEY_DEFAULT] = { - "key": "lovelace", - "version": 1, - "data": {"config": {"resources": [], "views": []}}, - } - assert await async_setup_component(hass, "lovelace", {}) - info = await get_system_health_info(hass, "lovelace") - assert info == {"dashboards": 1, "mode": "storage", "resources": 0, "views": 0} - - -async def test_system_health_info_yaml(hass): - """Test system health info endpoint.""" - assert await async_setup_component(hass, "lovelace", {"lovelace": {"mode": "YAML"}}) - with patch( - "homeassistant.components.lovelace.dashboard.load_yaml", - return_value={"views": [{"cards": []}]}, - ): - info = await get_system_health_info(hass, "lovelace") - assert info == {"dashboards": 1, "mode": "yaml", "resources": 0, "views": 1} - - -async def test_system_health_info_yaml_not_found(hass): - """Test system health info endpoint.""" - assert await async_setup_component(hass, "lovelace", {"lovelace": {"mode": "YAML"}}) - info = await get_system_health_info(hass, "lovelace") - assert info == { - "dashboards": 1, - "mode": "yaml", - "error": "{} not found".format(hass.config.path("ui-lovelace.yaml")), - "resources": 0, - } - - @pytest.mark.parametrize("url_path", ("test-panel", "test-panel-no-sidebar")) async def test_dashboard_from_yaml(hass, hass_ws_client, url_path): """Test we load lovelace dashboard config from yaml.""" diff --git a/tests/components/lovelace/test_system_health.py b/tests/components/lovelace/test_system_health.py new file mode 100644 index 00000000000..b81915083d2 --- /dev/null +++ b/tests/components/lovelace/test_system_health.py @@ -0,0 +1,52 @@ +"""Tests for Lovelace system health.""" +from homeassistant.components.lovelace import dashboard +from homeassistant.setup import async_setup_component + +from tests.async_mock import patch +from tests.common import get_system_health_info + + +async def test_system_health_info_autogen(hass): + """Test system health info endpoint.""" + assert await async_setup_component(hass, "lovelace", {}) + assert await async_setup_component(hass, "system_health", {}) + info = await get_system_health_info(hass, "lovelace") + assert info == {"dashboards": 1, "mode": "auto-gen", "resources": 0} + + +async def test_system_health_info_storage(hass, hass_storage): + """Test system health info endpoint.""" + assert await async_setup_component(hass, "system_health", {}) + hass_storage[dashboard.CONFIG_STORAGE_KEY_DEFAULT] = { + "key": "lovelace", + "version": 1, + "data": {"config": {"resources": [], "views": []}}, + } + assert await async_setup_component(hass, "lovelace", {}) + info = await get_system_health_info(hass, "lovelace") + assert info == {"dashboards": 1, "mode": "storage", "resources": 0, "views": 0} + + +async def test_system_health_info_yaml(hass): + """Test system health info endpoint.""" + assert await async_setup_component(hass, "system_health", {}) + assert await async_setup_component(hass, "lovelace", {"lovelace": {"mode": "YAML"}}) + with patch( + "homeassistant.components.lovelace.dashboard.load_yaml", + return_value={"views": [{"cards": []}]}, + ): + info = await get_system_health_info(hass, "lovelace") + assert info == {"dashboards": 1, "mode": "yaml", "resources": 0, "views": 1} + + +async def test_system_health_info_yaml_not_found(hass): + """Test system health info endpoint.""" + assert await async_setup_component(hass, "system_health", {}) + assert await async_setup_component(hass, "lovelace", {"lovelace": {"mode": "YAML"}}) + info = await get_system_health_info(hass, "lovelace") + assert info == { + "dashboards": 1, + "mode": "yaml", + "error": "{} not found".format(hass.config.path("ui-lovelace.yaml")), + "resources": 0, + } diff --git a/tests/components/luftdaten/test_config_flow.py b/tests/components/luftdaten/test_config_flow.py index 70b306d34c0..f3ee1f6c0f7 100644 --- a/tests/components/luftdaten/test_config_flow.py +++ b/tests/components/luftdaten/test_config_flow.py @@ -19,7 +19,7 @@ async def test_duplicate_error(hass): flow.hass = hass result = await flow.async_step_user(user_input=conf) - assert result["errors"] == {CONF_SENSOR_ID: "sensor_exists"} + assert result["errors"] == {CONF_SENSOR_ID: "already_configured"} async def test_communication_error(hass): diff --git a/tests/components/melcloud/test_config_flow.py b/tests/components/melcloud/test_config_flow.py index ab3d16a0d6a..1fca3ac877e 100644 --- a/tests/components/melcloud/test_config_flow.py +++ b/tests/components/melcloud/test_config_flow.py @@ -61,6 +61,7 @@ async def test_form(hass, mock_login, mock_get_devices): result["flow_id"], {"username": "test-email@test-domain.com", "password": "test-password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "test-email@test-domain.com" @@ -68,7 +69,6 @@ async def test_form(hass, mock_login, mock_get_devices): "username": "test-email@test-domain.com", "token": "test-token", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -128,6 +128,7 @@ async def test_import_with_token(hass, mock_login, mock_get_devices): context={"source": config_entries.SOURCE_IMPORT}, data={"username": "test-email@test-domain.com", "token": "test-token"}, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "test-email@test-domain.com" @@ -135,7 +136,6 @@ async def test_import_with_token(hass, mock_login, mock_get_devices): "username": "test-email@test-domain.com", "token": "test-token", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/metoffice/test_config_flow.py b/tests/components/metoffice/test_config_flow.py index 5987d44ac27..3f248704fa1 100644 --- a/tests/components/metoffice/test_config_flow.py +++ b/tests/components/metoffice/test_config_flow.py @@ -42,6 +42,7 @@ async def test_form(hass, requests_mock): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], {"api_key": TEST_API_KEY} ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == TEST_SITE_NAME_WAVERTREE @@ -51,7 +52,6 @@ async def test_form(hass, requests_mock): "longitude": TEST_LONGITUDE_WAVERTREE, "name": TEST_SITE_NAME_WAVERTREE, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/mfi/test_sensor.py b/tests/components/mfi/test_sensor.py index 05e1379cfb4..966dcbfd567 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, - } +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 setup_method(self, method): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - 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) + assert not PLATFORM.setup_platform(hass, dict(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() + +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", side_effect=mfi.MfiSensor + ) as mock_sensor: ports = { i: mock.MagicMock(model=model) for i, model in enumerate(mfi.SENSOR_MODELS) } @@ -107,82 +103,90 @@ class TestMfiSensorSetup(unittest.TestCase): 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 + mock_sensor.assert_any_call(port, hass) + assert mock.call(ports["bad"], hass) not in mock_sensor.mock_calls -class TestMfiSensor(unittest.TestCase): - """Test for mFi sensor platform.""" +@pytest.fixture(name="port") +def port_fixture(): + """Port fixture.""" + return mock.MagicMock() - 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() +@pytest.fixture(name="sensor") +def sensor_fixture(hass, port): + """Sensor fixture.""" + return mfi.MfiSensor(port, hass) - 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 +async def test_name(port, sensor): + """Test the name.""" + assert port.label == sensor.name - 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 +async def test_uom_temp(port, sensor): + """Test the UOM temperature.""" + port.tag = "temperature" + assert TEMP_CELSIUS == 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 +async def test_uom_power(port, sensor): + """Test the UOEM power.""" + port.tag = "active_pwr" + assert sensor.unit_of_measurement == "Watts" - 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 +async def test_uom_digital(port, sensor): + """Test the UOM digital input.""" + port.model = "Input Digital" + assert sensor.unit_of_measurement == "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() +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 45bb3530266..e700aad8353 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, - } +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 setup_method(self, method): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - 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", side_effect=mfi.MfiSwitch + ) as mock_switch: ports = { i: mock.MagicMock(model=model) for i, model in enumerate(mfi.SWITCH_MODELS) } @@ -47,74 +38,84 @@ class TestMfiSwitchSetup(unittest.TestCase): 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 + assert mock.call(ports["bad"], hass) not in mock_switch.mock_calls -class TestMfiSwitch(unittest.TestCase): - """Test for mFi switch platform.""" +@pytest.fixture(name="port") +def port_fixture(): + """Port fixture.""" + return mock.MagicMock() - 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() +@pytest.fixture(name="switch") +def switch_fixture(port): + """Switch fixture.""" + return mfi.MfiSwitch(port) - 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() +async def test_name(port, switch): + """Test the name.""" + assert port.label == switch.name - 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 +async def test_update(port, switch): + """Test update.""" + switch.update() + assert port.refresh.call_count == 1 + assert port.refresh.call_args == mock.call() - 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 +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" - 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 +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} diff --git a/tests/components/mochad/conftest.py b/tests/components/mochad/conftest.py new file mode 100644 index 00000000000..9b095046d9c --- /dev/null +++ b/tests/components/mochad/conftest.py @@ -0,0 +1,2 @@ +"""mochad conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/mochad/test_light.py b/tests/components/mochad/test_light.py index eb9cf047d02..9d484b2db65 100644 --- a/tests/components/mochad/test_light.py +++ b/tests/components/mochad/test_light.py @@ -1,14 +1,12 @@ """The tests for the mochad light platform.""" -import unittest import pytest from homeassistant.components import light from homeassistant.components.mochad import light as mochad -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 @pytest.fixture(autouse=True) @@ -18,122 +16,51 @@ def pymochad_mock(): yield device -class TestMochadSwitchSetup(unittest.TestCase): - """Test the mochad light.""" - - PLATFORM = mochad - COMPONENT = light - THING = "light" - - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.addCleanup(self.hass.stop) - - @mock.patch("homeassistant.components.mochad.light.MochadLight") - def test_setup_adds_proper_devices(self, mock_light): - """Test if setup adds devices.""" - good_config = { - "mochad": {}, - "light": { - "platform": "mochad", - "devices": [{"name": "Light1", "address": "a1"}], - }, - } - assert setup_component(self.hass, light.DOMAIN, good_config) +@pytest.fixture +def light_mock(hass, brightness): + """Mock light.""" + controller_mock = mock.MagicMock() + dev_dict = {"address": "a1", "name": "fake_light", "brightness_levels": brightness} + return mochad.MochadLight(hass, controller_mock, dev_dict) -class TestMochadLight(unittest.TestCase): - """Test for mochad light platform.""" - - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - controller_mock = mock.MagicMock() - dev_dict = {"address": "a1", "name": "fake_light", "brightness_levels": 32} - self.light = mochad.MochadLight(self.hass, controller_mock, dev_dict) - - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - - def test_name(self): - """Test the name.""" - assert "fake_light" == self.light.name - - def test_turn_on_with_no_brightness(self): - """Test turn_on.""" - self.light.turn_on() - self.light.light.send_cmd.assert_called_once_with("on") - - def test_turn_on_with_brightness(self): - """Test turn_on.""" - self.light.turn_on(brightness=45) - self.light.light.send_cmd.assert_has_calls( - [mock.call("on"), mock.call("dim 25")] - ) - - def test_turn_off(self): - """Test turn_off.""" - self.light.turn_off() - self.light.light.send_cmd.assert_called_once_with("off") +async def test_setup_adds_proper_devices(hass): + """Test if setup adds devices.""" + good_config = { + "mochad": {}, + "light": { + "platform": "mochad", + "devices": [{"name": "Light1", "address": "a1"}], + }, + } + assert await async_setup_component(hass, light.DOMAIN, good_config) -class TestMochadLight256Levels(unittest.TestCase): - """Test for mochad light platform.""" - - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - controller_mock = mock.MagicMock() - dev_dict = {"address": "a1", "name": "fake_light", "brightness_levels": 256} - self.light = mochad.MochadLight(self.hass, controller_mock, dev_dict) - - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - - def test_turn_on_with_no_brightness(self): - """Test turn_on.""" - self.light.turn_on() - self.light.light.send_cmd.assert_called_once_with("xdim 255") - - def test_turn_on_with_brightness(self): - """Test turn_on.""" - self.light.turn_on(brightness=45) - self.light.light.send_cmd.assert_called_once_with("xdim 45") - - def test_turn_off(self): - """Test turn_off.""" - self.light.turn_off() - self.light.light.send_cmd.assert_called_once_with("off") +@pytest.mark.parametrize( + "brightness,expected", [(32, "on"), (256, "xdim 255"), (64, "xdim 63")] +) +async def test_turn_on_with_no_brightness(light_mock, expected): + """Test turn_on.""" + light_mock.turn_on() + light_mock.light.send_cmd.assert_called_once_with(expected) -class TestMochadLight64Levels(unittest.TestCase): - """Test for mochad light platform.""" +@pytest.mark.parametrize( + "brightness,expected", + [ + (32, [mock.call("on"), mock.call("dim 25")]), + (256, [mock.call("xdim 45")]), + (64, [mock.call("xdim 11")]), + ], +) +async def test_turn_on_with_brightness(light_mock, expected): + """Test turn_on.""" + light_mock.turn_on(brightness=45) + light_mock.light.send_cmd.assert_has_calls(expected) - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - controller_mock = mock.MagicMock() - dev_dict = {"address": "a1", "name": "fake_light", "brightness_levels": 64} - self.light = mochad.MochadLight(self.hass, controller_mock, dev_dict) - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - - def test_turn_on_with_no_brightness(self): - """Test turn_on.""" - self.light.turn_on() - self.light.light.send_cmd.assert_called_once_with("xdim 63") - - def test_turn_on_with_brightness(self): - """Test turn_on.""" - self.light.turn_on(brightness=45) - self.light.light.send_cmd.assert_called_once_with("xdim 11") - - def test_turn_off(self): - """Test turn_off.""" - self.light.turn_off() - self.light.light.send_cmd.assert_called_once_with("off") +@pytest.mark.parametrize("brightness", [32]) +async def test_turn_off(light_mock): + """Test turn_off.""" + light_mock.turn_off() + light_mock.light.send_cmd.assert_called_once_with("off") diff --git a/tests/components/mochad/test_switch.py b/tests/components/mochad/test_switch.py index 66f84c16fee..e8d58233c40 100644 --- a/tests/components/mochad/test_switch.py +++ b/tests/components/mochad/test_switch.py @@ -1,14 +1,11 @@ """The tests for the mochad switch platform.""" -import unittest - import pytest from homeassistant.components import switch from homeassistant.components.mochad import switch as mochad -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 @pytest.fixture(autouse=True) @@ -20,55 +17,38 @@ def pymochad_mock(): yield -class TestMochadSwitchSetup(unittest.TestCase): - """Test the mochad switch.""" - - PLATFORM = mochad - COMPONENT = switch - THING = "switch" - - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.addCleanup(self.hass.stop) - - @mock.patch("homeassistant.components.mochad.switch.MochadSwitch") - def test_setup_adds_proper_devices(self, mock_switch): - """Test if setup adds devices.""" - good_config = { - "mochad": {}, - "switch": { - "platform": "mochad", - "devices": [{"name": "Switch1", "address": "a1"}], - }, - } - assert setup_component(self.hass, switch.DOMAIN, good_config) +@pytest.fixture +def switch_mock(hass): + """Mock switch.""" + controller_mock = mock.MagicMock() + dev_dict = {"address": "a1", "name": "fake_switch"} + return mochad.MochadSwitch(hass, controller_mock, dev_dict) -class TestMochadSwitch(unittest.TestCase): - """Test for mochad switch platform.""" +async def test_setup_adds_proper_devices(hass): + """Test if setup adds devices.""" + good_config = { + "mochad": {}, + "switch": { + "platform": "mochad", + "devices": [{"name": "Switch1", "address": "a1"}], + }, + } + assert await async_setup_component(hass, switch.DOMAIN, good_config) - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - controller_mock = mock.MagicMock() - dev_dict = {"address": "a1", "name": "fake_switch"} - self.switch = mochad.MochadSwitch(self.hass, controller_mock, dev_dict) - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() +async def test_name(switch_mock): + """Test the name.""" + assert "fake_switch" == switch_mock.name - def test_name(self): - """Test the name.""" - assert "fake_switch" == self.switch.name - def test_turn_on(self): - """Test turn_on.""" - self.switch.turn_on() - self.switch.switch.send_cmd.assert_called_once_with("on") +async def test_turn_on(switch_mock): + """Test turn_on.""" + switch_mock.turn_on() + switch_mock.switch.send_cmd.assert_called_once_with("on") - def test_turn_off(self): - """Test turn_off.""" - self.switch.turn_off() - self.switch.switch.send_cmd.assert_called_once_with("off") + +async def test_turn_off(switch_mock): + """Test turn_off.""" + switch_mock.turn_off() + switch_mock.switch.send_cmd.assert_called_once_with("off") diff --git a/tests/components/modbus/conftest.py b/tests/components/modbus/conftest.py index ca3e44dbe1d..ce6e6585512 100644 --- a/tests/components/modbus/conftest.py +++ b/tests/components/modbus/conftest.py @@ -64,6 +64,8 @@ async def setup_base_test( entity_id = f"{entity_domain}.{sensor_name}" device = hass.states.get(entity_id) + if device is None: + pytest.fail("CONFIG failed, see output") return entity_id, now, device diff --git a/tests/components/modbus/test_modbus_switch.py b/tests/components/modbus/test_modbus_switch.py index 75255389bea..da2ff953660 100644 --- a/tests/components/modbus/test_modbus_switch.py +++ b/tests/components/modbus/test_modbus_switch.py @@ -3,9 +3,22 @@ from datetime import timedelta import pytest -from homeassistant.components.modbus.const import CALL_TYPE_COIL, CONF_COILS +from homeassistant.components.modbus.const import ( + CALL_TYPE_COIL, + CALL_TYPE_REGISTER_HOLDING, + CONF_COILS, + CONF_REGISTER, + CONF_REGISTERS, +) from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN -from homeassistant.const import CONF_NAME, CONF_SLAVE, STATE_OFF, STATE_ON +from homeassistant.const import ( + CONF_COMMAND_OFF, + CONF_COMMAND_ON, + CONF_NAME, + CONF_SLAVE, + STATE_OFF, + STATE_ON, +) from .conftest import run_base_read_test, setup_base_test @@ -61,3 +74,113 @@ async def test_coil_switch(hass, mock_hub, regs, expected): expected, now + timedelta(seconds=scan_interval + 1), ) + + +@pytest.mark.parametrize( + "regs,expected", + [ + ( + [0x00], + STATE_OFF, + ), + ( + [0x80], + STATE_OFF, + ), + ( + [0xFE], + STATE_OFF, + ), + ( + [0xFF], + STATE_OFF, + ), + ( + [0x01], + STATE_ON, + ), + ], +) +async def test_register_switch(hass, mock_hub, regs, expected): + """Run test for given config.""" + switch_name = "modbus_test_switch" + scan_interval = 5 + entity_id, now, device = await setup_base_test( + switch_name, + hass, + mock_hub, + { + CONF_REGISTERS: [ + { + CONF_NAME: switch_name, + CONF_REGISTER: 1234, + CONF_SLAVE: 1, + CONF_COMMAND_OFF: 0x00, + CONF_COMMAND_ON: 0x01, + }, + ] + }, + SWITCH_DOMAIN, + scan_interval, + ) + + await run_base_read_test( + entity_id, + hass, + mock_hub, + CALL_TYPE_REGISTER_HOLDING, + regs, + expected, + now + timedelta(seconds=scan_interval + 1), + ) + + +@pytest.mark.parametrize( + "regs,expected", + [ + ( + [0x40], + STATE_ON, + ), + ( + [0x04], + STATE_OFF, + ), + ( + [0xFF], + STATE_OFF, + ), + ], +) +async def test_register_state_switch(hass, mock_hub, regs, expected): + """Run test for given config.""" + switch_name = "modbus_test_switch" + scan_interval = 5 + entity_id, now, device = await setup_base_test( + switch_name, + hass, + mock_hub, + { + CONF_REGISTERS: [ + { + CONF_NAME: switch_name, + CONF_REGISTER: 1234, + CONF_SLAVE: 1, + CONF_COMMAND_OFF: 0x04, + CONF_COMMAND_ON: 0x40, + }, + ] + }, + SWITCH_DOMAIN, + scan_interval, + ) + + await run_base_read_test( + entity_id, + hass, + mock_hub, + CALL_TYPE_REGISTER_HOLDING, + regs, + expected, + now + timedelta(seconds=scan_interval + 1), + ) diff --git a/tests/components/monoprice/test_config_flow.py b/tests/components/monoprice/test_config_flow.py index e2aae6eddaa..f3530bb2c75 100644 --- a/tests/components/monoprice/test_config_flow.py +++ b/tests/components/monoprice/test_config_flow.py @@ -43,6 +43,7 @@ async def test_form(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], CONFIG ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == CONFIG[CONF_PORT] @@ -50,7 +51,6 @@ async def test_form(hass): CONF_PORT: CONFIG[CONF_PORT], CONF_SOURCES: {"1": CONFIG[CONF_SOURCE_1], "4": CONFIG[CONF_SOURCE_4]}, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/mqtt/conftest.py b/tests/components/mqtt/conftest.py index 895327d1756..5f0acc3e5c2 100644 --- a/tests/components/mqtt/conftest.py +++ b/tests/components/mqtt/conftest.py @@ -1 +1,2 @@ """Test fixtures for mqtt component.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/mqtt/test_light.py b/tests/components/mqtt/test_light.py index 102d1726ccc..9e044380555 100644 --- a/tests/components/mqtt/test_light.py +++ b/tests/components/mqtt/test_light.py @@ -311,21 +311,26 @@ async def test_controlling_state_via_topic(hass, mqtt_mock): async_fire_mqtt_message(hass, "test_light_rgb/color_temp/status", "300") light_state = hass.states.get("light.test") + assert light_state.attributes.get("color_temp") is None + + async_fire_mqtt_message(hass, "test_light_rgb/white_value/status", "100") + + light_state = hass.states.get("light.test") + assert light_state.attributes["white_value"] == 100 assert light_state.attributes["color_temp"] == 300 async_fire_mqtt_message(hass, "test_light_rgb/effect/status", "rainbow") light_state = hass.states.get("light.test") assert light_state.attributes["effect"] == "rainbow" - async_fire_mqtt_message(hass, "test_light_rgb/white_value/status", "100") - - light_state = hass.states.get("light.test") - assert light_state.attributes["white_value"] == 100 - async_fire_mqtt_message(hass, "test_light_rgb/status", "1") async_fire_mqtt_message(hass, "test_light_rgb/rgb/status", "125,125,125") + light_state = hass.states.get("light.test") + assert light_state.attributes.get("rgb_color") is None + + async_fire_mqtt_message(hass, "test_light_rgb/white_value/status", "0") light_state = hass.states.get("light.test") assert light_state.attributes.get("rgb_color") == (255, 255, 255) @@ -385,18 +390,16 @@ async def test_invalid_state_via_topic(hass, mqtt_mock, caplog): async_fire_mqtt_message(hass, "test_light_rgb/status", "1") async_fire_mqtt_message(hass, "test_light_rgb/rgb/status", "255,255,255") async_fire_mqtt_message(hass, "test_light_rgb/brightness/status", "255") - async_fire_mqtt_message(hass, "test_light_rgb/color_temp/status", "153") async_fire_mqtt_message(hass, "test_light_rgb/effect/status", "none") - async_fire_mqtt_message(hass, "test_light_rgb/white_value/status", "255") state = hass.states.get("light.test") assert state.state == STATE_ON assert state.attributes.get("rgb_color") == (255, 255, 255) assert state.attributes.get("brightness") == 255 - assert state.attributes.get("color_temp") == 153 + assert state.attributes.get("color_temp") is None assert state.attributes.get("effect") == "none" assert state.attributes.get("hs_color") == (0, 0) - assert state.attributes.get("white_value") == 255 + assert state.attributes.get("white_value") is None assert state.attributes.get("xy_color") == (0.323, 0.329) async_fire_mqtt_message(hass, "test_light_rgb/status", "") @@ -409,21 +412,11 @@ async def test_invalid_state_via_topic(hass, mqtt_mock, caplog): light_state = hass.states.get("light.test") assert light_state.attributes["brightness"] == 255 - async_fire_mqtt_message(hass, "test_light_rgb/color_temp/status", "") - assert "Ignoring empty color temp message" in caplog.text - light_state = hass.states.get("light.test") - assert light_state.attributes["color_temp"] == 153 - async_fire_mqtt_message(hass, "test_light_rgb/effect/status", "") assert "Ignoring empty effect message" in caplog.text light_state = hass.states.get("light.test") assert light_state.attributes["effect"] == "none" - async_fire_mqtt_message(hass, "test_light_rgb/white_value/status", "") - assert "Ignoring empty white value message" in caplog.text - light_state = hass.states.get("light.test") - assert light_state.attributes["white_value"] == 255 - async_fire_mqtt_message(hass, "test_light_rgb/rgb/status", "") assert "Ignoring empty rgb message" in caplog.text light_state = hass.states.get("light.test") @@ -444,6 +437,29 @@ async def test_invalid_state_via_topic(hass, mqtt_mock, caplog): light_state = hass.states.get("light.test") assert light_state.attributes.get("xy_color") == (0.323, 0.329) + async_fire_mqtt_message(hass, "test_light_rgb/color_temp/status", "153") + async_fire_mqtt_message(hass, "test_light_rgb/white_value/status", "255") + + state = hass.states.get("light.test") + assert state.state == STATE_ON + assert state.attributes.get("rgb_color") is None + assert state.attributes.get("brightness") == 255 + assert state.attributes.get("color_temp") == 153 + assert state.attributes.get("effect") == "none" + assert state.attributes.get("hs_color") is None + assert state.attributes.get("white_value") == 255 + assert state.attributes.get("xy_color") is None + + async_fire_mqtt_message(hass, "test_light_rgb/color_temp/status", "") + assert "Ignoring empty color temp message" in caplog.text + light_state = hass.states.get("light.test") + assert light_state.attributes["color_temp"] == 153 + + async_fire_mqtt_message(hass, "test_light_rgb/white_value/status", "") + assert "Ignoring empty white value message" in caplog.text + light_state = hass.states.get("light.test") + assert light_state.attributes["white_value"] == 255 + async def test_brightness_controlling_scale(hass, mqtt_mock): """Test the brightness controlling scale.""" @@ -628,6 +644,15 @@ async def test_controlling_state_via_topic_with_templates(hass, mqtt_mock): async_fire_mqtt_message( hass, "test_light_rgb/effect/status", '{"hello": "rainbow"}' ) + + state = hass.states.get("light.test") + assert state.state == STATE_ON + assert state.attributes.get("brightness") == 50 + assert state.attributes.get("rgb_color") == (84, 169, 255) + assert state.attributes.get("color_temp") is None + assert state.attributes.get("effect") == "rainbow" + assert state.attributes.get("white_value") is None + async_fire_mqtt_message( hass, "test_light_rgb/white_value/status", '{"hello": "75"}' ) @@ -635,12 +660,13 @@ async def test_controlling_state_via_topic_with_templates(hass, mqtt_mock): state = hass.states.get("light.test") assert state.state == STATE_ON assert state.attributes.get("brightness") == 50 - assert state.attributes.get("rgb_color") == (84, 169, 255) + assert state.attributes.get("rgb_color") is None assert state.attributes.get("color_temp") == 300 assert state.attributes.get("effect") == "rainbow" assert state.attributes.get("white_value") == 75 async_fire_mqtt_message(hass, "test_light_rgb/hs/status", '{"hello": [100,50]}') + async_fire_mqtt_message(hass, "test_light_rgb/white_value/status", '{"hello": "0"}') state = hass.states.get("light.test") assert state.attributes.get("hs_color") == (100, 50) @@ -710,7 +736,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): "hs_color": [100, 100], "effect": "random", "color_temp": 100, - "white_value": 50, + # TODO: Test restoring state with white_value + "white_value": 0, }, ) with patch( @@ -726,8 +753,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): assert state.attributes.get("brightness") == 95 assert state.attributes.get("hs_color") == (100, 100) assert state.attributes.get("effect") == "random" - assert state.attributes.get("color_temp") == 100 - assert state.attributes.get("white_value") == 50 + assert state.attributes.get("color_temp") is None + assert state.attributes.get("white_value") is None assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_turn_on(hass, "light.test") @@ -754,7 +781,6 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): ) await common.async_turn_on(hass, "light.test", brightness=50, hs_color=[359, 78]) await common.async_turn_on(hass, "light.test", rgb_color=[255, 128, 0]) - await common.async_turn_on(hass, "light.test", white_value=80, color_temp=125) mqtt_mock.async_publish.assert_has_calls( [ @@ -762,9 +788,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): call("test_light_rgb/rgb/set", "255,128,0", 2, False), call("test_light_rgb/brightness/set", "50", 2, False), call("test_light_rgb/hs/set", "359.0,78.0", 2, False), - call("test_light_rgb/white_value/set", "80", 2, False), call("test_light_rgb/xy/set", "0.14,0.131", 2, False), - call("test_light_rgb/color_temp/set", "125", 2, False), ], any_order=True, ) @@ -774,8 +798,28 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): assert state.attributes["rgb_color"] == (255, 128, 0) assert state.attributes["brightness"] == 50 assert state.attributes["hs_color"] == (30.118, 100) - assert state.attributes["white_value"] == 80 + assert state.attributes.get("white_value") is None assert state.attributes["xy_color"] == (0.611, 0.375) + assert state.attributes.get("color_temp") is None + + await common.async_turn_on(hass, "light.test", white_value=80, color_temp=125) + + mqtt_mock.async_publish.assert_has_calls( + [ + call("test_light_rgb/white_value/set", "80", 2, False), + call("test_light_rgb/color_temp/set", "125", 2, False), + ], + any_order=True, + ) + + state = hass.states.get("light.test") + assert state.state == STATE_ON + assert state.attributes.get("rgb_color") is None + assert state.attributes["brightness"] == 50 + assert state.attributes.get("hs_color") is None + assert state.attributes["white_value"] == 80 + assert state.attributes.get("xy_color") is None + assert state.attributes["color_temp"] == 125 async def test_sending_mqtt_rgb_command_with_template(hass, mqtt_mock): @@ -1385,11 +1429,16 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog [ ( "test_light_rgb/state1", - '{"state1":{"state":"ON", "brightness":100, "ct":123, "fx":"cycle"}}', + '{"state1":{"state":"ON", "brightness":100, "ct":123, "white":100, "fx":"cycle"}}', ) ], "on", - [("brightness", 100), ("color_temp", 123), ("effect", "cycle")], + [ + ("brightness", 100), + ("color_temp", 123), + ("white_value", 100), + ("effect", "cycle"), + ], ), ( [("test_light_rgb/state1", '{"state1":{"state":"OFF"}}')], @@ -1400,11 +1449,11 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog [ ( "test_light_rgb/state1", - '{"state1":{"state":"ON", "hs":"1,2"}}', + '{"state1":{"state":"ON", "hs":"1,2", "white":0}}', ) ], "on", - [("hs_color", (1, 2))], + [("hs_color", (1, 2)), ("white_value", None)], ), ( [ @@ -1420,11 +1469,11 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog [ ( "test_light_rgb/state1", - '{"state1":{"white":50, "xy":"0.3, 0.4"}}', + '{"state1":{"xy":"0.3, 0.4"}}', ) ], "on", - [("white_value", 50), ("xy_color", (0.3, 0.401))], + [("xy_color", (0.3, 0.401))], ), ] state_data2 = [ @@ -1432,11 +1481,16 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog [ ( "test_light_rgb/state2", - '{"state2":{"state":"ON", "brightness":50, "ct":200, "fx":"loop"}}', + '{"state2":{"state":"ON", "brightness":50, "ct":200, "white":50, "fx":"loop"}}', ) ], "on", - [("brightness", 50), ("color_temp", 200), ("effect", "loop")], + [ + ("brightness", 50), + ("color_temp", 200), + ("white_value", 50), + ("effect", "loop"), + ], ), ( [ @@ -1480,11 +1534,11 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog [ ( "test_light_rgb/state2", - '{"state2":{"state":"ON", "hs":"1.2,2.2"}}', + '{"state2":{"state":"ON", "hs":"1.2,2.2", "white":0}}', ) ], "on", - [("hs_color", (1.2, 2.2))], + [("hs_color", (1.2, 2.2)), ("white_value", None)], ), ( [ @@ -1536,11 +1590,11 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog [ ( "test_light_rgb/state2", - '{"state2":{"white":75, "xy":"0.4, 0.3"}}', + '{"state2":{"xy":"0.4, 0.3"}}', ) ], "on", - [("white_value", 75), ("xy_color", (0.4, 0.3))], + [("xy_color", (0.4, 0.3))], ), ( [ @@ -1558,7 +1612,7 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog ), ], "on", - [("white_value", 75), ("xy_color", (0.4, 0.3))], + [("xy_color", (0.4, 0.3))], ), ] @@ -1640,11 +1694,16 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog): [ ( "test_light_rgb/state1", - '{"state1":{"state":"ON", "brightness":100, "ct":123, "fx":"cycle"}}', + '{"state1":{"state":"ON", "brightness":100, "ct":123, "white":100, "fx":"cycle"}}', ) ], "on", - [("brightness", 100), ("color_temp", 123), ("effect", "cycle")], + [ + ("brightness", 100), + ("color_temp", 123), + ("white_value", 100), + ("effect", "cycle"), + ], ), ( [("test_light_rgb/state1", '{"state1":{"state":"OFF"}}')], @@ -1655,7 +1714,7 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog): [ ( "test_light_rgb/state1", - '{"state1":{"state":"ON", "hs":"1,2"}}', + '{"state1":{"state":"ON", "hs":"1,2", "white":0}}', ) ], "on", @@ -1675,11 +1734,11 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog): [ ( "test_light_rgb/state1", - '{"state1":{"white":50, "xy":"0.3, 0.4"}}', + '{"state1":{"white":0, "xy":"0.3, 0.4"}}', ) ], "on", - [("white_value", 50), ("xy_color", (0.3, 0.401))], + [("white_value", None), ("xy_color", (0.3, 0.401))], ), ] state_data2 = [ @@ -1687,11 +1746,16 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog): [ ( "test_light_rgb/state1", - '{"state2":{"state":"ON", "brightness":50, "ct":200, "fx":"loop"}}', + '{"state2":{"state":"ON", "brightness":50, "ct":200, "white":50, "fx":"loop"}}', ) ], "on", - [("brightness", 50), ("color_temp", 200), ("effect", "loop")], + [ + ("brightness", 50), + ("color_temp", 200), + ("white_value", 50), + ("effect", "loop"), + ], ), ( [ @@ -1717,7 +1781,7 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog): [ ( "test_light_rgb/state1", - '{"state2":{"state":"ON", "hs":"1.2,2.2"}}', + '{"state2":{"state":"ON", "hs":"1.2,2.2", "white":0}}', ) ], "on", @@ -1757,11 +1821,11 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog): [ ( "test_light_rgb/state1", - '{"state2":{"white":75, "xy":"0.4, 0.3"}}', + '{"state2":{"xy":"0.4, 0.3"}}', ) ], "on", - [("white_value", 75), ("xy_color", (0.4, 0.3))], + [("white_value", None), ("xy_color", (0.4, 0.3))], ), ( [ @@ -1771,7 +1835,7 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog): ) ], "on", - [("white_value", 75), ("xy_color", (0.4, 0.3))], + [("white_value", None), ("xy_color", (0.4, 0.3))], ), ] diff --git a/tests/components/mqtt/test_subscription.py b/tests/components/mqtt/test_subscription.py index 19797f28c3f..f1ed26e89cc 100644 --- a/tests/components/mqtt/test_subscription.py +++ b/tests/components/mqtt/test_subscription.py @@ -160,21 +160,35 @@ async def test_qos_encoding_custom(hass, mqtt_mock, caplog): async def test_no_change(hass, mqtt_mock, caplog): """Test subscription to topics without change.""" + calls = [] + @callback - def msg_callback(*args): - """Do nothing.""" - pass + def record_calls(*args): + """Record calls.""" + calls.append(args) sub_state = None sub_state = await async_subscribe_topics( hass, sub_state, - {"test_topic1": {"topic": "test-topic1", "msg_callback": msg_callback}}, + {"test_topic1": {"topic": "test-topic1", "msg_callback": record_calls}}, ) - call_count = mqtt_mock.async_subscribe.call_count + subscribe_call_count = mqtt_mock.async_subscribe.call_count + + async_fire_mqtt_message(hass, "test-topic1", "test-payload") + assert len(calls) == 1 + sub_state = await async_subscribe_topics( hass, sub_state, - {"test_topic1": {"topic": "test-topic1", "msg_callback": msg_callback}}, + {"test_topic1": {"topic": "test-topic1", "msg_callback": record_calls}}, ) - assert call_count == mqtt_mock.async_subscribe.call_count + assert subscribe_call_count == mqtt_mock.async_subscribe.call_count + + async_fire_mqtt_message(hass, "test-topic1", "test-payload") + assert len(calls) == 2 + + await async_unsubscribe_topics(hass, sub_state) + + async_fire_mqtt_message(hass, "test-topic1", "test-payload") + assert len(calls) == 2 diff --git a/tests/components/mqtt_statestream/test_init.py b/tests/components/mqtt_statestream/test_init.py index a3b3c1ccfea..cea4b492f3e 100644 --- a/tests/components/mqtt_statestream/test_init.py +++ b/tests/components/mqtt_statestream/test_init.py @@ -1,6 +1,4 @@ """The tests for the MQTT statestream component.""" -import pytest - import homeassistant.components.mqtt_statestream as statestream from homeassistant.core import State from homeassistant.setup import async_setup_component @@ -9,11 +7,6 @@ from tests.async_mock import ANY, call from tests.common import mock_state_change_event -@pytest.fixture(autouse=True) -def mock_storage(hass_storage): - """Autouse hass_storage for the TestCase tests.""" - - async def add_statestream( hass, base_topic=None, diff --git a/tests/components/myq/test_config_flow.py b/tests/components/myq/test_config_flow.py index 4d1bf7db683..e2c43e8ce5c 100644 --- a/tests/components/myq/test_config_flow.py +++ b/tests/components/myq/test_config_flow.py @@ -31,6 +31,7 @@ async def test_form_user(hass): result["flow_id"], {"username": "test-username", "password": "test-password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "test-username" @@ -38,7 +39,6 @@ async def test_form_user(hass): "username": "test-username", "password": "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -61,6 +61,7 @@ async def test_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data={"username": "test-username", "password": "test-password"}, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "test-username" @@ -68,7 +69,6 @@ async def test_import(hass): "username": "test-username", "password": "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/nest/camera_sdm_test.py b/tests/components/nest/camera_sdm_test.py new file mode 100644 index 00000000000..e3397129ec9 --- /dev/null +++ b/tests/components/nest/camera_sdm_test.py @@ -0,0 +1,355 @@ +""" +Test for Nest cameras platform for the Smart Device Management API. + +These tests fake out the subscriber/devicemanager, and are not using a real +pubsub subscriber. +""" + +import datetime +from typing import List + +from aiohttp.client_exceptions import ClientConnectionError +from google_nest_sdm.auth import AbstractAuth +from google_nest_sdm.device import Device + +from homeassistant.components import camera +from homeassistant.components.camera import STATE_IDLE +from homeassistant.util.dt import utcnow + +from .common import async_setup_sdm_platform + +from tests.async_mock import patch +from tests.common import async_fire_time_changed + +PLATFORM = "camera" +CAMERA_DEVICE_TYPE = "sdm.devices.types.CAMERA" +DEVICE_ID = "some-device-id" +DEVICE_TRAITS = { + "sdm.devices.traits.Info": { + "customName": "My Camera", + }, + "sdm.devices.traits.CameraLiveStream": { + "maxVideoResolution": { + "width": 640, + "height": 480, + }, + "videoCodecs": ["H264"], + "audioCodecs": ["AAC"], + }, +} +DATETIME_FORMAT = "YY-MM-DDTHH:MM:SS" +DOMAIN = "nest" + + +class FakeResponse: + """A fake web response used for returning results of commands.""" + + def __init__(self, json=None, error=None): + """Initialize the FakeResponse.""" + self._json = json + self._error = error + + def raise_for_status(self): + """Mimics a successful response status.""" + if self._error: + raise self._error + pass + + async def json(self): + """Return a dict with the response.""" + assert self._json + return self._json + + +class FakeAuth(AbstractAuth): + """Fake authentication object that returns fake responses.""" + + def __init__(self, responses: List[FakeResponse]): + """Initialize the FakeAuth.""" + super().__init__(None, "") + self._responses = responses + + async def async_get_access_token(self): + """Return a fake access token.""" + return "some-token" + + async def creds(self): + """Return a fake creds.""" + return None + + async def request(self, method: str, url: str, **kwargs): + """Pass through the FakeResponse.""" + return self._responses.pop(0) + + +async def async_setup_camera(hass, traits={}, auth=None): + """Set up the platform and prerequisites.""" + devices = {} + if traits: + devices[DEVICE_ID] = Device.MakeDevice( + { + "name": DEVICE_ID, + "type": CAMERA_DEVICE_TYPE, + "traits": traits, + }, + auth=auth, + ) + return await async_setup_sdm_platform(hass, PLATFORM, devices) + + +async def fire_alarm(hass, point_in_time): + """Fire an alarm and wait for callbacks to run.""" + with patch("homeassistant.util.dt.utcnow", return_value=point_in_time): + async_fire_time_changed(hass, point_in_time) + await hass.async_block_till_done() + + +async def test_no_devices(hass): + """Test configuration that returns no devices.""" + await async_setup_camera(hass) + assert len(hass.states.async_all()) == 0 + + +async def test_ineligible_device(hass): + """Test configuration with devices that do not support cameras.""" + await async_setup_camera( + hass, + { + "sdm.devices.traits.Info": { + "customName": "My Camera", + }, + }, + ) + assert len(hass.states.async_all()) == 0 + + +async def test_camera_device(hass): + """Test a basic camera with a live stream.""" + await async_setup_camera(hass, DEVICE_TRAITS) + + assert len(hass.states.async_all()) == 1 + camera = hass.states.get("camera.my_camera") + assert camera is not None + assert camera.state == STATE_IDLE + + registry = await hass.helpers.entity_registry.async_get_registry() + entry = registry.async_get("camera.my_camera") + assert entry.unique_id == "some-device-id-camera" + assert entry.original_name == "My Camera" + assert entry.domain == "camera" + + device_registry = await hass.helpers.device_registry.async_get_registry() + device = device_registry.async_get(entry.device_id) + assert device.name == "My Camera" + assert device.model == "Camera" + assert device.identifiers == {("nest", DEVICE_ID)} + + +async def test_camera_stream(hass, aiohttp_client): + """Test a basic camera and fetch its live stream.""" + now = utcnow() + expiration = now + datetime.timedelta(seconds=100) + response = FakeResponse( + { + "results": { + "streamUrls": {"rtspUrl": "rtsp://some/url?auth=g.0.streamingToken"}, + "streamExtensionToken": "g.1.extensionToken", + "streamToken": "g.0.streamingToken", + "expiresAt": expiration.isoformat(timespec="seconds"), + }, + } + ) + await async_setup_camera(hass, DEVICE_TRAITS, auth=FakeAuth([response])) + + assert len(hass.states.async_all()) == 1 + cam = hass.states.get("camera.my_camera") + assert cam is not None + assert cam.state == STATE_IDLE + + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.0.streamingToken" + + with patch( + "homeassistant.components.ffmpeg.ImageFrame.get_image", + autopatch=True, + return_value=b"image bytes", + ): + image = await camera.async_get_image(hass, "camera.my_camera") + + assert image.content == b"image bytes" + + +async def test_refresh_expired_stream_token(hass, aiohttp_client): + """Test a camera stream expiration and refresh.""" + now = utcnow() + stream_1_expiration = now + datetime.timedelta(seconds=90) + stream_2_expiration = now + datetime.timedelta(seconds=180) + stream_3_expiration = now + datetime.timedelta(seconds=360) + responses = [ + # Stream URL #1 + FakeResponse( + { + "results": { + "streamUrls": { + "rtspUrl": "rtsp://some/url?auth=g.1.streamingToken" + }, + "streamExtensionToken": "g.1.extensionToken", + "streamToken": "g.1.streamingToken", + "expiresAt": stream_1_expiration.isoformat(timespec="seconds"), + }, + } + ), + # Stream URL #2 + FakeResponse( + { + "results": { + "streamExtensionToken": "g.2.extensionToken", + "streamToken": "g.2.streamingToken", + "expiresAt": stream_2_expiration.isoformat(timespec="seconds"), + }, + } + ), + # Stream URL #3 + FakeResponse( + { + "results": { + "streamExtensionToken": "g.3.extensionToken", + "streamToken": "g.3.streamingToken", + "expiresAt": stream_3_expiration.isoformat(timespec="seconds"), + }, + } + ), + ] + await async_setup_camera( + hass, + DEVICE_TRAITS, + auth=FakeAuth(responses), + ) + + assert len(hass.states.async_all()) == 1 + cam = hass.states.get("camera.my_camera") + assert cam is not None + assert cam.state == STATE_IDLE + + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.1.streamingToken" + + # Fire alarm before stream_1_expiration. The stream url is not refreshed + next_update = now + datetime.timedelta(seconds=25) + await fire_alarm(hass, next_update) + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.1.streamingToken" + + # Alarm is near stream_1_expiration which causes the stream extension + next_update = now + datetime.timedelta(seconds=65) + await fire_alarm(hass, next_update) + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.2.streamingToken" + + # Next alarm is well before stream_2_expiration, no change + next_update = now + datetime.timedelta(seconds=100) + await fire_alarm(hass, next_update) + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.2.streamingToken" + + # Alarm is near stream_2_expiration, causing it to be extended + next_update = now + datetime.timedelta(seconds=155) + await fire_alarm(hass, next_update) + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.3.streamingToken" + + +async def test_camera_removed(hass, aiohttp_client): + """Test case where entities are removed and stream tokens expired.""" + now = utcnow() + expiration = now + datetime.timedelta(seconds=100) + responses = [ + FakeResponse( + { + "results": { + "streamUrls": { + "rtspUrl": "rtsp://some/url?auth=g.0.streamingToken" + }, + "streamExtensionToken": "g.1.extensionToken", + "streamToken": "g.0.streamingToken", + "expiresAt": expiration.isoformat(timespec="seconds"), + }, + } + ), + FakeResponse({"results": {}}), + ] + await async_setup_camera( + hass, + DEVICE_TRAITS, + auth=FakeAuth(responses), + ) + + assert len(hass.states.async_all()) == 1 + cam = hass.states.get("camera.my_camera") + assert cam is not None + assert cam.state == STATE_IDLE + + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.0.streamingToken" + + for config_entry in hass.config_entries.async_entries(DOMAIN): + await hass.config_entries.async_remove(config_entry.entry_id) + assert len(hass.states.async_all()) == 0 + + +async def test_refresh_expired_stream_failure(hass, aiohttp_client): + """Tests a failure when refreshing the stream.""" + now = utcnow() + stream_1_expiration = now + datetime.timedelta(seconds=90) + stream_2_expiration = now + datetime.timedelta(seconds=180) + responses = [ + FakeResponse( + { + "results": { + "streamUrls": { + "rtspUrl": "rtsp://some/url?auth=g.1.streamingToken" + }, + "streamExtensionToken": "g.1.extensionToken", + "streamToken": "g.1.streamingToken", + "expiresAt": stream_1_expiration.isoformat(timespec="seconds"), + }, + } + ), + # Extending the stream fails with arbitrary error + FakeResponse(error=ClientConnectionError()), + # Next attempt to get a stream fetches a new url + FakeResponse( + { + "results": { + "streamUrls": { + "rtspUrl": "rtsp://some/url?auth=g.2.streamingToken" + }, + "streamExtensionToken": "g.2.extensionToken", + "streamToken": "g.2.streamingToken", + "expiresAt": stream_2_expiration.isoformat(timespec="seconds"), + }, + } + ), + ] + await async_setup_camera( + hass, + DEVICE_TRAITS, + auth=FakeAuth(responses), + ) + + assert len(hass.states.async_all()) == 1 + cam = hass.states.get("camera.my_camera") + assert cam is not None + assert cam.state == STATE_IDLE + + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.1.streamingToken" + + # Fire alarm when stream is nearing expiration, causing it to be extended. + # The stream expires. + next_update = now + datetime.timedelta(seconds=65) + await fire_alarm(hass, next_update) + + # The stream is entirely refreshed + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.2.streamingToken" diff --git a/tests/components/nest/climate_sdm_test.py b/tests/components/nest/climate_sdm_test.py new file mode 100644 index 00000000000..48efd32d859 --- /dev/null +++ b/tests/components/nest/climate_sdm_test.py @@ -0,0 +1,868 @@ +""" +Test for Nest climate platform for the Smart Device Management API. + +These tests fake out the subscriber/devicemanager, and are not using a real +pubsub subscriber. +""" + +from google_nest_sdm.device import Device +from google_nest_sdm.event import EventMessage + +from homeassistant.components.climate.const import ( + ATTR_CURRENT_TEMPERATURE, + ATTR_FAN_MODE, + ATTR_FAN_MODES, + ATTR_HVAC_ACTION, + ATTR_HVAC_MODES, + ATTR_PRESET_MODE, + ATTR_PRESET_MODES, + ATTR_TARGET_TEMP_HIGH, + ATTR_TARGET_TEMP_LOW, + CURRENT_HVAC_COOL, + CURRENT_HVAC_HEAT, + CURRENT_HVAC_OFF, + FAN_OFF, + FAN_ON, + HVAC_MODE_COOL, + HVAC_MODE_HEAT, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + PRESET_ECO, + PRESET_NONE, +) +from homeassistant.const import ATTR_TEMPERATURE + +from .common import async_setup_sdm_platform + +from tests.components.climate import common + +PLATFORM = "climate" + + +async def setup_climate(hass, raw_traits=None, auth=None): + """Load Nest climate devices.""" + devices = None + if raw_traits: + traits = raw_traits + traits["sdm.devices.traits.Info"] = {"customName": "My Thermostat"} + devices = { + "some-device-id": Device.MakeDevice( + { + "name": "some-device-id", + "type": "sdm.devices.types.Thermostat", + "traits": traits, + }, + auth=auth, + ), + } + return await async_setup_sdm_platform(hass, PLATFORM, devices) + + +async def test_no_devices(hass): + """Test no devices returned by the api.""" + await setup_climate(hass) + assert len(hass.states.async_all()) == 0 + + +async def test_climate_devices(hass): + """Test no eligible climate devices returned by the api.""" + await setup_climate(hass, {"sdm.devices.traits.CameraImage": {}}) + assert len(hass.states.async_all()) == 0 + + +async def test_thermostat_off(hass): + """Test a thermostat that is not running.""" + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "OFF", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 16.2, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 16.2 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_TEMPERATURE] is None + assert thermostat.attributes[ATTR_TARGET_TEMP_LOW] is None + assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] is None + assert ATTR_PRESET_MODE not in thermostat.attributes + assert ATTR_PRESET_MODES not in thermostat.attributes + assert ATTR_FAN_MODE not in thermostat.attributes + assert ATTR_FAN_MODES not in thermostat.attributes + + +async def test_thermostat_heat(hass): + """Test a thermostat that is heating.""" + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": { + "status": "HEATING", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEAT", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 16.2, + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "heatCelsius": 22.0, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_HEAT + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 16.2 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_TEMPERATURE] == 22.0 + assert thermostat.attributes[ATTR_TARGET_TEMP_LOW] is None + assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] is None + assert ATTR_PRESET_MODE not in thermostat.attributes + assert ATTR_PRESET_MODES not in thermostat.attributes + + +async def test_thermostat_cool(hass): + """Test a thermostat that is cooling.""" + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": { + "status": "COOLING", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "COOL", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 29.9, + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "coolCelsius": 28.0, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_COOL + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_COOL + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 29.9 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_TEMPERATURE] == 28.0 + assert thermostat.attributes[ATTR_TARGET_TEMP_LOW] is None + assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] is None + assert ATTR_PRESET_MODE not in thermostat.attributes + assert ATTR_PRESET_MODES not in thermostat.attributes + + +async def test_thermostat_heatcool(hass): + """Test a thermostat that is cooling in heatcool mode.""" + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": { + "status": "COOLING", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEATCOOL", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 29.9, + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "heatCelsius": 22.0, + "coolCelsius": 28.0, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT_COOL + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_COOL + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 29.9 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_TARGET_TEMP_LOW] == 22.0 + assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] == 28.0 + assert thermostat.attributes[ATTR_TEMPERATURE] is None + assert ATTR_PRESET_MODE not in thermostat.attributes + assert ATTR_PRESET_MODES not in thermostat.attributes + + +async def test_thermostat_eco_off(hass): + """Test a thermostat cooling with eco off.""" + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": { + "status": "COOLING", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEATCOOL", + }, + "sdm.devices.traits.ThermostatEco": { + "availableModes": ["MANUAL_ECO", "OFF"], + "mode": "OFF", + "heatCelsius": 20.0, + "coolCelsius": 22.0, + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 29.9, + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "heatCelsius": 22.0, + "coolCelsius": 28.0, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT_COOL + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_COOL + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 29.9 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_TARGET_TEMP_LOW] == 22.0 + assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] == 28.0 + assert thermostat.attributes[ATTR_TEMPERATURE] is None + assert thermostat.attributes[ATTR_PRESET_MODE] == PRESET_NONE + assert thermostat.attributes[ATTR_PRESET_MODES] == [PRESET_ECO, PRESET_NONE] + + +async def test_thermostat_eco_on(hass): + """Test a thermostat in eco mode.""" + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": { + "status": "COOLING", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEATCOOL", + }, + "sdm.devices.traits.ThermostatEco": { + "availableModes": ["MANUAL_ECO", "OFF"], + "mode": "MANUAL_ECO", + "heatCelsius": 21.0, + "coolCelsius": 29.0, + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 29.9, + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "heatCelsius": 22.0, + "coolCelsius": 28.0, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT_COOL + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_COOL + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 29.9 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_TARGET_TEMP_LOW] == 21.0 + assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] == 29.0 + assert thermostat.attributes[ATTR_TEMPERATURE] is None + assert thermostat.attributes[ATTR_PRESET_MODE] == PRESET_ECO + assert thermostat.attributes[ATTR_PRESET_MODES] == [PRESET_ECO, PRESET_NONE] + + +async def test_thermostat_eco_heat_only(hass): + """Test a thermostat in eco mode that only supports heat.""" + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": { + "status": "OFF", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "OFF"], + "mode": "HEAT", + }, + "sdm.devices.traits.ThermostatEco": { + "availableModes": ["MANUAL_ECO", "OFF"], + "mode": "MANUAL_ECO", + "heatCelsius": 21.0, + "coolCelsius": 29.0, + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 29.9, + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": {}, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 29.9 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_TEMPERATURE] == 21.0 + assert ATTR_TARGET_TEMP_LOW not in thermostat.attributes + assert ATTR_TARGET_TEMP_HIGH not in thermostat.attributes + assert thermostat.attributes[ATTR_PRESET_MODE] == PRESET_ECO + assert thermostat.attributes[ATTR_PRESET_MODES] == [PRESET_ECO, PRESET_NONE] + + +class FakeAuth: + """A fake implementation of the auth class that records requests.""" + + def __init__(self): + """Initialize FakeAuth.""" + self.method = None + self.url = None + self.json = None + + async def request(self, method, url, json): + """Capure the request arguments for tests to assert on.""" + self.method = method + self.url = url + self.json = json + + +async def test_thermostat_set_hvac_mode(hass): + """Test a thermostat changing hvac modes.""" + auth = FakeAuth() + subscriber = await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "OFF", + }, + }, + auth=auth, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + + await common.async_set_hvac_mode(hass, HVAC_MODE_HEAT) + await hass.async_block_till_done() + + assert auth.method == "post" + assert auth.url == "some-device-id:executeCommand" + assert auth.json == { + "command": "sdm.devices.commands.ThermostatMode.SetMode", + "params": {"mode": "HEAT"}, + } + + # Local state does not reflect the update + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + + # Simulate pubsub message when mode changes + event = EventMessage( + { + "eventId": "some-event-id", + "timestamp": "2019-01-01T00:00:01Z", + "resourceUpdate": { + "name": "some-device-id", + "traits": { + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEAT", + }, + }, + }, + }, + auth=None, + ) + subscriber.receive_event(event) + await hass.async_block_till_done() # Process dispatch/update signal + + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + + # Simulate pubsub message when the thermostat starts heating + event = EventMessage( + { + "eventId": "some-event-id", + "timestamp": "2019-01-01T00:00:01Z", + "resourceUpdate": { + "name": "some-device-id", + "traits": { + "sdm.devices.traits.ThermostatHvac": { + "status": "HEATING", + }, + }, + }, + }, + auth=None, + ) + subscriber.receive_event(event) + await hass.async_block_till_done() # Process dispatch/update signal + + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_HEAT + + +async def test_thermostat_set_eco_preset(hass): + """Test a thermostat put into eco mode.""" + auth = FakeAuth() + subscriber = await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatEco": { + "availableModes": ["MANUAL_ECO", "OFF"], + "mode": "OFF", + "heatCelsius": 15.0, + "coolCelsius": 28.0, + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "OFF", + }, + }, + auth=auth, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + assert thermostat.attributes[ATTR_PRESET_MODE] == PRESET_NONE + + # Turn on eco mode + await common.async_set_preset_mode(hass, PRESET_ECO) + await hass.async_block_till_done() + + assert auth.method == "post" + assert auth.url == "some-device-id:executeCommand" + assert auth.json == { + "command": "sdm.devices.commands.ThermostatEco.SetMode", + "params": {"mode": "MANUAL_ECO"}, + } + + # Local state does not reflect the update + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + assert thermostat.attributes[ATTR_PRESET_MODE] == PRESET_NONE + + # Simulate pubsub message when mode changes + event = EventMessage( + { + "eventId": "some-event-id", + "timestamp": "2019-01-01T00:00:01Z", + "resourceUpdate": { + "name": "some-device-id", + "traits": { + "sdm.devices.traits.ThermostatEco": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "MANUAL_ECO", + "heatCelsius": 15.0, + "coolCelsius": 28.0, + }, + }, + }, + }, + auth=auth, + ) + subscriber.receive_event(event) + await hass.async_block_till_done() # Process dispatch/update signal + + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + assert thermostat.attributes[ATTR_PRESET_MODE] == PRESET_ECO + + # Turn off eco mode + await common.async_set_preset_mode(hass, PRESET_NONE) + await hass.async_block_till_done() + + assert auth.method == "post" + assert auth.url == "some-device-id:executeCommand" + assert auth.json == { + "command": "sdm.devices.commands.ThermostatEco.SetMode", + "params": {"mode": "OFF"}, + } + + +async def test_thermostat_set_cool(hass): + """Test a thermostat in cool mode with a temperature change.""" + auth = FakeAuth() + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "COOL", + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "coolCelsius": 25.0, + }, + }, + auth=auth, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_COOL + + await common.async_set_temperature(hass, temperature=24.0) + await hass.async_block_till_done() + + assert auth.method == "post" + assert auth.url == "some-device-id:executeCommand" + assert auth.json == { + "command": "sdm.devices.commands.ThermostatTemperatureSetpoint.SetCool", + "params": {"coolCelsius": 24.0}, + } + + +async def test_thermostat_set_heat(hass): + """Test a thermostat heating mode with a temperature change.""" + auth = FakeAuth() + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEAT", + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "heatCelsius": 19.0, + }, + }, + auth=auth, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT + + await common.async_set_temperature(hass, temperature=20.0) + await hass.async_block_till_done() + + assert auth.method == "post" + assert auth.url == "some-device-id:executeCommand" + assert auth.json == { + "command": "sdm.devices.commands.ThermostatTemperatureSetpoint.SetHeat", + "params": {"heatCelsius": 20.0}, + } + + +async def test_thermostat_set_heat_cool(hass): + """Test a thermostat in heatcool mode with a temperature change.""" + auth = FakeAuth() + await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEATCOOL", + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "heatCelsius": 19.0, + "coolCelsius": 25.0, + }, + }, + auth=auth, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT_COOL + + await common.async_set_temperature( + hass, target_temp_low=20.0, target_temp_high=24.0 + ) + await hass.async_block_till_done() + + assert auth.method == "post" + assert auth.url == "some-device-id:executeCommand" + assert auth.json == { + "command": "sdm.devices.commands.ThermostatTemperatureSetpoint.SetRange", + "params": {"heatCelsius": 20.0, "coolCelsius": 24.0}, + } + + +async def test_thermostat_fan_off(hass): + """Test a thermostat with the fan not running.""" + await setup_climate( + hass, + { + "sdm.devices.traits.Fan": { + "timerMode": "OFF", + "timerTimeout": "2019-05-10T03:22:54Z", + }, + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "OFF", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 16.2, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 16.2 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_FAN_MODE] == FAN_OFF + assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF] + + +async def test_thermostat_fan_on(hass): + """Test a thermostat with the fan running.""" + await setup_climate( + hass, + { + "sdm.devices.traits.Fan": { + "timerMode": "ON", + "timerTimeout": "2019-05-10T03:22:54Z", + }, + "sdm.devices.traits.ThermostatHvac": { + "status": "OFF", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "OFF", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 16.2, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 16.2 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert thermostat.attributes[ATTR_FAN_MODE] == FAN_ON + assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF] + + +async def test_thermostat_set_fan(hass): + """Test a thermostat enabling the fan.""" + auth = FakeAuth() + await setup_climate( + hass, + { + "sdm.devices.traits.Fan": { + "timerMode": "ON", + "timerTimeout": "2019-05-10T03:22:54Z", + }, + "sdm.devices.traits.ThermostatHvac": { + "status": "OFF", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "OFF", + }, + }, + auth=auth, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_FAN_MODE] == FAN_ON + assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF] + + # Turn off fan mode + await common.async_set_fan_mode(hass, FAN_OFF) + await hass.async_block_till_done() + + assert auth.method == "post" + assert auth.url == "some-device-id:executeCommand" + assert auth.json == { + "command": "sdm.devices.commands.Fan.SetTimer", + "params": {"timerMode": "OFF"}, + } + + +async def test_thermostat_fan_empty(hass): + """Test a fan trait with an empty response.""" + await setup_climate( + hass, + { + "sdm.devices.traits.Fan": {}, + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "OFF", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 16.2, + }, + }, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_OFF + assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF + assert thermostat.attributes[ATTR_CURRENT_TEMPERATURE] == 16.2 + assert set(thermostat.attributes[ATTR_HVAC_MODES]) == { + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, + } + assert ATTR_FAN_MODE not in thermostat.attributes + assert ATTR_FAN_MODES not in thermostat.attributes + + +async def test_thermostat_target_temp(hass): + """Test a thermostat changing hvac modes and affected on target temps.""" + auth = FakeAuth() + subscriber = await setup_climate( + hass, + { + "sdm.devices.traits.ThermostatHvac": { + "status": "HEATING", + }, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEAT", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 20.1, + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "heatCelsius": 23.0, + }, + }, + auth=auth, + ) + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT + assert thermostat.attributes[ATTR_TEMPERATURE] == 23.0 + assert thermostat.attributes[ATTR_TARGET_TEMP_LOW] is None + assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] is None + + # Simulate pubsub message changing modes + event = EventMessage( + { + "eventId": "some-event-id", + "timestamp": "2019-01-01T00:00:01Z", + "resourceUpdate": { + "name": "some-device-id", + "traits": { + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEATCOOL", + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": { + "heatCelsius": 22.0, + "coolCelsius": 28.0, + }, + }, + }, + }, + auth=None, + ) + subscriber.receive_event(event) + await hass.async_block_till_done() # Process dispatch/update signal + + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVAC_MODE_HEAT_COOL + assert thermostat.attributes[ATTR_TARGET_TEMP_LOW] == 22.0 + assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] == 28.0 + assert thermostat.attributes[ATTR_TEMPERATURE] is None diff --git a/tests/components/nest/common.py b/tests/components/nest/common.py new file mode 100644 index 00000000000..c1c8dbd04d7 --- /dev/null +++ b/tests/components/nest/common.py @@ -0,0 +1,99 @@ +"""Common libraries for test setup.""" + +import time + +from google_nest_sdm.device_manager import DeviceManager +from google_nest_sdm.event import EventCallback, EventMessage +from google_nest_sdm.google_nest_subscriber import GoogleNestSubscriber + +from homeassistant.components.nest import DOMAIN +from homeassistant.setup import async_setup_component + +from tests.async_mock import patch +from tests.common import MockConfigEntry + +CONFIG = { + "nest": { + "client_id": "some-client-id", + "client_secret": "some-client-secret", + # Required fields for using SDM API + "project_id": "some-project-id", + "subscriber_id": "some-subscriber-id", + }, +} + +CONFIG_ENTRY_DATA = { + "sdm": {}, # Indicates new SDM API, not legacy API + "auth_implementation": "local", + "token": { + "expires_at": time.time() + 86400, + "access_token": { + "token": "some-token", + }, + }, +} + + +class FakeDeviceManager(DeviceManager): + """Fake DeviceManager that can supply a list of devices and structures.""" + + def __init__(self, devices: dict, structures: dict): + """Initialize FakeDeviceManager.""" + super().__init__() + self._devices = devices + + @property + def structures(self) -> dict: + """Override structures with fake result.""" + return self._structures + + @property + def devices(self) -> dict: + """Override devices with fake result.""" + return self._devices + + +class FakeSubscriber(GoogleNestSubscriber): + """Fake subscriber that supplies a FakeDeviceManager.""" + + def __init__(self, device_manager: FakeDeviceManager): + """Initialize Fake Subscriber.""" + self._device_manager = device_manager + self._callback = None + + def set_update_callback(self, callback: EventCallback): + """Capture the callback set by Home Assistant.""" + self._callback = callback + + async def start_async(self) -> DeviceManager: + """Return the fake device manager.""" + return self._device_manager + + async def async_get_device_manager(self) -> DeviceManager: + """Return the fake device manager.""" + return self._device_manager + + def stop_async(self): + """No-op to stop the subscriber.""" + return None + + def receive_event(self, event_message: EventMessage): + """Simulate a received pubsub message, invoked by tests.""" + # Update device state, then invoke HomeAssistant to refresh + self._device_manager.handle_event(event_message) + self._callback.handle_event(event_message) + + +async def async_setup_sdm_platform(hass, platform, devices={}, structures={}): + """Set up the platform and prerequisites.""" + MockConfigEntry(domain=DOMAIN, data=CONFIG_ENTRY_DATA).add_to_hass(hass) + device_manager = FakeDeviceManager(devices=devices, structures=structures) + subscriber = FakeSubscriber(device_manager) + with patch( + "homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation" + ), patch("homeassistant.components.nest.PLATFORMS", [platform]), patch( + "homeassistant.components.nest.GoogleNestSubscriber", return_value=subscriber + ): + assert await async_setup_component(hass, DOMAIN, CONFIG) + await hass.async_block_till_done() + return subscriber diff --git a/tests/components/nest/device_info_test.py b/tests/components/nest/device_info_test.py new file mode 100644 index 00000000000..1561364d348 --- /dev/null +++ b/tests/components/nest/device_info_test.py @@ -0,0 +1,103 @@ +"""Test for properties for devices common to all entity types.""" + +from google_nest_sdm.device import Device + +from homeassistant.components.nest.device_info import DeviceInfo + + +def test_device_custom_name(): + """Test a device name from an Info trait.""" + device = Device.MakeDevice( + { + "name": "some-device-id", + "type": "sdm.devices.types.DOORBELL", + "traits": { + "sdm.devices.traits.Info": { + "customName": "My Doorbell", + }, + }, + }, + auth=None, + ) + + device_info = DeviceInfo(device) + assert device_info.device_name == "My Doorbell" + assert device_info.device_model == "Doorbell" + assert device_info.device_brand == "Google Nest" + assert device_info.device_info == { + "identifiers": {("nest", "some-device-id")}, + "name": "My Doorbell", + "manufacturer": "Google Nest", + "model": "Doorbell", + } + + +def test_device_name_room(): + """Test a device name from the room name.""" + device = Device.MakeDevice( + { + "name": "some-device-id", + "type": "sdm.devices.types.DOORBELL", + "parentRelations": [ + {"parent": "some-structure-id", "displayName": "Some Room"} + ], + }, + auth=None, + ) + + device_info = DeviceInfo(device) + assert device_info.device_name == "Some Room" + assert device_info.device_model == "Doorbell" + assert device_info.device_brand == "Google Nest" + assert device_info.device_info == { + "identifiers": {("nest", "some-device-id")}, + "name": "Some Room", + "manufacturer": "Google Nest", + "model": "Doorbell", + } + + +def test_device_no_name(): + """Test a device that has a name inferred from the type.""" + device = Device.MakeDevice( + {"name": "some-device-id", "type": "sdm.devices.types.DOORBELL", "traits": {}}, + auth=None, + ) + + device_info = DeviceInfo(device) + assert device_info.device_name == "Doorbell" + assert device_info.device_model == "Doorbell" + assert device_info.device_brand == "Google Nest" + assert device_info.device_info == { + "identifiers": {("nest", "some-device-id")}, + "name": "Doorbell", + "manufacturer": "Google Nest", + "model": "Doorbell", + } + + +def test_device_invalid_type(): + """Test a device with a type name that is not recognized.""" + device = Device.MakeDevice( + { + "name": "some-device-id", + "type": "sdm.devices.types.INVALID_TYPE", + "traits": { + "sdm.devices.traits.Info": { + "customName": "My Doorbell", + }, + }, + }, + auth=None, + ) + + device_info = DeviceInfo(device) + assert device_info.device_name == "My Doorbell" + assert device_info.device_model is None + assert device_info.device_brand == "Google Nest" + assert device_info.device_info == { + "identifiers": {("nest", "some-device-id")}, + "name": "My Doorbell", + "manufacturer": "Google Nest", + "model": None, + } diff --git a/tests/components/nest/sensor_sdm_test.py b/tests/components/nest/sensor_sdm_test.py index ab2cae3d9f3..7d2e299a1a1 100644 --- a/tests/components/nest/sensor_sdm_test.py +++ b/tests/components/nest/sensor_sdm_test.py @@ -5,109 +5,19 @@ These tests fake out the subscriber/devicemanager, and are not using a real pubsub subscriber. """ -import time - from google_nest_sdm.device import Device -from google_nest_sdm.device_manager import DeviceManager -from google_nest_sdm.event import EventCallback, EventMessage -from google_nest_sdm.google_nest_subscriber import GoogleNestSubscriber +from google_nest_sdm.event import EventMessage -from homeassistant.components.nest import DOMAIN -from homeassistant.setup import async_setup_component - -from tests.async_mock import patch -from tests.common import MockConfigEntry +from .common import async_setup_sdm_platform PLATFORM = "sensor" -CONFIG = { - "nest": { - "client_id": "some-client-id", - "client_secret": "some-client-secret", - # Required fields for using SDM API - "project_id": "some-project-id", - "subscriber_id": "some-subscriber-id", - }, -} - -CONFIG_ENTRY_DATA = { - "sdm": {}, # Indicates new SDM API, not legacy API - "auth_implementation": "local", - "token": { - "expires_at": time.time() + 86400, - "access_token": { - "token": "some-token", - }, - }, -} - THERMOSTAT_TYPE = "sdm.devices.types.THERMOSTAT" -class FakeDeviceManager(DeviceManager): - """Fake DeviceManager that can supply a list of devices and structures.""" - - def __init__(self, devices: dict, structures: dict): - """Initialize FakeDeviceManager.""" - super().__init__() - self._devices = devices - - @property - def structures(self) -> dict: - """Override structures with fake result.""" - return self._structures - - @property - def devices(self) -> dict: - """Override devices with fake result.""" - return self._devices - - -class FakeSubscriber(GoogleNestSubscriber): - """Fake subscriber that supplies a FakeDeviceManager.""" - - def __init__(self, device_manager: FakeDeviceManager): - """Initialize Fake Subscriber.""" - self._device_manager = device_manager - self._callback = None - - def set_update_callback(self, callback: EventCallback): - """Capture the callback set by Home Assistant.""" - self._callback = callback - - async def start_async(self) -> DeviceManager: - """Return the fake device manager.""" - return self._device_manager - - @property - async def async_device_manager(self) -> DeviceManager: - """Return the fake device manager.""" - return self._device_manager - - def stop_async(self): - """No-op to stop the subscriber.""" - return None - - def receive_event(self, event_message: EventMessage): - """Simulate a received pubsub message, invoked by tests.""" - # Update device state, then invoke HomeAssistant to refresh - self._device_manager.handle_event(event_message) - self._callback.handle_event(event_message) - - -async def setup_sensor(hass, devices={}, structures={}): +async def async_setup_sensor(hass, devices={}, structures={}): """Set up the platform and prerequisites.""" - MockConfigEntry(domain=DOMAIN, data=CONFIG_ENTRY_DATA).add_to_hass(hass) - device_manager = FakeDeviceManager(devices=devices, structures=structures) - subscriber = FakeSubscriber(device_manager) - with patch( - "homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation" - ), patch("homeassistant.components.nest.PLATFORMS", [PLATFORM]), patch( - "homeassistant.components.nest.GoogleNestSubscriber", return_value=subscriber - ): - assert await async_setup_component(hass, DOMAIN, CONFIG) - await hass.async_block_till_done() - return subscriber + return await async_setup_sdm_platform(hass, PLATFORM, devices, structures) async def test_thermostat_device(hass): @@ -132,7 +42,7 @@ async def test_thermostat_device(hass): auth=None, ) } - await setup_sensor(hass, devices) + await async_setup_sensor(hass, devices) temperature = hass.states.get("sensor.my_sensor_temperature") assert temperature is not None @@ -157,7 +67,7 @@ async def test_thermostat_device(hass): async def test_no_devices(hass): """Test no devices returned by the api.""" - await setup_sensor(hass) + await async_setup_sensor(hass) temperature = hass.states.get("sensor.my_sensor_temperature") assert temperature is None @@ -178,7 +88,7 @@ async def test_device_no_sensor_traits(hass): auth=None, ) } - await setup_sensor(hass, devices) + await async_setup_sensor(hass, devices) temperature = hass.states.get("sensor.my_sensor_temperature") assert temperature is None @@ -206,7 +116,7 @@ async def test_device_name_from_structure(hass): auth=None, ) } - await setup_sensor(hass, devices) + await async_setup_sensor(hass, devices) temperature = hass.states.get("sensor.some_room_temperature") assert temperature is not None @@ -232,7 +142,7 @@ async def test_event_updates_sensor(hass): auth=None, ) } - subscriber = await setup_sensor(hass, devices) + subscriber = await async_setup_sensor(hass, devices) temperature = hass.states.get("sensor.my_sensor_temperature") assert temperature is not None @@ -281,7 +191,7 @@ async def test_device_with_unknown_type(hass): auth=None, ) } - await setup_sensor(hass, devices) + await async_setup_sensor(hass, devices) temperature = hass.states.get("sensor.my_sensor_temperature") assert temperature is not None diff --git a/tests/components/nexia/test_config_flow.py b/tests/components/nexia/test_config_flow.py index 944eb612038..81536f5beea 100644 --- a/tests/components/nexia/test_config_flow.py +++ b/tests/components/nexia/test_config_flow.py @@ -33,6 +33,7 @@ async def test_form(hass): result["flow_id"], {CONF_USERNAME: "username", CONF_PASSWORD: "password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "myhouse" @@ -40,7 +41,6 @@ async def test_form(hass): CONF_USERNAME: "username", CONF_PASSWORD: "password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -162,6 +162,7 @@ async def test_form_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data={CONF_USERNAME: "username", CONF_PASSWORD: "password"}, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "myhouse" @@ -169,7 +170,6 @@ async def test_form_import(hass): CONF_USERNAME: "username", CONF_PASSWORD: "password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/notion/test_config_flow.py b/tests/components/notion/test_config_flow.py index 7a887ac3468..728a8d40a52 100644 --- a/tests/components/notion/test_config_flow.py +++ b/tests/components/notion/test_config_flow.py @@ -68,23 +68,6 @@ async def test_show_form(hass): assert result["step_id"] == "user" -async def test_step_import(hass, mock_aionotion): - """Test that the import step works.""" - conf = {CONF_USERNAME: "user@host.com", CONF_PASSWORD: "password123"} - - flow = config_flow.NotionFlowHandler() - flow.hass = hass - flow.context = {"source": SOURCE_USER} - - result = await flow.async_step_import(import_config=conf) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result["title"] == "user@host.com" - assert result["data"] == { - CONF_USERNAME: "user@host.com", - CONF_PASSWORD: "password123", - } - - async def test_step_user(hass, mock_aionotion): """Test that the user step works.""" conf = {CONF_USERNAME: "user@host.com", CONF_PASSWORD: "password123"} diff --git a/tests/components/nuheat/test_config_flow.py b/tests/components/nuheat/test_config_flow.py index 4c392841142..5b2259faea8 100644 --- a/tests/components/nuheat/test_config_flow.py +++ b/tests/components/nuheat/test_config_flow.py @@ -40,6 +40,7 @@ async def test_form_user(hass): CONF_PASSWORD: "test-password", }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Master bathroom" @@ -48,7 +49,6 @@ async def test_form_user(hass): CONF_USERNAME: "test-username", CONF_PASSWORD: "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -79,6 +79,7 @@ async def test_form_import(hass): CONF_PASSWORD: "test-password", }, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "Master bathroom" @@ -87,7 +88,6 @@ async def test_form_import(hass): CONF_USERNAME: "test-username", CONF_PASSWORD: "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/nut/test_config_flow.py b/tests/components/nut/test_config_flow.py index 8d50d77c31d..e003ecd796b 100644 --- a/tests/components/nut/test_config_flow.py +++ b/tests/components/nut/test_config_flow.py @@ -57,6 +57,7 @@ async def test_form_zeroconf(hass): result2["flow_id"], {"resources": ["battery.voltage", "ups.status", "ups.status.display"]}, ) + await hass.async_block_till_done() assert result3["type"] == "create_entry" assert result3["title"] == "192.168.1.5:1234" @@ -68,7 +69,6 @@ async def test_form_zeroconf(hass): "username": "test-username", } assert result3["result"].unique_id is None - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -116,6 +116,7 @@ async def test_form_user_one_ups(hass): result2["flow_id"], {"resources": ["battery.voltage", "ups.status", "ups.status.display"]}, ) + await hass.async_block_till_done() assert result3["type"] == "create_entry" assert result3["title"] == "1.1.1.1:2222" @@ -126,7 +127,6 @@ async def test_form_user_one_ups(hass): "resources": ["battery.voltage", "ups.status", "ups.status.display"], "username": "test-username", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -195,6 +195,7 @@ async def test_form_user_multiple_ups(hass): result3["flow_id"], {"resources": ["battery.voltage"]}, ) + await hass.async_block_till_done() assert result4["type"] == "create_entry" assert result4["title"] == "ups2@1.1.1.1:2222" @@ -206,7 +207,6 @@ async def test_form_user_multiple_ups(hass): "resources": ["battery.voltage"], "username": "test-username", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 2 @@ -239,6 +239,7 @@ async def test_form_import(hass): "resources": ["battery.charge"], }, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "localhost:123" @@ -248,7 +249,6 @@ async def test_form_import(hass): "name": "name", "resources": ["battery.charge"], } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/nws/test_config_flow.py b/tests/components/nws/test_config_flow.py index 72e02f32b9d..2ea5f36a379 100644 --- a/tests/components/nws/test_config_flow.py +++ b/tests/components/nws/test_config_flow.py @@ -28,6 +28,7 @@ async def test_form(hass, mock_simple_nws_config): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], {"api_key": "test"} ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "ABC" @@ -37,7 +38,6 @@ async def test_form(hass, mock_simple_nws_config): "longitude": -90, "station": "ABC", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -94,9 +94,9 @@ async def test_form_already_configured(hass, mock_simple_nws_config): result["flow_id"], {"api_key": "test"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/nx584/test_binary_sensor.py b/tests/components/nx584/test_binary_sensor.py index 89892bb06f0..c12e8e24ebc 100644 --- a/tests/components/nx584/test_binary_sensor.py +++ b/tests/components/nx584/test_binary_sensor.py @@ -1,5 +1,4 @@ """The tests for the nx584 sensor platform.""" -import unittest from unittest import mock from nx584 import client as nx584_client @@ -7,211 +6,223 @@ import pytest import requests from homeassistant.components.nx584 import binary_sensor as nx584 -from homeassistant.setup import setup_component - -from tests.common import get_test_home_assistant +from homeassistant.setup import async_setup_component class StopMe(Exception): """Stop helper.""" - pass + +@pytest.fixture +def fake_zones(): + """Fixture for fake zones. + + Returns: + list: List of fake zones + """ + return [ + {"name": "front", "number": 1}, + {"name": "back", "number": 2}, + {"name": "inside", "number": 3}, + ] -class TestNX584SensorSetup(unittest.TestCase): - """Test the NX584 sensor platform.""" +@pytest.fixture +def client(fake_zones): + """Fixture for client. - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self._mock_client = mock.patch.object(nx584_client, "Client") - self._mock_client.start() - - self.fake_zones = [ - {"name": "front", "number": 1}, - {"name": "back", "number": 2}, - {"name": "inside", "number": 3}, - ] + Args: + fake_zones (list): Fixture of fake zones + Yields: + MagicMock: Client Mock + """ + with mock.patch.object(nx584_client, "Client") as _mock_client: client = nx584_client.Client.return_value - client.list_zones.return_value = self.fake_zones + client.list_zones.return_value = fake_zones client.get_version.return_value = "1.1" - self.addCleanup(self.tear_down_cleanup) - def tear_down_cleanup(self): - """Stop everything that was started.""" - self.hass.stop() - self._mock_client.stop() + yield _mock_client - @mock.patch("homeassistant.components.nx584.binary_sensor.NX584Watcher") - @mock.patch("homeassistant.components.nx584.binary_sensor.NX584ZoneSensor") - def test_setup_defaults(self, mock_nx, mock_watcher): - """Test the setup with no configuration.""" - add_entities = mock.MagicMock() - config = { - "host": nx584.DEFAULT_HOST, - "port": nx584.DEFAULT_PORT, - "exclude_zones": [], - "zone_types": {}, - } - assert nx584.setup_platform(self.hass, config, add_entities) - mock_nx.assert_has_calls( - [mock.call(zone, "opening") for zone in self.fake_zones] - ) - assert add_entities.called - assert nx584_client.Client.call_count == 1 - assert nx584_client.Client.call_args == mock.call("http://localhost:5007") - @mock.patch("homeassistant.components.nx584.binary_sensor.NX584Watcher") - @mock.patch("homeassistant.components.nx584.binary_sensor.NX584ZoneSensor") - def test_setup_full_config(self, mock_nx, mock_watcher): - """Test the setup with full configuration.""" - config = { - "host": "foo", - "port": 123, - "exclude_zones": [2], - "zone_types": {3: "motion"}, - } - add_entities = mock.MagicMock() - assert nx584.setup_platform(self.hass, config, add_entities) - mock_nx.assert_has_calls( - [ - mock.call(self.fake_zones[0], "opening"), - mock.call(self.fake_zones[2], "motion"), - ] - ) - assert add_entities.called - assert nx584_client.Client.call_count == 1 - assert nx584_client.Client.call_args == mock.call("http://foo:123") - assert mock_watcher.called +@pytest.mark.usefixtures("client") +@mock.patch("homeassistant.components.nx584.binary_sensor.NX584Watcher") +@mock.patch("homeassistant.components.nx584.binary_sensor.NX584ZoneSensor") +def test_nx584_sensor_setup_defaults(mock_nx, mock_watcher, hass, fake_zones): + """Test the setup with no configuration.""" + add_entities = mock.MagicMock() + config = { + "host": nx584.DEFAULT_HOST, + "port": nx584.DEFAULT_PORT, + "exclude_zones": [], + "zone_types": {}, + } + assert nx584.setup_platform(hass, config, add_entities) + mock_nx.assert_has_calls([mock.call(zone, "opening") for zone in fake_zones]) + assert add_entities.called + assert nx584_client.Client.call_count == 1 + assert nx584_client.Client.call_args == mock.call("http://localhost:5007") - def _test_assert_graceful_fail(self, config): - """Test the failing.""" - assert not setup_component(self.hass, "nx584", config) - def test_setup_bad_config(self): - """Test the setup with bad configuration.""" - bad_configs = [ - {"exclude_zones": ["a"]}, - {"zone_types": {"a": "b"}}, - {"zone_types": {1: "notatype"}}, - {"zone_types": {"notazone": "motion"}}, +@pytest.mark.usefixtures("client") +@mock.patch("homeassistant.components.nx584.binary_sensor.NX584Watcher") +@mock.patch("homeassistant.components.nx584.binary_sensor.NX584ZoneSensor") +def test_nx584_sensor_setup_full_config(mock_nx, mock_watcher, hass, fake_zones): + """Test the setup with full configuration.""" + config = { + "host": "foo", + "port": 123, + "exclude_zones": [2], + "zone_types": {3: "motion"}, + } + add_entities = mock.MagicMock() + assert nx584.setup_platform(hass, config, add_entities) + mock_nx.assert_has_calls( + [ + mock.call(fake_zones[0], "opening"), + mock.call(fake_zones[2], "motion"), ] - for config in bad_configs: - self._test_assert_graceful_fail(config) - - def test_setup_connect_failed(self): - """Test the setup with connection failure.""" - nx584_client.Client.return_value.list_zones.side_effect = ( - requests.exceptions.ConnectionError - ) - self._test_assert_graceful_fail({}) - - def test_setup_no_partitions(self): - """Test the setup with connection failure.""" - nx584_client.Client.return_value.list_zones.side_effect = IndexError - self._test_assert_graceful_fail({}) - - def test_setup_version_too_old(self): - """Test if version is too old.""" - nx584_client.Client.return_value.get_version.return_value = "1.0" - self._test_assert_graceful_fail({}) - - def test_setup_no_zones(self): - """Test the setup with no zones.""" - nx584_client.Client.return_value.list_zones.return_value = [] - add_entities = mock.MagicMock() - assert nx584.setup_platform(self.hass, {}, add_entities) - assert not add_entities.called + ) + assert add_entities.called + assert nx584_client.Client.call_count == 1 + assert nx584_client.Client.call_args == mock.call("http://foo:123") + assert mock_watcher.called -class TestNX584ZoneSensor(unittest.TestCase): +async def _test_assert_graceful_fail(hass, config): + """Test the failing.""" + assert not await async_setup_component(hass, "nx584", config) + + +@pytest.mark.usefixtures("client") +@pytest.mark.parametrize( + "config", + [ + ({"exclude_zones": ["a"]}), + ({"zone_types": {"a": "b"}}), + ({"zone_types": {1: "notatype"}}), + ({"zone_types": {"notazone": "motion"}}), + ], +) +async def test_nx584_sensor_setup_bad_config(hass, config): + """Test the setup with bad configuration.""" + await _test_assert_graceful_fail(hass, config) + + +@pytest.mark.usefixtures("client") +@pytest.mark.parametrize( + "exception_type", + [ + pytest.param(requests.exceptions.ConnectionError, id="connect_failed"), + pytest.param(IndexError, id="no_partitions"), + ], +) +async def test_nx584_sensor_setup_with_exceptions(hass, exception_type): + """Test the setup handles exceptions.""" + nx584_client.Client.return_value.list_zones.side_effect = exception_type + await _test_assert_graceful_fail(hass, {}) + + +@pytest.mark.usefixtures("client") +async def test_nx584_sensor_setup_version_too_old(hass): + """Test if version is too old.""" + nx584_client.Client.return_value.get_version.return_value = "1.0" + await _test_assert_graceful_fail(hass, {}) + + +@pytest.mark.usefixtures("client") +def test_nx584_sensor_setup_no_zones(hass): + """Test the setup with no zones.""" + nx584_client.Client.return_value.list_zones.return_value = [] + add_entities = mock.MagicMock() + assert nx584.setup_platform(hass, {}, add_entities) + assert not add_entities.called + + +def test_nx584_zone_sensor_normal(): """Test for the NX584 zone sensor.""" + zone = {"number": 1, "name": "foo", "state": True} + sensor = nx584.NX584ZoneSensor(zone, "motion") + assert "foo" == sensor.name + assert not sensor.should_poll + assert sensor.is_on + assert sensor.device_state_attributes["zone_number"] == 1 - def test_sensor_normal(self): - """Test the sensor.""" - zone = {"number": 1, "name": "foo", "state": True} - sensor = nx584.NX584ZoneSensor(zone, "motion") - assert "foo" == sensor.name - assert not sensor.should_poll - assert sensor.is_on - assert sensor.device_state_attributes["zone_number"] == 1 - - zone["state"] = False - assert not sensor.is_on + zone["state"] = False + assert not sensor.is_on -class TestNX584Watcher(unittest.TestCase): - """Test the NX584 watcher.""" +@mock.patch.object(nx584.NX584ZoneSensor, "schedule_update_ha_state") +def test_nx584_watcher_process_zone_event(mock_update): + """Test the processing of zone events.""" + zone1 = {"number": 1, "name": "foo", "state": True} + zone2 = {"number": 2, "name": "bar", "state": True} + zones = { + 1: nx584.NX584ZoneSensor(zone1, "motion"), + 2: nx584.NX584ZoneSensor(zone2, "motion"), + } + watcher = nx584.NX584Watcher(None, zones) + watcher._process_zone_event({"zone": 1, "zone_state": False}) + assert not zone1["state"] + assert mock_update.call_count == 1 - @mock.patch.object(nx584.NX584ZoneSensor, "schedule_update_ha_state") - def test_process_zone_event(self, mock_update): - """Test the processing of zone events.""" - zone1 = {"number": 1, "name": "foo", "state": True} - zone2 = {"number": 2, "name": "bar", "state": True} - zones = { - 1: nx584.NX584ZoneSensor(zone1, "motion"), - 2: nx584.NX584ZoneSensor(zone2, "motion"), - } - watcher = nx584.NX584Watcher(None, zones) - watcher._process_zone_event({"zone": 1, "zone_state": False}) - assert not zone1["state"] - assert mock_update.call_count == 1 - @mock.patch.object(nx584.NX584ZoneSensor, "schedule_update_ha_state") - def test_process_zone_event_missing_zone(self, mock_update): - """Test the processing of zone events with missing zones.""" - watcher = nx584.NX584Watcher(None, {}) - watcher._process_zone_event({"zone": 1, "zone_state": False}) - assert not mock_update.called +@mock.patch.object(nx584.NX584ZoneSensor, "schedule_update_ha_state") +def test_nx584_watcher_process_zone_event_missing_zone(mock_update): + """Test the processing of zone events with missing zones.""" + watcher = nx584.NX584Watcher(None, {}) + watcher._process_zone_event({"zone": 1, "zone_state": False}) + assert not mock_update.called - def test_run_with_zone_events(self): - """Test the zone events.""" - empty_me = [1, 2] - def fake_get_events(): - """Return nothing twice, then some events.""" - if empty_me: - empty_me.pop() - else: - return fake_events +def test_nx584_watcher_run_with_zone_events(): + """Test the zone events.""" + empty_me = [1, 2] - client = mock.MagicMock() - fake_events = [ - {"zone": 1, "zone_state": True, "type": "zone_status"}, - {"zone": 2, "foo": False}, - ] - client.get_events.side_effect = fake_get_events - watcher = nx584.NX584Watcher(client, {}) + def fake_get_events(): + """Return nothing twice, then some events.""" + if empty_me: + empty_me.pop() + else: + return fake_events - @mock.patch.object(watcher, "_process_zone_event") - def run(fake_process): - """Run a fake process.""" - fake_process.side_effect = StopMe - with pytest.raises(StopMe): - watcher._run() - assert fake_process.call_count == 1 - assert fake_process.call_args == mock.call(fake_events[0]) + client = mock.MagicMock() + fake_events = [ + {"zone": 1, "zone_state": True, "type": "zone_status"}, + {"zone": 2, "foo": False}, + ] + client.get_events.side_effect = fake_get_events + watcher = nx584.NX584Watcher(client, {}) - run() - assert 3 == client.get_events.call_count + @mock.patch.object(watcher, "_process_zone_event") + def run(fake_process): + """Run a fake process.""" + fake_process.side_effect = StopMe + with pytest.raises(StopMe): + watcher._run() + assert fake_process.call_count == 1 + assert fake_process.call_args == mock.call(fake_events[0]) - @mock.patch("time.sleep") - def test_run_retries_failures(self, mock_sleep): - """Test the retries with failures.""" - empty_me = [1, 2] + run() + assert 3 == client.get_events.call_count - def fake_run(): - """Fake runner.""" - if empty_me: - empty_me.pop() - raise requests.exceptions.ConnectionError() - raise StopMe() - watcher = nx584.NX584Watcher(None, {}) - with mock.patch.object(watcher, "_run") as mock_inner: - mock_inner.side_effect = fake_run - with pytest.raises(StopMe): - watcher.run() - assert 3 == mock_inner.call_count - mock_sleep.assert_has_calls([mock.call(10), mock.call(10)]) +@mock.patch("time.sleep") +def test_nx584_watcher_run_retries_failures(mock_sleep): + """Test the retries with failures.""" + empty_me = [1, 2] + + def fake_run(): + """Fake runner.""" + if empty_me: + empty_me.pop() + raise requests.exceptions.ConnectionError() + raise StopMe() + + watcher = nx584.NX584Watcher(None, {}) + with mock.patch.object(watcher, "_run") as mock_inner: + mock_inner.side_effect = fake_run + with pytest.raises(StopMe): + watcher.run() + assert 3 == mock_inner.call_count + mock_sleep.assert_has_calls([mock.call(10), mock.call(10)]) diff --git a/tests/components/omnilogic/test_config_flow.py b/tests/components/omnilogic/test_config_flow.py index ef29ff9f674..6243fe10efb 100644 --- a/tests/components/omnilogic/test_config_flow.py +++ b/tests/components/omnilogic/test_config_flow.py @@ -32,11 +32,11 @@ async def test_form(hass): result["flow_id"], DATA, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Omnilogic" assert result2["data"] == DATA - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/onboarding/test_views.py b/tests/components/onboarding/test_views.py index a1b857a52ce..73845aba7b2 100644 --- a/tests/components/onboarding/test_views.py +++ b/tests/components/onboarding/test_views.py @@ -72,6 +72,12 @@ async def mock_supervisor_fixture(hass, aioclient_mock): ), patch( "homeassistant.components.hassio.HassIO.get_host_info", return_value={}, + ), patch( + "homeassistant.components.hassio.HassIO.get_supervisor_info", + return_value={}, + ), patch( + "homeassistant.components.hassio.HassIO.get_os_info", + return_value={}, ), patch( "homeassistant.components.hassio.HassIO.get_ingress_panels", return_value={"panels": {}}, @@ -86,6 +92,8 @@ async def test_onboarding_progress(hass, hass_storage, aiohttp_client): mock_storage(hass_storage, {"done": ["hello"]}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() + client = await aiohttp_client(hass.http.app) with patch.object(views, "STEPS", ["hello", "world"]): @@ -104,6 +112,7 @@ async def test_onboarding_user_already_done(hass, hass_storage, aiohttp_client): with patch.object(onboarding, "STEPS", ["hello", "world"]): assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) @@ -125,6 +134,7 @@ async def test_onboarding_user(hass, hass_storage, aiohttp_client): """Test creating a new user.""" assert await async_setup_component(hass, "person", {}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) @@ -185,6 +195,7 @@ async def test_onboarding_user_invalid_name(hass, hass_storage, aiohttp_client): mock_storage(hass_storage, {"done": []}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) @@ -206,6 +217,7 @@ async def test_onboarding_user_race(hass, hass_storage, aiohttp_client): mock_storage(hass_storage, {"done": ["hello"]}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) @@ -240,6 +252,7 @@ async def test_onboarding_integration(hass, hass_storage, hass_client): mock_storage(hass_storage, {"done": [const.STEP_USER]}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await hass_client() @@ -282,6 +295,7 @@ async def test_onboarding_integration_invalid_redirect_uri( mock_storage(hass_storage, {"done": [const.STEP_USER]}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await hass_client() @@ -305,6 +319,7 @@ async def test_onboarding_integration_requires_auth(hass, hass_storage, aiohttp_ mock_storage(hass_storage, {"done": [const.STEP_USER]}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) @@ -320,6 +335,7 @@ async def test_onboarding_core_sets_up_met(hass, hass_storage, hass_client): mock_storage(hass_storage, {"done": [const.STEP_USER]}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await hass_client() @@ -339,6 +355,7 @@ async def test_onboarding_core_sets_up_rpi_power( await async_setup_component(hass, "persistent_notification", {}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await hass_client() @@ -363,6 +380,7 @@ async def test_onboarding_core_no_rpi_power( await async_setup_component(hass, "persistent_notification", {}) assert await async_setup_component(hass, "onboarding", {}) + await hass.async_block_till_done() client = await hass_client() diff --git a/tests/components/onewire/__init__.py b/tests/components/onewire/__init__.py index e5de65bc71e..eb9b42ea996 100644 --- a/tests/components/onewire/__init__.py +++ b/tests/components/onewire/__init__.py @@ -1 +1,92 @@ """Tests for 1-Wire integration.""" + +from homeassistant.components.onewire.const import ( + CONF_MOUNT_DIR, + CONF_NAMES, + CONF_TYPE_OWSERVER, + CONF_TYPE_SYSBUS, + DEFAULT_SYSBUS_MOUNT_DIR, + DOMAIN, +) +from homeassistant.config_entries import CONN_CLASS_LOCAL_POLL +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE + +from tests.async_mock import patch +from tests.common import MockConfigEntry + + +async def setup_onewire_sysbus_integration(hass): + """Create the 1-Wire integration.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + source="user", + data={ + CONF_TYPE: CONF_TYPE_SYSBUS, + CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR, + }, + unique_id=f"{CONF_TYPE_SYSBUS}:{DEFAULT_SYSBUS_MOUNT_DIR}", + connection_class=CONN_CLASS_LOCAL_POLL, + options={}, + entry_id="1", + ) + config_entry.add_to_hass(hass) + + with patch( + "homeassistant.components.onewire.onewirehub.os.path.isdir", return_value=True + ): + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + return config_entry + + +async def setup_onewire_owserver_integration(hass): + """Create the 1-Wire integration.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + source="user", + data={ + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: "1234", + }, + unique_id=f"{CONF_TYPE_OWSERVER}:1.2.3.4:1234", + connection_class=CONN_CLASS_LOCAL_POLL, + options={}, + entry_id="2", + ) + config_entry.add_to_hass(hass) + + with patch( + "homeassistant.components.onewire.onewirehub.protocol.proxy", + ): + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + return config_entry + + +async def setup_onewire_patched_owserver_integration(hass): + """Create the 1-Wire integration.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + source="user", + data={ + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: "1234", + CONF_NAMES: { + "10.111111111111": "My DS18B20", + }, + }, + unique_id=f"{CONF_TYPE_OWSERVER}:1.2.3.4:1234", + connection_class=CONN_CLASS_LOCAL_POLL, + options={}, + entry_id="2", + ) + config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + return config_entry diff --git a/tests/components/onewire/test_binary_sensor.py b/tests/components/onewire/test_binary_sensor.py new file mode 100644 index 00000000000..bc8cf1defc0 --- /dev/null +++ b/tests/components/onewire/test_binary_sensor.py @@ -0,0 +1,86 @@ +"""Tests for 1-Wire devices connected on OWServer.""" +import copy + +from pyownet.protocol import Error as ProtocolError +import pytest + +from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN +from homeassistant.components.onewire.binary_sensor import DEVICE_BINARY_SENSORS +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.setup import async_setup_component + +from . import setup_onewire_patched_owserver_integration + +from tests.async_mock import patch +from tests.common import mock_registry + +MOCK_DEVICE_SENSORS = { + "12.111111111111": { + "inject_reads": [ + b"DS2406", # read device type + ], + BINARY_SENSOR_DOMAIN: [ + { + "entity_id": "binary_sensor.12_111111111111_sensed_a", + "injected_value": b" 1", + "result": STATE_ON, + }, + { + "entity_id": "binary_sensor.12_111111111111_sensed_b", + "injected_value": b" 0", + "result": STATE_OFF, + }, + ], + }, +} + + +@pytest.mark.parametrize("device_id", MOCK_DEVICE_SENSORS.keys()) +@patch("homeassistant.components.onewire.onewirehub.protocol.proxy") +async def test_owserver_binary_sensor(owproxy, hass, device_id): + """Test for 1-Wire binary sensor. + + This test forces all entities to be enabled. + """ + await async_setup_component(hass, "persistent_notification", {}) + entity_registry = mock_registry(hass) + + mock_device_sensor = MOCK_DEVICE_SENSORS[device_id] + + device_family = device_id[0:2] + dir_return_value = [f"/{device_id}/"] + read_side_effect = [device_family.encode()] + if "inject_reads" in mock_device_sensor: + read_side_effect += mock_device_sensor["inject_reads"] + + expected_sensors = mock_device_sensor[BINARY_SENSOR_DOMAIN] + for expected_sensor in expected_sensors: + read_side_effect.append(expected_sensor["injected_value"]) + + # Ensure enough read side effect + read_side_effect.extend([ProtocolError("Missing injected value")] * 10) + owproxy.return_value.dir.return_value = dir_return_value + owproxy.return_value.read.side_effect = read_side_effect + + # Force enable binary sensors + patch_device_binary_sensors = copy.deepcopy(DEVICE_BINARY_SENSORS) + for item in patch_device_binary_sensors[device_family]: + item["default_disabled"] = False + + with patch( + "homeassistant.components.onewire.SUPPORTED_PLATFORMS", [BINARY_SENSOR_DOMAIN] + ), patch.dict( + "homeassistant.components.onewire.binary_sensor.DEVICE_BINARY_SENSORS", + patch_device_binary_sensors, + ): + await setup_onewire_patched_owserver_integration(hass) + await hass.async_block_till_done() + + assert len(entity_registry.entities) == len(expected_sensors) + + for expected_sensor in expected_sensors: + entity_id = expected_sensor["entity_id"] + registry_entry = entity_registry.entities.get(entity_id) + assert registry_entry is not None + state = hass.states.get(entity_id) + assert state.state == expected_sensor["result"] diff --git a/tests/components/onewire/test_config_flow.py b/tests/components/onewire/test_config_flow.py new file mode 100644 index 00000000000..dfb64a3846e --- /dev/null +++ b/tests/components/onewire/test_config_flow.py @@ -0,0 +1,333 @@ +"""Tests for 1-Wire config flow.""" +from pyownet import protocol + +from homeassistant.components.onewire.const import ( + CONF_MOUNT_DIR, + CONF_TYPE_OWSERVER, + CONF_TYPE_SYSBUS, + DEFAULT_OWSERVER_PORT, + DEFAULT_SYSBUS_MOUNT_DIR, + DOMAIN, +) +from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE +from homeassistant.data_entry_flow import ( + RESULT_TYPE_ABORT, + RESULT_TYPE_CREATE_ENTRY, + RESULT_TYPE_FORM, +) + +from . import setup_onewire_owserver_integration, setup_onewire_sysbus_integration + +from tests.async_mock import patch + + +async def test_user_owserver(hass): + """Test OWServer user flow.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] == RESULT_TYPE_FORM + assert not result["errors"] + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_TYPE: CONF_TYPE_OWSERVER}, + ) + + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == "owserver" + assert not result["errors"] + + # Invalid server + with patch( + "homeassistant.components.onewire.onewirehub.protocol.proxy", + side_effect=protocol.ConnError, + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_HOST: "1.2.3.4", CONF_PORT: 1234}, + ) + + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == "owserver" + assert result["errors"] == {"base": "cannot_connect"} + + # Valid server + with patch("homeassistant.components.onewire.onewirehub.protocol.proxy",), patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_HOST: "1.2.3.4", CONF_PORT: 1234}, + ) + + assert result["type"] == RESULT_TYPE_CREATE_ENTRY + assert result["title"] == "1.2.3.4" + assert result["data"] == { + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: 1234, + } + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_user_owserver_duplicate(hass): + """Test OWServer flow.""" + with patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + await setup_onewire_owserver_integration(hass) + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] == RESULT_TYPE_FORM + assert not result["errors"] + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_TYPE: CONF_TYPE_OWSERVER}, + ) + + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == "owserver" + assert not result["errors"] + + # Duplicate server + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_HOST: "1.2.3.4", CONF_PORT: 1234}, + ) + assert result["type"] == RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_user_sysbus(hass): + """Test SysBus flow.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] == RESULT_TYPE_FORM + assert not result["errors"] + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_TYPE: CONF_TYPE_SYSBUS}, + ) + + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == "mount_dir" + assert not result["errors"] + + # Invalid path + with patch( + "homeassistant.components.onewire.onewirehub.os.path.isdir", + return_value=False, + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_MOUNT_DIR: "/sys/bus/invalid_directory"}, + ) + + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == "mount_dir" + assert result["errors"] == {"base": "invalid_path"} + + # Valid path + with patch( + "homeassistant.components.onewire.onewirehub.os.path.isdir", + return_value=True, + ), patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_MOUNT_DIR: "/sys/bus/directory"}, + ) + + assert result["type"] == RESULT_TYPE_CREATE_ENTRY + assert result["title"] == "/sys/bus/directory" + assert result["data"] == { + CONF_TYPE: CONF_TYPE_SYSBUS, + CONF_MOUNT_DIR: "/sys/bus/directory", + } + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_user_sysbus_duplicate(hass): + """Test SysBus duplicate flow.""" + with patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + await setup_onewire_sysbus_integration(hass) + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] == RESULT_TYPE_FORM + assert not result["errors"] + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_TYPE: CONF_TYPE_SYSBUS}, + ) + + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == "mount_dir" + assert not result["errors"] + + # Valid path + with patch( + "homeassistant.components.onewire.onewirehub.os.path.isdir", + return_value=True, + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR}, + ) + + assert result["type"] == RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_import_sysbus(hass): + """Test import step.""" + + with patch( + "homeassistant.components.onewire.onewirehub.os.path.isdir", + return_value=True, + ), patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={CONF_TYPE: CONF_TYPE_SYSBUS}, + ) + assert result["type"] == RESULT_TYPE_CREATE_ENTRY + assert result["title"] == DEFAULT_SYSBUS_MOUNT_DIR + assert result["data"] == { + CONF_TYPE: CONF_TYPE_SYSBUS, + CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR, + } + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_import_sysbus_with_mount_dir(hass): + """Test import step.""" + + with patch( + "homeassistant.components.onewire.onewirehub.os.path.isdir", + return_value=True, + ), patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={ + CONF_TYPE: CONF_TYPE_SYSBUS, + CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR, + }, + ) + assert result["type"] == RESULT_TYPE_CREATE_ENTRY + assert result["title"] == DEFAULT_SYSBUS_MOUNT_DIR + assert result["data"] == { + CONF_TYPE: CONF_TYPE_SYSBUS, + CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR, + } + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_import_owserver(hass): + """Test import step.""" + + with patch("homeassistant.components.onewire.onewirehub.protocol.proxy",), patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={ + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + }, + ) + assert result["type"] == RESULT_TYPE_CREATE_ENTRY + assert result["title"] == "1.2.3.4" + assert result["data"] == { + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: DEFAULT_OWSERVER_PORT, + } + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_import_owserver_with_port(hass): + """Test import step.""" + + with patch("homeassistant.components.onewire.onewirehub.protocol.proxy",), patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={ + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: "1234", + }, + ) + assert result["type"] == RESULT_TYPE_CREATE_ENTRY + assert result["title"] == "1.2.3.4" + assert result["data"] == { + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: "1234", + } + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/onewire/test_entity_owserver.py b/tests/components/onewire/test_entity_owserver.py index 95b0137f7eb..a09808316c4 100644 --- a/tests/components/onewire/test_entity_owserver.py +++ b/tests/components/onewire/test_entity_owserver.py @@ -1,52 +1,173 @@ """Tests for 1-Wire devices connected on OWServer.""" -from unittest.mock import patch - from pyownet.protocol import Error as ProtocolError import pytest +from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN from homeassistant.components.onewire.const import ( - DEFAULT_OWSERVER_PORT, DOMAIN, PRESSURE_CBAR, + SUPPORTED_PLATFORMS, ) from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN -from homeassistant.const import PERCENTAGE, TEMP_CELSIUS +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from homeassistant.const import ( + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_ILLUMINANCE, + DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLTAGE, + ELECTRICAL_CURRENT_AMPERE, + LIGHT_LUX, + PERCENTAGE, + PRESSURE_MBAR, + STATE_OFF, + STATE_ON, + TEMP_CELSIUS, + VOLT, +) from homeassistant.setup import async_setup_component -from tests.common import mock_registry +from . import setup_onewire_patched_owserver_integration -MOCK_CONFIG = { - "sensor": { - "platform": DOMAIN, - "host": "localhost", - "port": DEFAULT_OWSERVER_PORT, - "names": { - "10.111111111111": "My DS18B20", - }, - } -} +from tests.async_mock import patch +from tests.common import mock_device_registry, mock_registry MOCK_DEVICE_SENSORS = { - "00.111111111111": {"sensors": []}, + "00.111111111111": { + "inject_reads": [ + b"", # read device type + ], + SENSOR_DOMAIN: [], + }, "10.111111111111": { - "sensors": [ + "inject_reads": [ + b"DS18S20", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "10.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS18S20", + "name": "10.111111111111", + }, + SENSOR_DOMAIN: [ { "entity_id": "sensor.my_ds18b20_temperature", "unique_id": "/10.111111111111/temperature", "injected_value": b" 25.123", "result": "25.1", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], + }, + "12.111111111111": { + "inject_reads": [ + b"DS2406", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "12.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS2406", + "name": "12.111111111111", + }, + BINARY_SENSOR_DOMAIN: [ + { + "entity_id": "binary_sensor.12_111111111111_sensed_a", + "unique_id": "/12.111111111111/sensed.A", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "binary_sensor.12_111111111111_sensed_b", + "unique_id": "/12.111111111111/sensed.B", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + ], + SENSOR_DOMAIN: [ + { + "entity_id": "sensor.12_111111111111_temperature", + "unique_id": "/12.111111111111/TAI8570/temperature", + "injected_value": b" 25.123", + "result": "25.1", + "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, + "disabled": True, + }, + { + "entity_id": "sensor.12_111111111111_pressure", + "unique_id": "/12.111111111111/TAI8570/pressure", + "injected_value": b" 1025.123", + "result": "1025.1", + "unit": PRESSURE_MBAR, + "class": DEVICE_CLASS_PRESSURE, + "disabled": True, + }, + ], + SWITCH_DOMAIN: [ + { + "entity_id": "switch.12_111111111111_pio_a", + "unique_id": "/12.111111111111/PIO.A", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.12_111111111111_pio_b", + "unique_id": "/12.111111111111/PIO.B", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.12_111111111111_latch_a", + "unique_id": "/12.111111111111/latch.A", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.12_111111111111_latch_b", + "unique_id": "/12.111111111111/latch.B", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + ], }, "1D.111111111111": { - "sensors": [ + "inject_reads": [ + b"DS2423", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "1D.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS2423", + "name": "1D.111111111111", + }, + SENSOR_DOMAIN: [ { "entity_id": "sensor.1d_111111111111_counter_a", "unique_id": "/1D.111111111111/counter.A", "injected_value": b" 251123", "result": "251123", "unit": "count", + "class": None, }, { "entity_id": "sensor.1d_111111111111_counter_b", @@ -54,64 +175,454 @@ MOCK_DEVICE_SENSORS = { "injected_value": b" 248125", "result": "248125", "unit": "count", + "class": None, }, - ] + ], }, "22.111111111111": { - "sensors": [ + "inject_reads": [ + b"DS1822", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "22.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS1822", + "name": "22.111111111111", + }, + SENSOR_DOMAIN: [ { "entity_id": "sensor.22_111111111111_temperature", "unique_id": "/22.111111111111/temperature", "injected_value": ProtocolError, "result": "unknown", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], + }, + "26.111111111111": { + "inject_reads": [ + b"DS2438", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "26.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS2438", + "name": "26.111111111111", + }, + SENSOR_DOMAIN: [ + { + "entity_id": "sensor.26_111111111111_temperature", + "unique_id": "/26.111111111111/temperature", + "injected_value": b" 25.123", + "result": "25.1", + "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, + }, + { + "entity_id": "sensor.26_111111111111_humidity", + "unique_id": "/26.111111111111/humidity", + "injected_value": b" 72.7563", + "result": "72.8", + "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_humidity_hih3600", + "unique_id": "/26.111111111111/HIH3600/humidity", + "injected_value": b" 73.7563", + "result": "73.8", + "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_humidity_hih4000", + "unique_id": "/26.111111111111/HIH4000/humidity", + "injected_value": b" 74.7563", + "result": "74.8", + "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_humidity_hih5030", + "unique_id": "/26.111111111111/HIH5030/humidity", + "injected_value": b" 75.7563", + "result": "75.8", + "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_humidity_htm1735", + "unique_id": "/26.111111111111/HTM1735/humidity", + "injected_value": ProtocolError, + "result": "unknown", + "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_pressure", + "unique_id": "/26.111111111111/B1-R1-A/pressure", + "injected_value": b" 969.265", + "result": "969.3", + "unit": PRESSURE_MBAR, + "class": DEVICE_CLASS_PRESSURE, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_illuminance", + "unique_id": "/26.111111111111/S3-R1-A/illuminance", + "injected_value": b" 65.8839", + "result": "65.9", + "unit": LIGHT_LUX, + "class": DEVICE_CLASS_ILLUMINANCE, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_voltage_vad", + "unique_id": "/26.111111111111/VAD", + "injected_value": b" 2.97", + "result": "3.0", + "unit": VOLT, + "class": DEVICE_CLASS_VOLTAGE, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_voltage_vdd", + "unique_id": "/26.111111111111/VDD", + "injected_value": b" 4.74", + "result": "4.7", + "unit": VOLT, + "class": DEVICE_CLASS_VOLTAGE, + "disabled": True, + }, + { + "entity_id": "sensor.26_111111111111_current", + "unique_id": "/26.111111111111/IAD", + "injected_value": b" 1", + "result": "1.0", + "unit": ELECTRICAL_CURRENT_AMPERE, + "class": DEVICE_CLASS_CURRENT, + "disabled": True, + }, + ], }, "28.111111111111": { - "sensors": [ + "inject_reads": [ + b"DS18B20", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "28.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS18B20", + "name": "28.111111111111", + }, + SENSOR_DOMAIN: [ { "entity_id": "sensor.28_111111111111_temperature", "unique_id": "/28.111111111111/temperature", "injected_value": b" 26.984", "result": "27.0", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], + }, + "29.111111111111": { + "inject_reads": [ + b"DS2408", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "29.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS2408", + "name": "29.111111111111", + }, + BINARY_SENSOR_DOMAIN: [ + { + "entity_id": "binary_sensor.29_111111111111_sensed_0", + "unique_id": "/29.111111111111/sensed.0", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "binary_sensor.29_111111111111_sensed_1", + "unique_id": "/29.111111111111/sensed.1", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "binary_sensor.29_111111111111_sensed_2", + "unique_id": "/29.111111111111/sensed.2", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "binary_sensor.29_111111111111_sensed_3", + "unique_id": "/29.111111111111/sensed.3", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "binary_sensor.29_111111111111_sensed_4", + "unique_id": "/29.111111111111/sensed.4", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "binary_sensor.29_111111111111_sensed_5", + "unique_id": "/29.111111111111/sensed.5", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "binary_sensor.29_111111111111_sensed_6", + "unique_id": "/29.111111111111/sensed.6", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "binary_sensor.29_111111111111_sensed_7", + "unique_id": "/29.111111111111/sensed.7", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + ], + SWITCH_DOMAIN: [ + { + "entity_id": "switch.29_111111111111_pio_0", + "unique_id": "/29.111111111111/PIO.0", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_pio_1", + "unique_id": "/29.111111111111/PIO.1", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_pio_2", + "unique_id": "/29.111111111111/PIO.2", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_pio_3", + "unique_id": "/29.111111111111/PIO.3", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_pio_4", + "unique_id": "/29.111111111111/PIO.4", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_pio_5", + "unique_id": "/29.111111111111/PIO.5", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_pio_6", + "unique_id": "/29.111111111111/PIO.6", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_pio_7", + "unique_id": "/29.111111111111/PIO.7", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_latch_0", + "unique_id": "/29.111111111111/latch.0", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_latch_1", + "unique_id": "/29.111111111111/latch.1", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_latch_2", + "unique_id": "/29.111111111111/latch.2", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_latch_3", + "unique_id": "/29.111111111111/latch.3", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_latch_4", + "unique_id": "/29.111111111111/latch.4", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_latch_5", + "unique_id": "/29.111111111111/latch.5", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_latch_6", + "unique_id": "/29.111111111111/latch.6", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.29_111111111111_latch_7", + "unique_id": "/29.111111111111/latch.7", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + ], }, "3B.111111111111": { - "sensors": [ + "inject_reads": [ + b"DS1825", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "3B.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS1825", + "name": "3B.111111111111", + }, + SENSOR_DOMAIN: [ { "entity_id": "sensor.3b_111111111111_temperature", "unique_id": "/3B.111111111111/temperature", "injected_value": b" 28.243", "result": "28.2", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], }, "42.111111111111": { - "sensors": [ + "inject_reads": [ + b"DS28EA00", # read device type + ], + "device_info": { + "identifiers": {(DOMAIN, "42.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "DS28EA00", + "name": "42.111111111111", + }, + SENSOR_DOMAIN: [ { "entity_id": "sensor.42_111111111111_temperature", "unique_id": "/42.111111111111/temperature", "injected_value": b" 29.123", "result": "29.1", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], }, "EF.111111111111": { "inject_reads": [ b"HobbyBoards_EF", # read type ], - "sensors": [ + "device_info": { + "identifiers": {(DOMAIN, "EF.111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "HobbyBoards_EF", + "name": "EF.111111111111", + }, + SENSOR_DOMAIN: [ { "entity_id": "sensor.ef_111111111111_humidity", "unique_id": "/EF.111111111111/humidity/humidity_corrected", "injected_value": b" 67.745", "result": "67.7", "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, }, { "entity_id": "sensor.ef_111111111111_humidity_raw", @@ -119,6 +630,7 @@ MOCK_DEVICE_SENSORS = { "injected_value": b" 65.541", "result": "65.5", "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, }, { "entity_id": "sensor.ef_111111111111_temperature", @@ -126,6 +638,7 @@ MOCK_DEVICE_SENSORS = { "injected_value": b" 25.123", "result": "25.1", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, ], }, @@ -137,13 +650,20 @@ MOCK_DEVICE_SENSORS = { b" 0", # read is_leaf_2 b" 0", # read is_leaf_3 ], - "sensors": [ + "device_info": { + "identifiers": {(DOMAIN, "EF.111111111112")}, + "manufacturer": "Maxim Integrated", + "model": "HB_MOISTURE_METER", + "name": "EF.111111111112", + }, + SENSOR_DOMAIN: [ { "entity_id": "sensor.ef_111111111112_wetness_0", "unique_id": "/EF.111111111112/moisture/sensor.0", "injected_value": b" 41.745", "result": "41.7", "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, }, { "entity_id": "sensor.ef_111111111112_wetness_1", @@ -151,6 +671,7 @@ MOCK_DEVICE_SENSORS = { "injected_value": b" 42.541", "result": "42.5", "unit": PERCENTAGE, + "class": DEVICE_CLASS_HUMIDITY, }, { "entity_id": "sensor.ef_111111111112_moisture_2", @@ -158,6 +679,7 @@ MOCK_DEVICE_SENSORS = { "injected_value": b" 43.123", "result": "43.1", "unit": PRESSURE_CBAR, + "class": DEVICE_CLASS_PRESSURE, }, { "entity_id": "sensor.ef_111111111112_moisture_3", @@ -165,6 +687,7 @@ MOCK_DEVICE_SENSORS = { "injected_value": b" 44.123", "result": "44.1", "unit": PRESSURE_CBAR, + "class": DEVICE_CLASS_PRESSURE, }, ], }, @@ -172,33 +695,60 @@ MOCK_DEVICE_SENSORS = { @pytest.mark.parametrize("device_id", MOCK_DEVICE_SENSORS.keys()) -async def test_owserver_setup_valid_device(hass, device_id): - """Test for 1-Wire device.""" +@pytest.mark.parametrize("platform", SUPPORTED_PLATFORMS) +@patch("homeassistant.components.onewire.onewirehub.protocol.proxy") +async def test_owserver_setup_valid_device(owproxy, hass, device_id, platform): + """Test for 1-Wire device. + + As they would be on a clean setup: all binary-sensors and switches disabled. + """ + await async_setup_component(hass, "persistent_notification", {}) entity_registry = mock_registry(hass) + device_registry = mock_device_registry(hass) + mock_device_sensor = MOCK_DEVICE_SENSORS[device_id] + + device_family = device_id[0:2] dir_return_value = [f"/{device_id}/"] - read_side_effect = [device_id[0:2].encode()] - if "inject_reads" in MOCK_DEVICE_SENSORS[device_id]: - read_side_effect += MOCK_DEVICE_SENSORS[device_id]["inject_reads"] + read_side_effect = [device_family.encode()] + if "inject_reads" in mock_device_sensor: + read_side_effect += mock_device_sensor["inject_reads"] - expected_sensors = MOCK_DEVICE_SENSORS[device_id]["sensors"] + expected_sensors = mock_device_sensor.get(platform, []) for expected_sensor in expected_sensors: read_side_effect.append(expected_sensor["injected_value"]) - with patch("homeassistant.components.onewire.sensor.protocol.proxy") as owproxy: - owproxy.return_value.dir.return_value = dir_return_value - owproxy.return_value.read.side_effect = read_side_effect + # Ensure enough read side effect + read_side_effect.extend([ProtocolError("Missing injected value")] * 20) + owproxy.return_value.dir.return_value = dir_return_value + owproxy.return_value.read.side_effect = read_side_effect - assert await async_setup_component(hass, SENSOR_DOMAIN, MOCK_CONFIG) + with patch("homeassistant.components.onewire.SUPPORTED_PLATFORMS", [platform]): + await setup_onewire_patched_owserver_integration(hass) await hass.async_block_till_done() assert len(entity_registry.entities) == len(expected_sensors) + if len(expected_sensors) > 0: + device_info = mock_device_sensor["device_info"] + assert len(device_registry.devices) == 1 + registry_entry = device_registry.async_get_device({(DOMAIN, device_id)}, set()) + assert registry_entry is not None + assert registry_entry.identifiers == {(DOMAIN, device_id)} + assert registry_entry.manufacturer == device_info["manufacturer"] + assert registry_entry.name == device_info["name"] + assert registry_entry.model == device_info["model"] + for expected_sensor in expected_sensors: entity_id = expected_sensor["entity_id"] registry_entry = entity_registry.entities.get(entity_id) assert registry_entry is not None assert registry_entry.unique_id == expected_sensor["unique_id"] assert registry_entry.unit_of_measurement == expected_sensor["unit"] + assert registry_entry.device_class == expected_sensor["class"] + assert registry_entry.disabled == expected_sensor.get("disabled", False) state = hass.states.get(entity_id) - assert state.state == expected_sensor["result"] + if registry_entry.disabled: + assert state is None + else: + assert state.state == expected_sensor["result"] diff --git a/tests/components/onewire/test_entity_sysbus.py b/tests/components/onewire/test_entity_sysbus.py index 8a233315ab2..3ec46c60837 100644 --- a/tests/components/onewire/test_entity_sysbus.py +++ b/tests/components/onewire/test_entity_sysbus.py @@ -1,18 +1,17 @@ """Tests for 1-Wire devices connected on SysBus.""" -from unittest.mock import PropertyMock, patch - from pi1wire import InvalidCRCException, UnsupportResponseException import pytest from homeassistant.components.onewire.const import DEFAULT_SYSBUS_MOUNT_DIR, DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN -from homeassistant.const import TEMP_CELSIUS +from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS from homeassistant.setup import async_setup_component -from tests.common import mock_registry +from tests.async_mock import patch +from tests.common import mock_device_registry, mock_registry MOCK_CONFIG = { - "sensor": { + SENSOR_DOMAIN: { "platform": DOMAIN, "mount_dir": DEFAULT_SYSBUS_MOUNT_DIR, "names": { @@ -24,6 +23,12 @@ MOCK_CONFIG = { MOCK_DEVICE_SENSORS = { "00-111111111111": {"sensors": []}, "10-111111111111": { + "device_info": { + "identifiers": {(DOMAIN, "10-111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "10", + "name": "10-111111111111", + }, "sensors": [ { "entity_id": "sensor.my_ds18b20_temperature", @@ -31,11 +36,19 @@ MOCK_DEVICE_SENSORS = { "injected_value": 25.123, "result": "25.1", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], }, + "12-111111111111": {"sensors": []}, "1D-111111111111": {"sensors": []}, "22-111111111111": { + "device_info": { + "identifiers": {(DOMAIN, "22-111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "22", + "name": "22-111111111111", + }, "sensors": [ { "entity_id": "sensor.22_111111111111_temperature", @@ -43,10 +56,18 @@ MOCK_DEVICE_SENSORS = { "injected_value": FileNotFoundError, "result": "unknown", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], }, + "26-111111111111": {"sensors": []}, "28-111111111111": { + "device_info": { + "identifiers": {(DOMAIN, "28-111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "28", + "name": "28-111111111111", + }, "sensors": [ { "entity_id": "sensor.28_111111111111_temperature", @@ -54,10 +75,18 @@ MOCK_DEVICE_SENSORS = { "injected_value": InvalidCRCException, "result": "unknown", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], }, + "29-111111111111": {"sensors": []}, "3B-111111111111": { + "device_info": { + "identifiers": {(DOMAIN, "3B-111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "3B", + "name": "3B-111111111111", + }, "sensors": [ { "entity_id": "sensor.3b_111111111111_temperature", @@ -65,10 +94,17 @@ MOCK_DEVICE_SENSORS = { "injected_value": 29.993, "result": "30.0", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], }, "42-111111111111": { + "device_info": { + "identifiers": {(DOMAIN, "42-111111111111")}, + "manufacturer": "Maxim Integrated", + "model": "42", + "name": "42-111111111111", + }, "sensors": [ { "entity_id": "sensor.42_111111111111_temperature", @@ -76,8 +112,9 @@ MOCK_DEVICE_SENSORS = { "injected_value": UnsupportResponseException, "result": "unknown", "unit": TEMP_CELSIUS, + "class": DEVICE_CLASS_TEMPERATURE, }, - ] + ], }, "EF-111111111111": { "sensors": [], @@ -92,30 +129,46 @@ MOCK_DEVICE_SENSORS = { async def test_onewiredirect_setup_valid_device(hass, device_id): """Test that sysbus config entry works correctly.""" entity_registry = mock_registry(hass) + device_registry = mock_device_registry(hass) + mock_device_sensor = MOCK_DEVICE_SENSORS[device_id] + + glob_result = [f"/{DEFAULT_SYSBUS_MOUNT_DIR}/{device_id}"] read_side_effect = [] - expected_sensors = MOCK_DEVICE_SENSORS[device_id]["sensors"] + expected_sensors = mock_device_sensor["sensors"] for expected_sensor in expected_sensors: read_side_effect.append(expected_sensor["injected_value"]) + # Ensure enough read side effect + read_side_effect.extend([FileNotFoundError("Missing injected value")] * 20) + with patch( - "homeassistant.components.onewire.sensor.Pi1Wire" - ) as mock_pi1wire, patch("pi1wire.OneWire") as mock_owsensor: - type(mock_owsensor).mac_address = PropertyMock( - return_value=device_id.replace("-", "") - ) - mock_owsensor.get_temperature.side_effect = read_side_effect - mock_pi1wire.return_value.find_all_sensors.return_value = [mock_owsensor] + "homeassistant.components.onewire.onewirehub.os.path.isdir", return_value=True + ), patch("pi1wire._finder.glob.glob", return_value=glob_result,), patch( + "pi1wire.OneWire.get_temperature", + side_effect=read_side_effect, + ): assert await async_setup_component(hass, SENSOR_DOMAIN, MOCK_CONFIG) await hass.async_block_till_done() assert len(entity_registry.entities) == len(expected_sensors) + if len(expected_sensors) > 0: + device_info = mock_device_sensor["device_info"] + assert len(device_registry.devices) == 1 + registry_entry = device_registry.async_get_device({(DOMAIN, device_id)}, set()) + assert registry_entry is not None + assert registry_entry.identifiers == {(DOMAIN, device_id)} + assert registry_entry.manufacturer == device_info["manufacturer"] + assert registry_entry.name == device_info["name"] + assert registry_entry.model == device_info["model"] + for expected_sensor in expected_sensors: entity_id = expected_sensor["entity_id"] registry_entry = entity_registry.entities.get(entity_id) assert registry_entry is not None assert registry_entry.unique_id == expected_sensor["unique_id"] assert registry_entry.unit_of_measurement == expected_sensor["unit"] + assert registry_entry.device_class == expected_sensor["class"] state = hass.states.get(entity_id) assert state.state == expected_sensor["result"] diff --git a/tests/components/onewire/test_init.py b/tests/components/onewire/test_init.py new file mode 100644 index 00000000000..8edb5fa0178 --- /dev/null +++ b/tests/components/onewire/test_init.py @@ -0,0 +1,88 @@ +"""Tests for 1-Wire config flow.""" +from pyownet.protocol import ConnError, OwnetError + +from homeassistant.components.onewire.const import CONF_TYPE_OWSERVER, DOMAIN +from homeassistant.config_entries import ( + CONN_CLASS_LOCAL_POLL, + ENTRY_STATE_LOADED, + ENTRY_STATE_NOT_LOADED, + ENTRY_STATE_SETUP_RETRY, +) +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE + +from . import setup_onewire_owserver_integration, setup_onewire_sysbus_integration + +from tests.async_mock import patch +from tests.common import MockConfigEntry + + +async def test_owserver_connect_failure(hass): + """Test connection failure raises ConfigEntryNotReady.""" + config_entry_owserver = MockConfigEntry( + domain=DOMAIN, + source="user", + data={ + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: "1234", + }, + unique_id=f"{CONF_TYPE_OWSERVER}:1.2.3.4:1234", + connection_class=CONN_CLASS_LOCAL_POLL, + options={}, + entry_id="2", + ) + config_entry_owserver.add_to_hass(hass) + + with patch( + "homeassistant.components.onewire.onewirehub.protocol.proxy", + side_effect=ConnError, + ): + await hass.config_entries.async_setup(config_entry_owserver.entry_id) + await hass.async_block_till_done() + + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + assert config_entry_owserver.state == ENTRY_STATE_SETUP_RETRY + assert not hass.data.get(DOMAIN) + + +async def test_failed_owserver_listing(hass): + """Create the 1-Wire integration.""" + config_entry_owserver = MockConfigEntry( + domain=DOMAIN, + source="user", + data={ + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: "1234", + }, + unique_id=f"{CONF_TYPE_OWSERVER}:1.2.3.4:1234", + connection_class=CONN_CLASS_LOCAL_POLL, + options={}, + entry_id="2", + ) + config_entry_owserver.add_to_hass(hass) + + with patch("homeassistant.components.onewire.onewirehub.protocol.proxy") as owproxy: + owproxy.return_value.dir.side_effect = OwnetError + await hass.config_entries.async_setup(config_entry_owserver.entry_id) + await hass.async_block_till_done() + + return config_entry_owserver + + +async def test_unload_entry(hass): + """Test being able to unload an entry.""" + config_entry_owserver = await setup_onewire_owserver_integration(hass) + config_entry_sysbus = await setup_onewire_sysbus_integration(hass) + + assert len(hass.config_entries.async_entries(DOMAIN)) == 2 + assert config_entry_owserver.state == ENTRY_STATE_LOADED + assert config_entry_sysbus.state == ENTRY_STATE_LOADED + + assert await hass.config_entries.async_unload(config_entry_owserver.entry_id) + assert await hass.config_entries.async_unload(config_entry_sysbus.entry_id) + await hass.async_block_till_done() + + assert config_entry_owserver.state == ENTRY_STATE_NOT_LOADED + assert config_entry_sysbus.state == ENTRY_STATE_NOT_LOADED + assert not hass.data.get(DOMAIN) diff --git a/tests/components/onewire/test_sensor.py b/tests/components/onewire/test_sensor.py index 0aa02a9906d..751ef106147 100644 --- a/tests/components/onewire/test_sensor.py +++ b/tests/components/onewire/test_sensor.py @@ -7,7 +7,7 @@ from tests.common import assert_setup_component async def test_setup_minimum(hass): - """Test setup with minimum configuration.""" + """Test old platform setup with minimum configuration.""" config = {"sensor": {"platform": "onewire"}} with assert_setup_component(1, "sensor"): assert await async_setup_component(hass, sensor.DOMAIN, config) @@ -15,7 +15,7 @@ async def test_setup_minimum(hass): async def test_setup_sysbus(hass): - """Test setup with SysBus configuration.""" + """Test old platform setup with SysBus configuration.""" config = { "sensor": { "platform": "onewire", @@ -28,7 +28,7 @@ async def test_setup_sysbus(hass): async def test_setup_owserver(hass): - """Test setup with OWServer configuration.""" + """Test old platform setup with OWServer configuration.""" config = {"sensor": {"platform": "onewire", "host": "localhost"}} with assert_setup_component(1, "sensor"): assert await async_setup_component(hass, sensor.DOMAIN, config) @@ -36,7 +36,7 @@ async def test_setup_owserver(hass): async def test_setup_owserver_with_port(hass): - """Test setup with OWServer configuration.""" + """Test old platform setup with OWServer configuration.""" config = {"sensor": {"platform": "onewire", "host": "localhost", "port": "1234"}} with assert_setup_component(1, "sensor"): assert await async_setup_component(hass, sensor.DOMAIN, config) diff --git a/tests/components/onewire/test_switch.py b/tests/components/onewire/test_switch.py new file mode 100644 index 00000000000..3a1f2eb9f7a --- /dev/null +++ b/tests/components/onewire/test_switch.py @@ -0,0 +1,129 @@ +"""Tests for 1-Wire devices connected on OWServer.""" +import copy + +from pyownet.protocol import Error as ProtocolError +import pytest + +from homeassistant.components.onewire.switch import DEVICE_SWITCHES +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TOGGLE, STATE_OFF, STATE_ON +from homeassistant.setup import async_setup_component + +from . import setup_onewire_patched_owserver_integration + +from tests.async_mock import patch +from tests.common import mock_registry + +MOCK_DEVICE_SENSORS = { + "12.111111111111": { + "inject_reads": [ + b"DS2406", # read device type + ], + SWITCH_DOMAIN: [ + { + "entity_id": "switch.12_111111111111_pio_a", + "unique_id": "/12.111111111111/PIO.A", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.12_111111111111_pio_b", + "unique_id": "/12.111111111111/PIO.B", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.12_111111111111_latch_a", + "unique_id": "/12.111111111111/latch.A", + "injected_value": b" 1", + "result": STATE_ON, + "unit": None, + "class": None, + "disabled": True, + }, + { + "entity_id": "switch.12_111111111111_latch_b", + "unique_id": "/12.111111111111/latch.B", + "injected_value": b" 0", + "result": STATE_OFF, + "unit": None, + "class": None, + "disabled": True, + }, + ], + } +} + + +@pytest.mark.parametrize("device_id", ["12.111111111111"]) +@patch("homeassistant.components.onewire.onewirehub.protocol.proxy") +async def test_owserver_switch(owproxy, hass, device_id): + """Test for 1-Wire switch. + + This test forces all entities to be enabled. + """ + await async_setup_component(hass, "persistent_notification", {}) + entity_registry = mock_registry(hass) + + mock_device_sensor = MOCK_DEVICE_SENSORS[device_id] + + device_family = device_id[0:2] + dir_return_value = [f"/{device_id}/"] + read_side_effect = [device_family.encode()] + if "inject_reads" in mock_device_sensor: + read_side_effect += mock_device_sensor["inject_reads"] + + expected_sensors = mock_device_sensor[SWITCH_DOMAIN] + for expected_sensor in expected_sensors: + read_side_effect.append(expected_sensor["injected_value"]) + + # Ensure enough read side effect + read_side_effect.extend([ProtocolError("Missing injected value")] * 10) + owproxy.return_value.dir.return_value = dir_return_value + owproxy.return_value.read.side_effect = read_side_effect + + # Force enable switches + patch_device_switches = copy.deepcopy(DEVICE_SWITCHES) + for item in patch_device_switches[device_family]: + item["default_disabled"] = False + + with patch( + "homeassistant.components.onewire.SUPPORTED_PLATFORMS", [SWITCH_DOMAIN] + ), patch.dict( + "homeassistant.components.onewire.switch.DEVICE_SWITCHES", patch_device_switches + ): + await setup_onewire_patched_owserver_integration(hass) + await hass.async_block_till_done() + + assert len(entity_registry.entities) == len(expected_sensors) + + for expected_sensor in expected_sensors: + entity_id = expected_sensor["entity_id"] + registry_entry = entity_registry.entities.get(entity_id) + assert registry_entry is not None + state = hass.states.get(entity_id) + assert state.state == expected_sensor["result"] + + if state.state == STATE_ON: + owproxy.return_value.read.side_effect = [b" 0"] + expected_sensor["result"] = STATE_OFF + elif state.state == STATE_OFF: + owproxy.return_value.read.side_effect = [b" 1"] + expected_sensor["result"] = STATE_ON + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TOGGLE, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state.state == expected_sensor["result"] diff --git a/tests/components/opentherm_gw/test_config_flow.py b/tests/components/opentherm_gw/test_config_flow.py index a696bc47590..a7be6ddcf6b 100644 --- a/tests/components/opentherm_gw/test_config_flow.py +++ b/tests/components/opentherm_gw/test_config_flow.py @@ -40,6 +40,7 @@ async def test_form_user(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_NAME: "Test Entry 1", CONF_DEVICE: "/dev/ttyUSB0"} ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Test Entry 1" @@ -48,7 +49,6 @@ async def test_form_user(hass): CONF_DEVICE: "/dev/ttyUSB0", CONF_ID: "test_entry_1", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_pyotgw_connect.mock_calls) == 1 @@ -148,7 +148,7 @@ async def test_form_connection_timeout(hass): ) assert result2["type"] == "form" - assert result2["errors"] == {"base": "timeout"} + assert result2["errors"] == {"base": "cannot_connect"} assert len(mock_connect.mock_calls) == 1 @@ -164,7 +164,7 @@ async def test_form_connection_error(hass): ) assert result2["type"] == "form" - assert result2["errors"] == {"base": "serial_error"} + assert result2["errors"] == {"base": "cannot_connect"} assert len(mock_connect.mock_calls) == 1 @@ -206,5 +206,5 @@ async def test_options_form(hass): ) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result["data"][CONF_PRECISION] is None + assert result["data"][CONF_PRECISION] == 0.0 assert result["data"][CONF_FLOOR_TEMP] is True diff --git a/tests/components/openweathermap/test_config_flow.py b/tests/components/openweathermap/test_config_flow.py index 4b3297563ed..c4d6be156bf 100644 --- a/tests/components/openweathermap/test_config_flow.py +++ b/tests/components/openweathermap/test_config_flow.py @@ -1,6 +1,5 @@ """Define tests for the OpenWeatherMap config flow.""" -from pyowm.exceptions.api_call_error import APICallError -from pyowm.exceptions.api_response_error import UnauthorizedError +from pyowm.commons.exceptions import APIRequestError, UnauthorizedError from homeassistant import data_entry_flow from homeassistant.components.openweathermap.const import ( @@ -9,7 +8,7 @@ from homeassistant.components.openweathermap.const import ( DEFAULT_LANGUAGE, DOMAIN, ) -from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER +from homeassistant.config_entries import SOURCE_USER from homeassistant.const import ( CONF_API_KEY, CONF_LATITUDE, @@ -38,7 +37,7 @@ async def test_form(hass): mocked_owm = _create_mocked_owm(True) with patch( - "pyowm.weatherapi25.owm25.OWM25", + "pyowm.weatherapi25.weather_manager.WeatherManager", return_value=mocked_owm, ): result = await hass.config_entries.flow.async_init( @@ -70,38 +69,12 @@ async def test_form(hass): assert result["data"][CONF_API_KEY] == CONFIG[CONF_API_KEY] -async def test_form_import(hass): - """Test we can import yaml config.""" - mocked_owm = _create_mocked_owm(True) - - with patch("pyowm.weatherapi25.owm25.OWM25", return_value=mocked_owm), patch( - "homeassistant.components.openweathermap.async_setup", return_value=True - ) as mock_setup, patch( - "homeassistant.components.openweathermap.async_setup_entry", - return_value=True, - ) as mock_setup_entry: - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=VALID_YAML_CONFIG.copy(), - ) - - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result["data"][CONF_LATITUDE] == hass.config.latitude - assert result["data"][CONF_LONGITUDE] == hass.config.longitude - assert result["data"][CONF_API_KEY] == VALID_YAML_CONFIG[CONF_API_KEY] - - await hass.async_block_till_done() - assert len(mock_setup.mock_calls) == 1 - assert len(mock_setup_entry.mock_calls) == 1 - - async def test_form_options(hass): """Test that the options form.""" mocked_owm = _create_mocked_owm(True) with patch( - "pyowm.weatherapi25.owm25.OWM25", + "pyowm.weatherapi25.weather_manager.WeatherManager", return_value=mocked_owm, ): config_entry = MockConfigEntry( @@ -139,12 +112,12 @@ async def test_form_options(hass): assert result["step_id"] == "init" result = await hass.config_entries.options.async_configure( - result["flow_id"], user_input={CONF_MODE: "freedaily"} + result["flow_id"], user_input={CONF_MODE: "onecall_daily"} ) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert config_entry.options == { - CONF_MODE: "freedaily", + CONF_MODE: "onecall_daily", CONF_LANGUAGE: DEFAULT_LANGUAGE, } @@ -158,7 +131,7 @@ async def test_form_invalid_api_key(hass): mocked_owm = _create_mocked_owm(True) with patch( - "pyowm.weatherapi25.owm25.OWM25", + "pyowm.weatherapi25.weather_manager.WeatherManager", return_value=mocked_owm, side_effect=UnauthorizedError(""), ): @@ -174,9 +147,9 @@ async def test_form_api_call_error(hass): mocked_owm = _create_mocked_owm(True) with patch( - "pyowm.weatherapi25.owm25.OWM25", + "pyowm.weatherapi25.weather_manager.WeatherManager", return_value=mocked_owm, - side_effect=APICallError(""), + side_effect=APIRequestError(""), ): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=CONFIG @@ -202,31 +175,37 @@ async def test_form_api_offline(hass): def _create_mocked_owm(is_api_online: bool): mocked_owm = MagicMock() - mocked_owm.is_API_online.return_value = is_api_online weather = MagicMock() - weather.get_temperature.return_value.get.return_value = 10 - weather.get_pressure.return_value.get.return_value = 10 - weather.get_humidity.return_value = 10 - weather.get_wind.return_value.get.return_value = 0 - weather.get_clouds.return_value = "clouds" - weather.get_rain.return_value = [] - weather.get_snow.return_value = 3 - weather.get_detailed_status.return_value = "status" - weather.get_weather_code.return_value = 803 + weather.temperature.return_value.get.return_value = 10 + weather.pressure.get.return_value = 10 + weather.humidity.return_value = 10 + weather.wind.return_value.get.return_value = 0 + weather.clouds.return_value = "clouds" + weather.rain.return_value = [] + weather.snow.return_value = [] + weather.detailed_status.return_value = "status" + weather.weather_code = 803 - mocked_owm.weather_at_coords.return_value.get_weather.return_value = weather + mocked_owm.weather_at_coords.return_value.weather = weather one_day_forecast = MagicMock() - one_day_forecast.get_reference_time.return_value = 10 - one_day_forecast.get_temperature.return_value.get.return_value = 10 - one_day_forecast.get_rain.return_value.get.return_value = 0 - one_day_forecast.get_snow.return_value.get.return_value = 0 - one_day_forecast.get_wind.return_value.get.return_value = 0 - one_day_forecast.get_weather_code.return_value = 803 + one_day_forecast.reference_time.return_value = 10 + one_day_forecast.temperature.return_value.get.return_value = 10 + one_day_forecast.rain.return_value.get.return_value = 0 + one_day_forecast.snow.return_value.get.return_value = 0 + one_day_forecast.wind.return_value.get.return_value = 0 + one_day_forecast.weather_code = 803 - mocked_owm.three_hours_forecast_at_coords.return_value.get_forecast.return_value.get_weathers.return_value = [ - one_day_forecast - ] + mocked_owm.forecast_at_coords.return_value.forecast.weathers = [one_day_forecast] + + one_call = MagicMock() + one_call.current = weather + one_call.forecast_hourly = [one_day_forecast] + one_call.forecast_daily = [one_day_forecast] + + mocked_owm.one_call.return_value = one_call + + mocked_owm.weather_manager.return_value.one_call.return_value = is_api_online return mocked_owm diff --git a/tests/components/ovo_energy/test_config_flow.py b/tests/components/ovo_energy/test_config_flow.py index 58006488764..57192933572 100644 --- a/tests/components/ovo_energy/test_config_flow.py +++ b/tests/components/ovo_energy/test_config_flow.py @@ -79,6 +79,12 @@ async def test_full_flow_implementation(hass: HomeAssistant) -> None: with patch( "homeassistant.components.ovo_energy.config_flow.OVOEnergy.authenticate", return_value=True, + ), patch( + "homeassistant.components.ovo_energy.async_setup", + return_value=True, + ), patch( + "homeassistant.components.ovo_energy.async_setup_entry", + return_value=True, ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], diff --git a/tests/components/ozw/conftest.py b/tests/components/ozw/conftest.py index 3af9594d868..f2518fb8007 100644 --- a/tests/components/ozw/conftest.py +++ b/tests/components/ozw/conftest.py @@ -7,6 +7,7 @@ from .common import MQTTMessage from tests.async_mock import patch from tests.common import load_fixture +from tests.components.light.conftest import mock_light_profiles # noqa @pytest.fixture(name="generic_data", scope="session") @@ -236,3 +237,19 @@ async def lock_msg_fixture(hass): message = MQTTMessage(topic=lock_json["topic"], payload=lock_json["payload"]) message.encode() return message + + +@pytest.fixture(name="stop_addon") +def mock_install_addon(): + """Mock stop add-on.""" + with patch("homeassistant.components.hassio.async_stop_addon") as stop_addon: + yield stop_addon + + +@pytest.fixture(name="uninstall_addon") +def mock_uninstall_addon(): + """Mock uninstall add-on.""" + with patch( + "homeassistant.components.hassio.async_uninstall_addon" + ) as uninstall_addon: + yield uninstall_addon diff --git a/tests/components/ozw/test_config_flow.py b/tests/components/ozw/test_config_flow.py index 1af6787a952..7561244999d 100644 --- a/tests/components/ozw/test_config_flow.py +++ b/tests/components/ozw/test_config_flow.py @@ -1,5 +1,8 @@ """Test the Z-Wave over MQTT config flow.""" +import pytest + from homeassistant import config_entries, setup +from homeassistant.components.hassio.handler import HassioAPIError from homeassistant.components.ozw.config_flow import TITLE from homeassistant.components.ozw.const import DOMAIN @@ -7,15 +10,70 @@ from tests.async_mock import patch from tests.common import MockConfigEntry -async def test_user_create_entry(hass): - """Test the user step creates an entry.""" +@pytest.fixture(name="supervisor") +def mock_supervisor_fixture(): + """Mock Supervisor.""" + with patch("homeassistant.components.hassio.is_hassio", return_value=True): + yield + + +@pytest.fixture(name="addon_info") +def mock_addon_info(): + """Mock Supervisor add-on info.""" + with patch("homeassistant.components.hassio.async_get_addon_info") as addon_info: + addon_info.return_value = {} + yield addon_info + + +@pytest.fixture(name="addon_running") +def mock_addon_running(addon_info): + """Mock add-on already running.""" + addon_info.return_value["state"] = "started" + return addon_info + + +@pytest.fixture(name="addon_installed") +def mock_addon_installed(addon_info): + """Mock add-on already installed but not running.""" + addon_info.return_value["state"] = "stopped" + addon_info.return_value["version"] = "1.0" + return addon_info + + +@pytest.fixture(name="addon_options") +def mock_addon_options(addon_info): + """Mock add-on options.""" + addon_info.return_value["options"] = {} + return addon_info + + +@pytest.fixture(name="set_addon_options") +def mock_set_addon_options(): + """Mock set add-on options.""" + with patch( + "homeassistant.components.hassio.async_set_addon_options" + ) as set_options: + yield set_options + + +@pytest.fixture(name="install_addon") +def mock_install_addon(): + """Mock install add-on.""" + with patch("homeassistant.components.hassio.async_install_addon") as install_addon: + yield install_addon + + +@pytest.fixture(name="start_addon") +def mock_start_addon(): + """Mock start add-on.""" + with patch("homeassistant.components.hassio.async_start_addon") as start_addon: + yield start_addon + + +async def test_user_not_supervisor_create_entry(hass): + """Test the user step creates an entry not on Supervisor.""" hass.config.components.add("mqtt") await setup.async_setup_component(hass, "persistent_notification", {}) - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_USER} - ) - assert result["type"] == "form" - assert result["errors"] is None with patch( "homeassistant.components.ozw.async_setup", return_value=True @@ -23,12 +81,19 @@ async def test_user_create_entry(hass): "homeassistant.components.ozw.async_setup_entry", return_value=True, ) as mock_setup_entry: - result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + await hass.async_block_till_done() - assert result2["type"] == "create_entry" - assert result2["title"] == TITLE - assert result2["data"] == {} - await hass.async_block_till_done() + assert result["type"] == "create_entry" + assert result["title"] == TITLE + assert result["data"] == { + "usb_path": None, + "network_key": None, + "use_addon": False, + "integration_created_addon": False, + } assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -52,3 +117,230 @@ async def test_one_instance_allowed(hass): ) assert result["type"] == "abort" assert result["reason"] == "single_instance_allowed" + + +async def test_not_addon(hass, supervisor): + """Test opting out of add-on on Supervisor.""" + hass.config.components.add("mqtt") + await setup.async_setup_component(hass, "persistent_notification", {}) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + + with patch( + "homeassistant.components.ozw.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.ozw.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"use_addon": False} + ) + await hass.async_block_till_done() + + assert result["type"] == "create_entry" + assert result["title"] == TITLE + assert result["data"] == { + "usb_path": None, + "network_key": None, + "use_addon": False, + "integration_created_addon": False, + } + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_addon_running(hass, supervisor, addon_running): + """Test add-on already running on Supervisor.""" + hass.config.components.add("mqtt") + await setup.async_setup_component(hass, "persistent_notification", {}) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + + with patch( + "homeassistant.components.ozw.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.ozw.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"use_addon": True} + ) + await hass.async_block_till_done() + + assert result["type"] == "create_entry" + assert result["title"] == TITLE + assert result["data"] == { + "usb_path": None, + "network_key": None, + "use_addon": True, + "integration_created_addon": False, + } + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_addon_info_failure(hass, supervisor, addon_info): + """Test add-on info failure.""" + hass.config.components.add("mqtt") + addon_info.side_effect = HassioAPIError() + await setup.async_setup_component(hass, "persistent_notification", {}) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"use_addon": True} + ) + + assert result["type"] == "abort" + assert result["reason"] == "addon_info_failed" + + +async def test_addon_installed( + hass, supervisor, addon_installed, addon_options, set_addon_options, start_addon +): + """Test add-on already installed but not running on Supervisor.""" + hass.config.components.add("mqtt") + await setup.async_setup_component(hass, "persistent_notification", {}) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"use_addon": True} + ) + + with patch( + "homeassistant.components.ozw.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.ozw.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"usb_path": "/test", "network_key": "abc123"} + ) + await hass.async_block_till_done() + + assert result["type"] == "create_entry" + assert result["title"] == TITLE + assert result["data"] == { + "usb_path": "/test", + "network_key": "abc123", + "use_addon": True, + "integration_created_addon": False, + } + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_set_addon_config_failure( + hass, supervisor, addon_installed, addon_options, set_addon_options +): + """Test add-on set config failure.""" + hass.config.components.add("mqtt") + set_addon_options.side_effect = HassioAPIError() + await setup.async_setup_component(hass, "persistent_notification", {}) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"use_addon": True} + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"usb_path": "/test", "network_key": "abc123"} + ) + + assert result["type"] == "abort" + assert result["reason"] == "addon_set_config_failed" + + +async def test_start_addon_failure( + hass, supervisor, addon_installed, addon_options, set_addon_options, start_addon +): + """Test add-on start failure.""" + hass.config.components.add("mqtt") + start_addon.side_effect = HassioAPIError() + await setup.async_setup_component(hass, "persistent_notification", {}) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"use_addon": True} + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"usb_path": "/test", "network_key": "abc123"} + ) + + assert result["type"] == "form" + assert result["errors"] == {"base": "addon_start_failed"} + + +async def test_addon_not_installed( + hass, + supervisor, + addon_installed, + install_addon, + addon_options, + set_addon_options, + start_addon, +): + """Test add-on not installed.""" + hass.config.components.add("mqtt") + addon_installed.return_value["version"] = None + await setup.async_setup_component(hass, "persistent_notification", {}) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"use_addon": True} + ) + + with patch( + "homeassistant.components.ozw.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.ozw.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"usb_path": "/test", "network_key": "abc123"} + ) + await hass.async_block_till_done() + + assert result["type"] == "create_entry" + assert result["title"] == TITLE + assert result["data"] == { + "usb_path": "/test", + "network_key": "abc123", + "use_addon": True, + "integration_created_addon": True, + } + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_install_addon_failure(hass, supervisor, addon_installed, install_addon): + """Test add-on install failure.""" + hass.config.components.add("mqtt") + addon_installed.return_value["version"] = None + install_addon.side_effect = HassioAPIError() + await setup.async_setup_component(hass, "persistent_notification", {}) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"use_addon": True} + ) + + assert result["type"] == "abort" + assert result["reason"] == "addon_install_failed" diff --git a/tests/components/ozw/test_init.py b/tests/components/ozw/test_init.py index 9a76b4906fa..bf1eefe866a 100644 --- a/tests/components/ozw/test_init.py +++ b/tests/components/ozw/test_init.py @@ -1,5 +1,6 @@ """Test integration initialization.""" from homeassistant import config_entries +from homeassistant.components.hassio.handler import HassioAPIError from homeassistant.components.ozw import DOMAIN, PLATFORMS, const from .common import setup_ozw @@ -60,3 +61,70 @@ async def test_unload_entry(hass, generic_data, switch_msg, caplog): assert len(hass.states.async_entity_ids("switch")) == 1 for record in caplog.records: assert record.levelname != "ERROR" + + +async def test_remove_entry(hass, stop_addon, uninstall_addon, caplog): + """Test remove the config entry.""" + # test successful remove without created add-on + entry = MockConfigEntry( + domain=DOMAIN, + title="Z-Wave", + connection_class=config_entries.CONN_CLASS_LOCAL_PUSH, + data={"integration_created_addon": False}, + ) + entry.add_to_hass(hass) + assert entry.state == config_entries.ENTRY_STATE_NOT_LOADED + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + + await hass.config_entries.async_remove(entry.entry_id) + + assert entry.state == config_entries.ENTRY_STATE_NOT_LOADED + assert len(hass.config_entries.async_entries(DOMAIN)) == 0 + + # test successful remove with created add-on + entry = MockConfigEntry( + domain=DOMAIN, + title="Z-Wave", + connection_class=config_entries.CONN_CLASS_LOCAL_PUSH, + data={"integration_created_addon": True}, + ) + entry.add_to_hass(hass) + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + + await hass.config_entries.async_remove(entry.entry_id) + + stop_addon.call_count == 1 + uninstall_addon.call_count == 1 + assert entry.state == config_entries.ENTRY_STATE_NOT_LOADED + assert len(hass.config_entries.async_entries(DOMAIN)) == 0 + stop_addon.reset_mock() + uninstall_addon.reset_mock() + + # test add-on stop failure + entry.add_to_hass(hass) + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + stop_addon.side_effect = HassioAPIError() + + await hass.config_entries.async_remove(entry.entry_id) + + stop_addon.call_count == 1 + uninstall_addon.call_count == 0 + assert entry.state == config_entries.ENTRY_STATE_NOT_LOADED + assert len(hass.config_entries.async_entries(DOMAIN)) == 0 + assert "Failed to stop the OpenZWave add-on" in caplog.text + stop_addon.side_effect = None + stop_addon.reset_mock() + uninstall_addon.reset_mock() + + # test add-on uninstall failure + entry.add_to_hass(hass) + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + uninstall_addon.side_effect = HassioAPIError() + + await hass.config_entries.async_remove(entry.entry_id) + + stop_addon.call_count == 1 + uninstall_addon.call_count == 1 + assert entry.state == config_entries.ENTRY_STATE_NOT_LOADED + assert len(hass.config_entries.async_entries(DOMAIN)) == 0 + assert "Failed to uninstall the OpenZWave add-on" in caplog.text diff --git a/tests/components/pilight/test_init.py b/tests/components/pilight/test_init.py index 24aa48ddf75..25ccb3dcf36 100644 --- a/tests/components/pilight/test_init.py +++ b/tests/components/pilight/test_init.py @@ -2,20 +2,15 @@ from datetime import timedelta import logging import socket -import unittest -import pytest +from voluptuous import MultipleInvalid from homeassistant.components import pilight -from homeassistant.setup import setup_component +from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util from tests.async_mock import patch -from tests.common import ( - assert_setup_component, - async_fire_time_changed, - get_test_home_assistant, -) +from tests.common import assert_setup_component, async_fire_time_changed _LOGGER = logging.getLogger(__name__) @@ -66,351 +61,340 @@ class PilightDaemonSim: _LOGGER.error("PilightDaemonSim callback: %s", function) -@pytest.mark.skip("Flaky") -class TestPilight(unittest.TestCase): - """Test the Pilight component.""" +@patch("homeassistant.components.pilight._LOGGER.error") +async def test_connection_failed_error(mock_error, hass): + """Try to connect at 127.0.0.1:5001 with socket error.""" + with assert_setup_component(4): + with patch("pilight.pilight.Client", side_effect=socket.error) as mock_client: + assert not await async_setup_component( + hass, pilight.DOMAIN, {pilight.DOMAIN: {}} + ) + mock_client.assert_called_once_with( + host=pilight.DEFAULT_HOST, port=pilight.DEFAULT_PORT + ) + assert mock_error.call_count == 1 - def setUp(self): # pylint: disable=invalid-name - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.skip_teardown_stop = False - self.addCleanup(self.tear_down_cleanup) - def tear_down_cleanup(self): - """Stop everything that was started.""" - if not self.skip_teardown_stop: - self.hass.stop() +@patch("homeassistant.components.pilight._LOGGER.error") +async def test_connection_timeout_error(mock_error, hass): + """Try to connect at 127.0.0.1:5001 with socket timeout.""" + with assert_setup_component(4): + with patch("pilight.pilight.Client", side_effect=socket.timeout) as mock_client: + assert not await async_setup_component( + hass, pilight.DOMAIN, {pilight.DOMAIN: {}} + ) + mock_client.assert_called_once_with( + host=pilight.DEFAULT_HOST, port=pilight.DEFAULT_PORT + ) + assert mock_error.call_count == 1 - @patch("homeassistant.components.pilight._LOGGER.error") - def test_connection_failed_error(self, mock_error): - """Try to connect at 127.0.0.1:5001 with socket error.""" - with assert_setup_component(4): - with patch( - "pilight.pilight.Client", side_effect=socket.error - ) as mock_client: - assert not setup_component( - self.hass, pilight.DOMAIN, {pilight.DOMAIN: {}} - ) - mock_client.assert_called_once_with( - host=pilight.DEFAULT_HOST, port=pilight.DEFAULT_PORT - ) - assert mock_error.call_count == 1 - @patch("homeassistant.components.pilight._LOGGER.error") - def test_connection_timeout_error(self, mock_error): - """Try to connect at 127.0.0.1:5001 with socket timeout.""" - with assert_setup_component(4): - with patch( - "pilight.pilight.Client", side_effect=socket.timeout - ) as mock_client: - assert not setup_component( - self.hass, pilight.DOMAIN, {pilight.DOMAIN: {}} - ) - mock_client.assert_called_once_with( - host=pilight.DEFAULT_HOST, port=pilight.DEFAULT_PORT - ) - assert mock_error.call_count == 1 +@patch("pilight.pilight.Client", PilightDaemonSim) +async def test_send_code_no_protocol(hass): + """Try to send data without protocol information, should give error.""" + with assert_setup_component(4): + assert await async_setup_component(hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.core._LOGGER.error") - @patch("homeassistant.components.pilight._LOGGER.error") - def test_send_code_no_protocol(self, mock_pilight_error, mock_error): - """Try to send data without protocol information, should give error.""" - with assert_setup_component(4): - assert setup_component(self.hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) - - # Call without protocol info, should be ignored with error - self.hass.services.call( + # Call without protocol info, should raise an error + try: + await hass.services.async_call( pilight.DOMAIN, pilight.SERVICE_NAME, service_data={"noprotocol": "test", "value": 42}, blocking=True, ) - self.hass.block_till_done() - error_log_call = mock_error.call_args_list[-1] - assert "required key not provided @ data['protocol']" in str(error_log_call) + await hass.async_block_till_done() + except MultipleInvalid as error: + assert "required key not provided @ data['protocol']" in str(error) - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.components.pilight._LOGGER.error") - def test_send_code(self, mock_pilight_error): - """Try to send proper data.""" - with assert_setup_component(4): - assert setup_component(self.hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) + +@patch("homeassistant.components.pilight._LOGGER.error") +@patch("homeassistant.components.pilight._LOGGER", _LOGGER) +@patch("pilight.pilight.Client", PilightDaemonSim) +async def test_send_code(mock_pilight_error, hass): + """Try to send proper data.""" + with assert_setup_component(4): + assert await async_setup_component(hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) + + # Call with protocol info, should not give error + service_data = {"protocol": "test", "value": 42} + await hass.services.async_call( + pilight.DOMAIN, + pilight.SERVICE_NAME, + service_data=service_data, + blocking=True, + ) + await hass.async_block_till_done() + error_log_call = mock_pilight_error.call_args_list[-1] + service_data["protocol"] = [service_data["protocol"]] + assert str(service_data) in str(error_log_call) + + +@patch("pilight.pilight.Client", PilightDaemonSim) +@patch("homeassistant.components.pilight._LOGGER.error") +async def test_send_code_fail(mock_pilight_error, hass): + """Check IOError exception error message.""" + with assert_setup_component(4): + with patch("pilight.pilight.Client.send_code", side_effect=IOError): + assert await async_setup_component( + hass, pilight.DOMAIN, {pilight.DOMAIN: {}} + ) # Call with protocol info, should not give error service_data = {"protocol": "test", "value": 42} - self.hass.services.call( + await hass.services.async_call( pilight.DOMAIN, pilight.SERVICE_NAME, service_data=service_data, blocking=True, ) - self.hass.block_till_done() + await hass.async_block_till_done() error_log_call = mock_pilight_error.call_args_list[-1] - service_data["protocol"] = [service_data["protocol"]] - assert str(service_data) in str(error_log_call) - - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.components.pilight._LOGGER.error") - def test_send_code_fail(self, mock_pilight_error): - """Check IOError exception error message.""" - with assert_setup_component(4): - with patch("pilight.pilight.Client.send_code", side_effect=IOError): - assert setup_component(self.hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) - - # Call with protocol info, should not give error - service_data = {"protocol": "test", "value": 42} - self.hass.services.call( - pilight.DOMAIN, - pilight.SERVICE_NAME, - service_data=service_data, - blocking=True, - ) - self.hass.block_till_done() - error_log_call = mock_pilight_error.call_args_list[-1] - assert "Pilight send failed" in str(error_log_call) - - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.components.pilight._LOGGER.error") - def test_send_code_delay(self, mock_pilight_error): - """Try to send proper data with delay afterwards.""" - with assert_setup_component(4): - assert setup_component( - self.hass, - pilight.DOMAIN, - {pilight.DOMAIN: {pilight.CONF_SEND_DELAY: 5.0}}, - ) - - # Call with protocol info, should not give error - service_data1 = {"protocol": "test11", "value": 42} - service_data2 = {"protocol": "test22", "value": 42} - self.hass.services.call( - pilight.DOMAIN, - pilight.SERVICE_NAME, - service_data=service_data1, - blocking=True, - ) - self.hass.services.call( - pilight.DOMAIN, - pilight.SERVICE_NAME, - service_data=service_data2, - blocking=True, - ) - service_data1["protocol"] = [service_data1["protocol"]] - service_data2["protocol"] = [service_data2["protocol"]] - - async_fire_time_changed(self.hass, dt_util.utcnow()) - self.hass.block_till_done() - error_log_call = mock_pilight_error.call_args_list[-1] - assert str(service_data1) in str(error_log_call) - - new_time = dt_util.utcnow() + timedelta(seconds=5) - async_fire_time_changed(self.hass, new_time) - self.hass.block_till_done() - error_log_call = mock_pilight_error.call_args_list[-1] - assert str(service_data2) in str(error_log_call) - - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.components.pilight._LOGGER.error") - def test_start_stop(self, mock_pilight_error): - """Check correct startup and stop of pilight daemon.""" - with assert_setup_component(4): - assert setup_component(self.hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) - - # Test startup - self.hass.start() - self.hass.block_till_done() - error_log_call = mock_pilight_error.call_args_list[-2] - assert "PilightDaemonSim callback" in str(error_log_call) - error_log_call = mock_pilight_error.call_args_list[-1] - assert "PilightDaemonSim start" in str(error_log_call) - - # Test stop - self.skip_teardown_stop = True - self.hass.stop() - error_log_call = mock_pilight_error.call_args_list[-1] - assert "PilightDaemonSim stop" in str(error_log_call) - - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.core._LOGGER.info") - def test_receive_code(self, mock_info): - """Check if code receiving via pilight daemon works.""" - with assert_setup_component(4): - assert setup_component(self.hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) - - # Test startup - self.hass.start() - self.hass.block_till_done() - - expected_message = dict( - { - "protocol": PilightDaemonSim.test_message["protocol"], - "uuid": PilightDaemonSim.test_message["uuid"], - }, - **PilightDaemonSim.test_message["message"], - ) - error_log_call = mock_info.call_args_list[-1] - - # Check if all message parts are put on event bus - for key, value in expected_message.items(): - assert str(key) in str(error_log_call) - assert str(value) in str(error_log_call) - - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.core._LOGGER.info") - def test_whitelist_exact_match(self, mock_info): - """Check whitelist filter with matched data.""" - with assert_setup_component(4): - whitelist = { - "protocol": [PilightDaemonSim.test_message["protocol"]], - "uuid": [PilightDaemonSim.test_message["uuid"]], - "id": [PilightDaemonSim.test_message["message"]["id"]], - "unit": [PilightDaemonSim.test_message["message"]["unit"]], - } - assert setup_component( - self.hass, pilight.DOMAIN, {pilight.DOMAIN: {"whitelist": whitelist}} - ) - - self.hass.start() - self.hass.block_till_done() - - expected_message = dict( - { - "protocol": PilightDaemonSim.test_message["protocol"], - "uuid": PilightDaemonSim.test_message["uuid"], - }, - **PilightDaemonSim.test_message["message"], - ) - info_log_call = mock_info.call_args_list[-1] - - # Check if all message parts are put on event bus - for key, value in expected_message.items(): - assert str(key) in str(info_log_call) - assert str(value) in str(info_log_call) - - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.core._LOGGER.info") - def test_whitelist_partial_match(self, mock_info): - """Check whitelist filter with partially matched data, should work.""" - with assert_setup_component(4): - whitelist = { - "protocol": [PilightDaemonSim.test_message["protocol"]], - "id": [PilightDaemonSim.test_message["message"]["id"]], - } - assert setup_component( - self.hass, pilight.DOMAIN, {pilight.DOMAIN: {"whitelist": whitelist}} - ) - - self.hass.start() - self.hass.block_till_done() - - expected_message = dict( - { - "protocol": PilightDaemonSim.test_message["protocol"], - "uuid": PilightDaemonSim.test_message["uuid"], - }, - **PilightDaemonSim.test_message["message"], - ) - info_log_call = mock_info.call_args_list[-1] - - # Check if all message parts are put on event bus - for key, value in expected_message.items(): - assert str(key) in str(info_log_call) - assert str(value) in str(info_log_call) - - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.core._LOGGER.info") - def test_whitelist_or_match(self, mock_info): - """Check whitelist filter with several subsection, should work.""" - with assert_setup_component(4): - whitelist = { - "protocol": [ - PilightDaemonSim.test_message["protocol"], - "other_protocol", - ], - "id": [PilightDaemonSim.test_message["message"]["id"]], - } - assert setup_component( - self.hass, pilight.DOMAIN, {pilight.DOMAIN: {"whitelist": whitelist}} - ) - - self.hass.start() - self.hass.block_till_done() - - expected_message = dict( - { - "protocol": PilightDaemonSim.test_message["protocol"], - "uuid": PilightDaemonSim.test_message["uuid"], - }, - **PilightDaemonSim.test_message["message"], - ) - info_log_call = mock_info.call_args_list[-1] - - # Check if all message parts are put on event bus - for key, value in expected_message.items(): - assert str(key) in str(info_log_call) - assert str(value) in str(info_log_call) - - @patch("pilight.pilight.Client", PilightDaemonSim) - @patch("homeassistant.core._LOGGER.info") - def test_whitelist_no_match(self, mock_info): - """Check whitelist filter with unmatched data, should not work.""" - with assert_setup_component(4): - whitelist = { - "protocol": ["wrong_protocol"], - "id": [PilightDaemonSim.test_message["message"]["id"]], - } - assert setup_component( - self.hass, pilight.DOMAIN, {pilight.DOMAIN: {"whitelist": whitelist}} - ) - - self.hass.start() - self.hass.block_till_done() - - info_log_call = mock_info.call_args_list[-1] - - assert not ("Event pilight_received" in info_log_call) + assert "Pilight send failed" in str(error_log_call) -class TestPilightCallrateThrottler(unittest.TestCase): - """Test the Throttler used to throttle calls to send_code.""" +@patch("homeassistant.components.pilight._LOGGER.error") +@patch("homeassistant.components.pilight._LOGGER", _LOGGER) +@patch("pilight.pilight.Client", PilightDaemonSim) +async def test_send_code_delay(mock_pilight_error, hass): + """Try to send proper data with delay afterwards.""" + with assert_setup_component(4): + assert await async_setup_component( + hass, + pilight.DOMAIN, + {pilight.DOMAIN: {pilight.CONF_SEND_DELAY: 5.0}}, + ) - def setUp(self): # pylint: disable=invalid-name - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.addCleanup(self.hass.stop) + # Call with protocol info, should not give error + service_data1 = {"protocol": "test11", "value": 42} + service_data2 = {"protocol": "test22", "value": 42} + await hass.services.async_call( + pilight.DOMAIN, + pilight.SERVICE_NAME, + service_data=service_data1, + blocking=True, + ) + await hass.services.async_call( + pilight.DOMAIN, + pilight.SERVICE_NAME, + service_data=service_data2, + blocking=True, + ) + service_data1["protocol"] = [service_data1["protocol"]] + service_data2["protocol"] = [service_data2["protocol"]] - def test_call_rate_delay_throttle_disabled(self): - """Test that the limiter is a noop if no delay set.""" - runs = [] + async_fire_time_changed(hass, dt_util.utcnow()) + await hass.async_block_till_done() + error_log_call = mock_pilight_error.call_args_list[-1] + assert str(service_data1) in str(error_log_call) - limit = pilight.CallRateDelayThrottle(self.hass, 0.0) - action = limit.limited(lambda x: runs.append(x)) + new_time = dt_util.utcnow() + timedelta(seconds=5) + async_fire_time_changed(hass, new_time) + await hass.async_block_till_done() + error_log_call = mock_pilight_error.call_args_list[-1] + assert str(service_data2) in str(error_log_call) - for i in range(3): - action(i) - assert runs == [0, 1, 2] +@patch("homeassistant.components.pilight._LOGGER.error") +@patch("homeassistant.components.pilight._LOGGER", _LOGGER) +@patch("pilight.pilight.Client", PilightDaemonSim) +async def test_start_stop(mock_pilight_error, hass): + """Check correct startup and stop of pilight daemon.""" + with assert_setup_component(4): + assert await async_setup_component(hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) - def test_call_rate_delay_throttle_enabled(self): - """Test that throttling actually work.""" - runs = [] - delay = 5.0 + # Test startup + await hass.async_start() + await hass.async_block_till_done() - limit = pilight.CallRateDelayThrottle(self.hass, delay) - action = limit.limited(lambda x: runs.append(x)) + error_log_call = mock_pilight_error.call_args_list[-2] + assert "PilightDaemonSim callback" in str(error_log_call) + error_log_call = mock_pilight_error.call_args_list[-1] + assert "PilightDaemonSim start" in str(error_log_call) - for i in range(3): - action(i) + # Test stop + with patch.object(hass.loop, "stop"): + await hass.async_stop() + error_log_call = mock_pilight_error.call_args_list[-1] + assert "PilightDaemonSim stop" in str(error_log_call) - self.hass.block_till_done() - assert runs == [0] - exp = [] - now = dt_util.utcnow() - for i in range(3): - exp.append(i) - shifted_time = now + (timedelta(seconds=delay + 0.1) * i) - async_fire_time_changed(self.hass, shifted_time) - self.hass.block_till_done() - assert runs == exp +@patch("pilight.pilight.Client", PilightDaemonSim) +@patch("homeassistant.core._LOGGER.debug") +async def test_receive_code(mock_debug, hass): + """Check if code receiving via pilight daemon works.""" + with assert_setup_component(4): + assert await async_setup_component(hass, pilight.DOMAIN, {pilight.DOMAIN: {}}) + + # Test startup + await hass.async_start() + await hass.async_block_till_done() + + expected_message = dict( + { + "protocol": PilightDaemonSim.test_message["protocol"], + "uuid": PilightDaemonSim.test_message["uuid"], + }, + **PilightDaemonSim.test_message["message"], + ) + debug_log_call = mock_debug.call_args_list[-3] + + # Check if all message parts are put on event bus + for key, value in expected_message.items(): + assert str(key) in str(debug_log_call) + assert str(value) in str(debug_log_call) + + +@patch("pilight.pilight.Client", PilightDaemonSim) +@patch("homeassistant.core._LOGGER.debug") +async def test_whitelist_exact_match(mock_debug, hass): + """Check whitelist filter with matched data.""" + with assert_setup_component(4): + whitelist = { + "protocol": [PilightDaemonSim.test_message["protocol"]], + "uuid": [PilightDaemonSim.test_message["uuid"]], + "id": [PilightDaemonSim.test_message["message"]["id"]], + "unit": [PilightDaemonSim.test_message["message"]["unit"]], + } + assert await async_setup_component( + hass, pilight.DOMAIN, {pilight.DOMAIN: {"whitelist": whitelist}} + ) + + await hass.async_start() + await hass.async_block_till_done() + + expected_message = dict( + { + "protocol": PilightDaemonSim.test_message["protocol"], + "uuid": PilightDaemonSim.test_message["uuid"], + }, + **PilightDaemonSim.test_message["message"], + ) + debug_log_call = mock_debug.call_args_list[-3] + + # Check if all message parts are put on event bus + for key, value in expected_message.items(): + assert str(key) in str(debug_log_call) + assert str(value) in str(debug_log_call) + + +@patch("pilight.pilight.Client", PilightDaemonSim) +@patch("homeassistant.core._LOGGER.debug") +async def test_whitelist_partial_match(mock_debug, hass): + """Check whitelist filter with partially matched data, should work.""" + with assert_setup_component(4): + whitelist = { + "protocol": [PilightDaemonSim.test_message["protocol"]], + "id": [PilightDaemonSim.test_message["message"]["id"]], + } + assert await async_setup_component( + hass, pilight.DOMAIN, {pilight.DOMAIN: {"whitelist": whitelist}} + ) + + await hass.async_start() + await hass.async_block_till_done() + + expected_message = dict( + { + "protocol": PilightDaemonSim.test_message["protocol"], + "uuid": PilightDaemonSim.test_message["uuid"], + }, + **PilightDaemonSim.test_message["message"], + ) + debug_log_call = mock_debug.call_args_list[-3] + + # Check if all message parts are put on event bus + for key, value in expected_message.items(): + assert str(key) in str(debug_log_call) + assert str(value) in str(debug_log_call) + + +@patch("pilight.pilight.Client", PilightDaemonSim) +@patch("homeassistant.core._LOGGER.debug") +async def test_whitelist_or_match(mock_debug, hass): + """Check whitelist filter with several subsection, should work.""" + with assert_setup_component(4): + whitelist = { + "protocol": [ + PilightDaemonSim.test_message["protocol"], + "other_protocol", + ], + "id": [PilightDaemonSim.test_message["message"]["id"]], + } + assert await async_setup_component( + hass, pilight.DOMAIN, {pilight.DOMAIN: {"whitelist": whitelist}} + ) + + await hass.async_start() + await hass.async_block_till_done() + + expected_message = dict( + { + "protocol": PilightDaemonSim.test_message["protocol"], + "uuid": PilightDaemonSim.test_message["uuid"], + }, + **PilightDaemonSim.test_message["message"], + ) + debug_log_call = mock_debug.call_args_list[-3] + + # Check if all message parts are put on event bus + for key, value in expected_message.items(): + assert str(key) in str(debug_log_call) + assert str(value) in str(debug_log_call) + + +@patch("pilight.pilight.Client", PilightDaemonSim) +@patch("homeassistant.core._LOGGER.debug") +async def test_whitelist_no_match(mock_debug, hass): + """Check whitelist filter with unmatched data, should not work.""" + with assert_setup_component(4): + whitelist = { + "protocol": ["wrong_protocol"], + "id": [PilightDaemonSim.test_message["message"]["id"]], + } + assert await async_setup_component( + hass, pilight.DOMAIN, {pilight.DOMAIN: {"whitelist": whitelist}} + ) + + await hass.async_start() + await hass.async_block_till_done() + debug_log_call = mock_debug.call_args_list[-3] + + assert not ("Event pilight_received" in debug_log_call) + + +async def test_call_rate_delay_throttle_enabled(hass): + """Test that throttling actually work.""" + runs = [] + delay = 5.0 + + limit = pilight.CallRateDelayThrottle(hass, delay) + action = limit.limited(lambda x: runs.append(x)) + + for i in range(3): + await hass.async_add_executor_job(action, i) + + await hass.async_block_till_done() + assert runs == [0] + + exp = [] + now = dt_util.utcnow() + for i in range(3): + exp.append(i) + shifted_time = now + (timedelta(seconds=delay + 0.1) * i) + async_fire_time_changed(hass, shifted_time) + await hass.async_block_till_done() + assert runs == exp + + +def test_call_rate_delay_throttle_disabled(hass): + """Test that the limiter is a noop if no delay set.""" + runs = [] + + limit = pilight.CallRateDelayThrottle(hass, 0.0) + action = limit.limited(lambda x: runs.append(x)) + + for i in range(3): + action(i) + + assert runs == [0, 1, 2] diff --git a/tests/components/pilight/test_sensor.py b/tests/components/pilight/test_sensor.py index 54c72675bc7..e4ab4ce5651 100644 --- a/tests/components/pilight/test_sensor.py +++ b/tests/components/pilight/test_sensor.py @@ -1,42 +1,34 @@ """The tests for the Pilight sensor platform.""" import logging +import pytest + from homeassistant.components import pilight import homeassistant.components.sensor as sensor -from homeassistant.setup import setup_component +from homeassistant.setup import async_setup_component -from tests.common import assert_setup_component, get_test_home_assistant, mock_component - -HASS = None +from tests.common import assert_setup_component, mock_component -def fire_pilight_message(protocol, data): +@pytest.fixture(autouse=True) +def setup_comp(hass): + """Initialize components.""" + mock_component(hass, "pilight") + + +def fire_pilight_message(hass, protocol, data): """Fire the fake Pilight message.""" message = {pilight.CONF_PROTOCOL: protocol} message.update(data) - HASS.bus.fire(pilight.EVENT, message) + + hass.bus.async_fire(pilight.EVENT, message) -# pylint: disable=invalid-name -def setup_function(): - """Initialize a Home Assistant server.""" - global HASS - - HASS = get_test_home_assistant() - mock_component(HASS, "pilight") - - -# pylint: disable=invalid-name -def teardown_function(): - """Stop the Home Assistant server.""" - HASS.stop() - - -def test_sensor_value_from_code(): +async def test_sensor_value_from_code(hass): """Test the setting of value via pilight.""" with assert_setup_component(1): - setup_component( - HASS, + assert await async_setup_component( + hass, sensor.DOMAIN, { sensor.DOMAIN: { @@ -48,26 +40,26 @@ def test_sensor_value_from_code(): } }, ) - HASS.block_till_done() + await hass.async_block_till_done() - state = HASS.states.get("sensor.test") + state = hass.states.get("sensor.test") assert state.state == "unknown" unit_of_measurement = state.attributes.get("unit_of_measurement") assert unit_of_measurement == "fav unit" # Set value from data with correct payload - fire_pilight_message(protocol="test-protocol", data={"test": 42}) - HASS.block_till_done() - state = HASS.states.get("sensor.test") + fire_pilight_message(hass, protocol="test-protocol", data={"test": 42}) + await hass.async_block_till_done() + state = hass.states.get("sensor.test") assert state.state == "42" -def test_disregard_wrong_payload(): +async def test_disregard_wrong_payload(hass): """Test omitting setting of value with wrong payload.""" with assert_setup_component(1): - setup_component( - HASS, + assert await async_setup_component( + hass, sensor.DOMAIN, { sensor.DOMAIN: { @@ -78,40 +70,41 @@ def test_disregard_wrong_payload(): } }, ) - HASS.block_till_done() + await hass.async_block_till_done() # Try set value from data with incorrect payload fire_pilight_message( - protocol="test-protocol_2", data={"test": "data", "uuid": "0-0-0-0"} + hass, protocol="test-protocol_2", data={"test": "data", "uuid": "0-0-0-0"} ) - HASS.block_till_done() - state = HASS.states.get("sensor.test_2") + await hass.async_block_till_done() + state = hass.states.get("sensor.test_2") assert state.state == "unknown" # Try set value from data with partially matched payload fire_pilight_message( - protocol="wrong-protocol", data={"test": "data", "uuid": "1-2-3-4"} + hass, protocol="wrong-protocol", data={"test": "data", "uuid": "1-2-3-4"} ) - HASS.block_till_done() - state = HASS.states.get("sensor.test_2") + await hass.async_block_till_done() + state = hass.states.get("sensor.test_2") assert state.state == "unknown" # Try set value from data with fully matched payload fire_pilight_message( + hass, protocol="test-protocol_2", data={"test": "data", "uuid": "1-2-3-4", "other_payload": 3.141}, ) - HASS.block_till_done() - state = HASS.states.get("sensor.test_2") + await hass.async_block_till_done() + state = hass.states.get("sensor.test_2") assert state.state == "data" -def test_variable_missing(caplog): +async def test_variable_missing(hass, caplog): """Check if error message when variable missing.""" caplog.set_level(logging.ERROR) with assert_setup_component(1): - setup_component( - HASS, + assert await async_setup_component( + hass, sensor.DOMAIN, { sensor.DOMAIN: { @@ -122,13 +115,15 @@ def test_variable_missing(caplog): } }, ) - HASS.block_till_done() + await hass.async_block_till_done() # Create code without sensor variable fire_pilight_message( - protocol="test-protocol", data={"uuid": "1-2-3-4", "other_variable": 3.141} + hass, + protocol="test-protocol", + data={"uuid": "1-2-3-4", "other_variable": 3.141}, ) - HASS.block_till_done() + await hass.async_block_till_done() logs = caplog.text diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 5af2bf2ccd3..0f0e4551b1c 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -178,3 +178,36 @@ def mock_smile_p1(): ) yield smile_mock.return_value + + +@pytest.fixture(name="mock_stretch") +def mock_stretch(): + """Create a Mock Stretch environment for testing exceptions.""" + chosen_env = "stretch_v31" + with patch("homeassistant.components.plugwise.gateway.Smile") as smile_mock: + smile_mock.InvalidAuthentication = Smile.InvalidAuthentication + smile_mock.ConnectionFailedError = Smile.ConnectionFailedError + smile_mock.XMLDataMissingError = Smile.XMLDataMissingError + + smile_mock.return_value.gateway_id = "259882df3c05415b99c2d962534ce820" + smile_mock.return_value.heater_id = None + smile_mock.return_value.smile_version = "3.1.11" + smile_mock.return_value.smile_type = "stretch" + smile_mock.return_value.smile_hostname = "stretch98765" + + smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True) + smile_mock.return_value.full_update_device.side_effect = AsyncMock( + return_value=True + ) + smile_mock.return_value.set_relay_state.side_effect = AsyncMock( + return_value=True + ) + + smile_mock.return_value.get_all_devices.return_value = _read_json( + chosen_env, "get_all_devices" + ) + smile_mock.return_value.get_device_data.side_effect = partial( + _get_device_data, chosen_env + ) + + yield smile_mock.return_value diff --git a/tests/components/plugwise/test_config_flow.py b/tests/components/plugwise/test_config_flow.py index 9b67f06e469..dea42dfb01d 100644 --- a/tests/components/plugwise/test_config_flow.py +++ b/tests/components/plugwise/test_config_flow.py @@ -9,7 +9,14 @@ from homeassistant.components.plugwise.const import ( DOMAIN, ) from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF -from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_SCAN_INTERVAL +from homeassistant.const import ( + CONF_HOST, + CONF_NAME, + CONF_PASSWORD, + CONF_PORT, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) from tests.async_mock import MagicMock, patch from tests.common import MockConfigEntry @@ -18,6 +25,8 @@ TEST_HOST = "1.1.1.1" TEST_HOSTNAME = "smileabcdef" TEST_PASSWORD = "test_password" TEST_PORT = 81 +TEST_USERNAME = "smile" +TEST_USERNAME2 = "stretch" TEST_DISCOVERY = { "host": TEST_HOST, @@ -66,16 +75,17 @@ async def test_form(hass): ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, ) await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["data"] == { - "host": TEST_HOST, - "password": TEST_PASSWORD, - "port": DEFAULT_PORT, + CONF_HOST: TEST_HOST, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: DEFAULT_PORT, + CONF_USERNAME: TEST_USERNAME, } assert len(mock_setup.mock_calls) == 1 @@ -105,16 +115,58 @@ async def test_zeroconf_form(hass): ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"password": TEST_PASSWORD}, + {CONF_PASSWORD: TEST_PASSWORD}, ) await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["data"] == { - "host": TEST_HOST, - "password": TEST_PASSWORD, - "port": DEFAULT_PORT, + CONF_HOST: TEST_HOST, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: DEFAULT_PORT, + CONF_USERNAME: TEST_USERNAME, + } + + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_form_username(hass): + """Test we get the username data back.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["errors"] == {} + + with patch( + "homeassistant.components.plugwise.config_flow.Smile.connect", + return_value=True, + ), patch( + "homeassistant.components.plugwise.async_setup", + return_value=True, + ) as mock_setup, patch( + "homeassistant.components.plugwise.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_HOST: TEST_HOST, + CONF_PASSWORD: TEST_PASSWORD, + CONF_USERNAME: TEST_USERNAME2, + }, + ) + + await hass.async_block_till_done() + + assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result2["data"] == { + CONF_HOST: TEST_HOST, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: DEFAULT_PORT, + CONF_USERNAME: TEST_USERNAME2, } assert len(mock_setup.mock_calls) == 1 @@ -140,7 +192,7 @@ async def test_zeroconf_form(hass): ) as mock_setup_entry: result4 = await hass.config_entries.flow.async_configure( result3["flow_id"], - {"password": TEST_PASSWORD}, + {CONF_PASSWORD: TEST_PASSWORD}, ) await hass.async_block_till_done() @@ -160,7 +212,7 @@ async def test_form_invalid_auth(hass, mock_smile): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM @@ -178,7 +230,7 @@ async def test_form_cannot_connect(hass, mock_smile): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM @@ -196,7 +248,7 @@ async def test_form_cannot_connect_port(hass, mock_smile): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD, "port": TEST_PORT}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD, CONF_PORT: TEST_PORT}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM @@ -214,7 +266,7 @@ async def test_form_other_problem(hass, mock_smile): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM diff --git a/tests/components/plugwise/test_sensor.py b/tests/components/plugwise/test_sensor.py index bc586120517..a727337d747 100644 --- a/tests/components/plugwise/test_sensor.py +++ b/tests/components/plugwise/test_sensor.py @@ -27,7 +27,7 @@ async def test_adam_climate_sensor_entities(hass, mock_smile_adam): ) state = hass.states.get("sensor.zone_lisa_wk_battery") - assert float(state.state) == 34 + assert int(state.state) == 34 async def test_anna_climate_sensor_entities(hass, mock_smile_anna): @@ -54,13 +54,25 @@ async def test_p1_dsmr_sensor_entities(hass, mock_smile_p1): assert float(state.state) == -2761.0 state = hass.states.get("sensor.p1_electricity_consumed_off_peak_cumulative") - assert int(state.state) == 551 + assert float(state.state) == 551.1 state = hass.states.get("sensor.p1_electricity_produced_peak_point") assert float(state.state) == 2761.0 state = hass.states.get("sensor.p1_electricity_consumed_peak_cumulative") - assert int(state.state) == 442 + assert float(state.state) == 442.9 state = hass.states.get("sensor.p1_gas_consumed_cumulative") assert float(state.state) == 584.9 + + +async def test_stretch_sensor_entities(hass, mock_stretch): + """Test creation of power related sensor entities.""" + entry = await async_init_integration(hass, mock_stretch) + assert entry.state == ENTRY_STATE_LOADED + + state = hass.states.get("sensor.koelkast_92c4a_electricity_consumed") + assert float(state.state) == 53.2 + + state = hass.states.get("sensor.droger_52559_electricity_consumed_interval") + assert float(state.state) == 1.06 diff --git a/tests/components/plugwise/test_switch.py b/tests/components/plugwise/test_switch.py index a58ebf83caa..ded21113f2b 100644 --- a/tests/components/plugwise/test_switch.py +++ b/tests/components/plugwise/test_switch.py @@ -48,3 +48,49 @@ async def test_adam_climate_switch_changes(hass, mock_smile_adam): ) state = hass.states.get("switch.fibaro_hc2") assert str(state.state) == "on" + + +async def test_stretch_switch_entities(hass, mock_stretch): + """Test creation of climate related switch entities.""" + entry = await async_init_integration(hass, mock_stretch) + assert entry.state == ENTRY_STATE_LOADED + + state = hass.states.get("switch.koelkast_92c4a") + assert str(state.state) == "on" + + state = hass.states.get("switch.droger_52559") + assert str(state.state) == "on" + + +async def test_stretch_switch_changes(hass, mock_stretch): + """Test changing of power related switch entities.""" + entry = await async_init_integration(hass, mock_stretch) + assert entry.state == ENTRY_STATE_LOADED + + await hass.services.async_call( + "switch", + "turn_off", + {"entity_id": "switch.koelkast_92c4a"}, + blocking=True, + ) + + state = hass.states.get("switch.koelkast_92c4a") + assert str(state.state) == "off" + + await hass.services.async_call( + "switch", + "toggle", + {"entity_id": "switch.droger_52559"}, + blocking=True, + ) + state = hass.states.get("switch.droger_52559") + assert str(state.state) == "off" + + await hass.services.async_call( + "switch", + "toggle", + {"entity_id": "switch.droger_52559"}, + blocking=True, + ) + state = hass.states.get("switch.droger_52559") + assert str(state.state) == "on" diff --git a/tests/components/plum_lightpad/test_config_flow.py b/tests/components/plum_lightpad/test_config_flow.py index 7f6196ef9b7..f2ac756c4a3 100644 --- a/tests/components/plum_lightpad/test_config_flow.py +++ b/tests/components/plum_lightpad/test_config_flow.py @@ -30,6 +30,7 @@ async def test_form(hass): result["flow_id"], {"username": "test-plum-username", "password": "test-plum-password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "test-plum-username" @@ -37,7 +38,6 @@ async def test_form(hass): "username": "test-plum-username", "password": "test-plum-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/poolsense/test_config_flow.py b/tests/components/poolsense/test_config_flow.py index c969ed9c416..8ea05339c84 100644 --- a/tests/components/poolsense/test_config_flow.py +++ b/tests/components/poolsense/test_config_flow.py @@ -47,10 +47,10 @@ async def test_valid_credentials(hass): context={"source": SOURCE_USER}, data={CONF_EMAIL: "test-email", CONF_PASSWORD: "test-password"}, ) + await hass.async_block_till_done() assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["title"] == "test-email" - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/powerwall/test_config_flow.py b/tests/components/powerwall/test_config_flow.py index 5f9445debe0..4f1a587b31b 100644 --- a/tests/components/powerwall/test_config_flow.py +++ b/tests/components/powerwall/test_config_flow.py @@ -35,11 +35,11 @@ async def test_form_source_user(hass): result["flow_id"], {CONF_IP_ADDRESS: "1.2.3.4"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "My site" assert result2["data"] == {CONF_IP_ADDRESS: "1.2.3.4"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -63,11 +63,11 @@ async def test_form_source_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data={CONF_IP_ADDRESS: "1.2.3.4"}, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "Imported site" assert result["data"] == {CONF_IP_ADDRESS: "1.2.3.4"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/profiler/test_config_flow.py b/tests/components/profiler/test_config_flow.py index e6cb62421af..dc2ddff14d9 100644 --- a/tests/components/profiler/test_config_flow.py +++ b/tests/components/profiler/test_config_flow.py @@ -25,11 +25,11 @@ async def test_form_user(hass): result["flow_id"], {}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Profiler" assert result2["data"] == {} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/profiler/test_init.py b/tests/components/profiler/test_init.py index 2373e64a593..0ccda904eb6 100644 --- a/tests/components/profiler/test_init.py +++ b/tests/components/profiler/test_init.py @@ -1,12 +1,23 @@ """Test the Profiler config flow.""" +from datetime import timedelta import os from homeassistant import setup -from homeassistant.components.profiler import CONF_SECONDS, SERVICE_START +from homeassistant.components.profiler import ( + CONF_SCAN_INTERVAL, + CONF_SECONDS, + CONF_TYPE, + SERVICE_DUMP_LOG_OBJECTS, + SERVICE_MEMORY, + SERVICE_START, + SERVICE_START_LOG_OBJECTS, + SERVICE_STOP_LOG_OBJECTS, +) from homeassistant.components.profiler.const import DOMAIN +import homeassistant.util.dt as dt_util from tests.async_mock import patch -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, async_fire_time_changed async def test_basic_usage(hass, tmpdir): @@ -39,3 +50,100 @@ async def test_basic_usage(hass, tmpdir): 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() + + +async def test_object_growth_logging(hass, caplog): + """Test we can setup and the service and we can dump objects to the log.""" + + 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_START_LOG_OBJECTS) + assert hass.services.has_service(DOMAIN, SERVICE_STOP_LOG_OBJECTS) + + await hass.services.async_call( + DOMAIN, SERVICE_START_LOG_OBJECTS, {CONF_SCAN_INTERVAL: 10} + ) + await hass.async_block_till_done() + + assert "Growth" in caplog.text + caplog.clear() + + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=11)) + await hass.async_block_till_done() + assert "Growth" in caplog.text + + await hass.services.async_call(DOMAIN, SERVICE_STOP_LOG_OBJECTS, {}) + await hass.async_block_till_done() + caplog.clear() + + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=21)) + await hass.async_block_till_done() + assert "Growth" not in caplog.text + + assert await hass.config_entries.async_unload(entry.entry_id) + await hass.async_block_till_done() + + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=31)) + await hass.async_block_till_done() + assert "Growth" not in caplog.text + + +async def test_dump_log_object(hass, caplog): + """Test we can setup and the service is registered and logging works.""" + + 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_DUMP_LOG_OBJECTS) + + await hass.services.async_call( + DOMAIN, SERVICE_DUMP_LOG_OBJECTS, {CONF_TYPE: "MockConfigEntry"} + ) + await hass.async_block_till_done() + + assert "MockConfigEntry" in caplog.text + caplog.clear() + + assert await hass.config_entries.async_unload(entry.entry_id) + await hass.async_block_till_done() diff --git a/tests/components/pvpc_hourly_pricing/test_sensor.py b/tests/components/pvpc_hourly_pricing/test_sensor.py index 6dae784a0cc..ca3dec1e891 100644 --- a/tests/components/pvpc_hourly_pricing/test_sensor.py +++ b/tests/components/pvpc_hourly_pricing/test_sensor.py @@ -54,7 +54,11 @@ async def test_sensor_availability( # 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/components/rachio/test_config_flow.py b/tests/components/rachio/test_config_flow.py index eb6b5ef4386..75d671262a1 100644 --- a/tests/components/rachio/test_config_flow.py +++ b/tests/components/rachio/test_config_flow.py @@ -50,6 +50,7 @@ async def test_form(hass): CONF_MANUAL_RUN_MINS: 5, }, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "myusername" @@ -58,7 +59,6 @@ async def test_form(hass): CONF_CUSTOM_URL: "http://custom.url", CONF_MANUAL_RUN_MINS: 5, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/rainmachine/test_config_flow.py b/tests/components/rainmachine/test_config_flow.py index b07e5ab81d3..7fb30d0043d 100644 --- a/tests/components/rainmachine/test_config_flow.py +++ b/tests/components/rainmachine/test_config_flow.py @@ -4,13 +4,7 @@ from regenmaschine.errors import RainMachineError from homeassistant import data_entry_flow from homeassistant.components.rainmachine import CONF_ZONE_RUN_TIME, DOMAIN, config_flow from homeassistant.config_entries import SOURCE_USER -from homeassistant.const import ( - CONF_IP_ADDRESS, - CONF_PASSWORD, - CONF_PORT, - CONF_SCAN_INTERVAL, - CONF_SSL, -) +from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SSL from tests.async_mock import patch from tests.common import MockConfigEntry @@ -57,6 +51,40 @@ async def test_invalid_password(hass): assert result["errors"] == {CONF_PASSWORD: "invalid_auth"} +async def test_options_flow(hass): + """Test config flow options.""" + conf = { + CONF_IP_ADDRESS: "192.168.1.100", + CONF_PASSWORD: "password", + CONF_PORT: 8080, + CONF_SSL: True, + } + + config_entry = MockConfigEntry( + domain=DOMAIN, + unique_id="abcde12345", + data=conf, + options={CONF_ZONE_RUN_TIME: 900}, + ) + config_entry.add_to_hass(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 + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], user_input={CONF_ZONE_RUN_TIME: 600} + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert config_entry.options == {CONF_ZONE_RUN_TIME: 600} + + async def test_show_form(hass): """Test that the form is served with no input.""" flow = config_flow.RainMachineFlowHandler() @@ -76,7 +104,6 @@ async def test_step_user(hass): CONF_PASSWORD: "password", CONF_PORT: 8080, CONF_SSL: True, - CONF_SCAN_INTERVAL: 60, } flow = config_flow.RainMachineFlowHandler() @@ -96,6 +123,5 @@ async def test_step_user(hass): CONF_PASSWORD: "password", CONF_PORT: 8080, CONF_SSL: True, - CONF_SCAN_INTERVAL: 60, CONF_ZONE_RUN_TIME: 600, } diff --git a/tests/components/remote/common.py b/tests/components/remote/common.py deleted file mode 100644 index ef9ca91dada..00000000000 --- a/tests/components/remote/common.py +++ /dev/null @@ -1,130 +0,0 @@ -"""Collection of helper methods. - -All containing methods are legacy helpers that should not be used by new -components. Instead call the service directly. -""" -from homeassistant.components.remote import ( - ATTR_ACTIVITY, - ATTR_ALTERNATIVE, - ATTR_COMMAND, - ATTR_COMMAND_TYPE, - ATTR_DELAY_SECS, - ATTR_DEVICE, - ATTR_NUM_REPEATS, - ATTR_TIMEOUT, - DOMAIN, - SERVICE_DELETE_COMMAND, - SERVICE_LEARN_COMMAND, - SERVICE_SEND_COMMAND, -) -from homeassistant.const import ( - ATTR_ENTITY_ID, - ENTITY_MATCH_ALL, - SERVICE_TURN_OFF, - SERVICE_TURN_ON, -) -from homeassistant.loader import bind_hass - - -@bind_hass -def turn_on(hass, activity=None, entity_id=ENTITY_MATCH_ALL): - """Turn all or specified remote on.""" - data = { - key: value - for key, value in [(ATTR_ACTIVITY, activity), (ATTR_ENTITY_ID, entity_id)] - if value is not None - } - hass.services.call(DOMAIN, SERVICE_TURN_ON, data) - - -@bind_hass -def turn_off(hass, activity=None, entity_id=ENTITY_MATCH_ALL): - """Turn all or specified remote off.""" - data = {} - if activity: - data[ATTR_ACTIVITY] = activity - - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) - - -@bind_hass -def send_command( - hass, - command, - entity_id=ENTITY_MATCH_ALL, - device=None, - num_repeats=None, - delay_secs=None, -): - """Send a command to a device.""" - data = {ATTR_COMMAND: command} - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - if device: - data[ATTR_DEVICE] = device - - if num_repeats: - data[ATTR_NUM_REPEATS] = num_repeats - - if delay_secs: - data[ATTR_DELAY_SECS] = delay_secs - - hass.services.call(DOMAIN, SERVICE_SEND_COMMAND, data) - - -@bind_hass -def learn_command( - hass, - entity_id=ENTITY_MATCH_ALL, - device=None, - command=None, - alternative=None, - command_type=None, - timeout=None, -): - """Learn a command from a device.""" - data = {} - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - if device: - data[ATTR_DEVICE] = device - - if command: - data[ATTR_COMMAND] = command - - if command_type: - data[ATTR_COMMAND_TYPE] = command_type - - if alternative: - data[ATTR_ALTERNATIVE] = alternative - - if timeout: - data[ATTR_TIMEOUT] = timeout - - hass.services.call(DOMAIN, SERVICE_LEARN_COMMAND, data) - - -@bind_hass -def delete_command( - hass, - entity_id=ENTITY_MATCH_ALL, - device=None, - command=None, -): - """Delete commands from the database.""" - data = {} - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - if device: - data[ATTR_DEVICE] = device - - if command: - data[ATTR_COMMAND] = command - - hass.services.call(DOMAIN, SERVICE_DELETE_COMMAND, data) diff --git a/tests/components/rest/test_switch.py b/tests/components/rest/test_switch.py index 47eec8e700f..f21eea0e242 100644 --- a/tests/components/rest/test_switch.py +++ b/tests/components/rest/test_switch.py @@ -16,254 +16,239 @@ from homeassistant.const import ( HTTP_OK, ) from homeassistant.helpers.template import Template -from homeassistant.setup import setup_component +from homeassistant.setup import async_setup_component -from tests.common import assert_setup_component, get_test_home_assistant +from tests.common import assert_setup_component + +"""Tests for setting up the REST switch platform.""" + +NAME = "foo" +METHOD = "post" +RESOURCE = "http://localhost/" +STATE_RESOURCE = RESOURCE +HEADERS = {"Content-type": CONTENT_TYPE_JSON} +AUTH = None -class TestRestSwitchSetup: - """Tests for setting up the REST switch platform.""" +async def test_setup_missing_config(hass): + """Test setup with configuration missing required entries.""" + assert not await rest.async_setup_platform(hass, {CONF_PLATFORM: rest.DOMAIN}, None) - def setup_method(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - def teardown_method(self): - """Stop everything that was started.""" - self.hass.stop() +async def test_setup_missing_schema(hass): + """Test setup with resource missing schema.""" + assert not await rest.async_setup_platform( + hass, + {CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "localhost"}, + None, + ) - def test_setup_missing_config(self): - """Test setup with configuration missing required entries.""" - assert not asyncio.run_coroutine_threadsafe( - rest.async_setup_platform(self.hass, {CONF_PLATFORM: rest.DOMAIN}, None), - self.hass.loop, - ).result() - def test_setup_missing_schema(self): - """Test setup with resource missing schema.""" - assert not asyncio.run_coroutine_threadsafe( - rest.async_setup_platform( - self.hass, - {CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "localhost"}, - None, - ), - self.hass.loop, - ).result() +async def test_setup_failed_connect(hass, aioclient_mock): + """Test setup when connection error occurs.""" + aioclient_mock.get("http://localhost", exc=aiohttp.ClientError) + assert not await rest.async_setup_platform( + hass, + {CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "http://localhost"}, + None, + ) - def test_setup_failed_connect(self, aioclient_mock): - """Test setup when connection error occurs.""" - aioclient_mock.get("http://localhost", exc=aiohttp.ClientError) - assert not asyncio.run_coroutine_threadsafe( - rest.async_setup_platform( - self.hass, - {CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "http://localhost"}, - None, - ), - self.hass.loop, - ).result() - def test_setup_timeout(self, aioclient_mock): - """Test setup when connection timeout occurs.""" - aioclient_mock.get("http://localhost", exc=asyncio.TimeoutError()) - assert not asyncio.run_coroutine_threadsafe( - rest.async_setup_platform( - self.hass, - {CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "http://localhost"}, - None, - ), - self.hass.loop, - ).result() +async def test_setup_timeout(hass, aioclient_mock): + """Test setup when connection timeout occurs.""" + aioclient_mock.get("http://localhost", exc=asyncio.TimeoutError()) + assert not await rest.async_setup_platform( + hass, + {CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "http://localhost"}, + None, + ) - def test_setup_minimum(self, aioclient_mock): - """Test setup with minimum configuration.""" - aioclient_mock.get("http://localhost", status=HTTP_OK) - with assert_setup_component(1, SWITCH_DOMAIN): - assert setup_component( - self.hass, - SWITCH_DOMAIN, - { - SWITCH_DOMAIN: { - CONF_PLATFORM: rest.DOMAIN, - CONF_RESOURCE: "http://localhost", - } - }, - ) - assert aioclient_mock.call_count == 1 - def test_setup(self, aioclient_mock): - """Test setup with valid configuration.""" - aioclient_mock.get("http://localhost", status=HTTP_OK) - assert setup_component( - self.hass, +async def test_setup_minimum(hass, aioclient_mock): + """Test setup with minimum configuration.""" + aioclient_mock.get("http://localhost", status=HTTP_OK) + with assert_setup_component(1, SWITCH_DOMAIN): + assert await async_setup_component( + hass, SWITCH_DOMAIN, { SWITCH_DOMAIN: { CONF_PLATFORM: rest.DOMAIN, - CONF_NAME: "foo", CONF_RESOURCE: "http://localhost", - CONF_HEADERS: {"Content-type": CONTENT_TYPE_JSON}, - rest.CONF_BODY_ON: "custom on text", - rest.CONF_BODY_OFF: "custom off text", } }, ) - assert aioclient_mock.call_count == 1 - assert_setup_component(1, SWITCH_DOMAIN) - - def test_setup_with_state_resource(self, aioclient_mock): - """Test setup with valid configuration.""" - aioclient_mock.get("http://localhost", status=HTTP_NOT_FOUND) - aioclient_mock.get("http://localhost/state", status=HTTP_OK) - assert setup_component( - self.hass, - SWITCH_DOMAIN, - { - SWITCH_DOMAIN: { - CONF_PLATFORM: rest.DOMAIN, - CONF_NAME: "foo", - CONF_RESOURCE: "http://localhost", - rest.CONF_STATE_RESOURCE: "http://localhost/state", - CONF_HEADERS: {"Content-type": CONTENT_TYPE_JSON}, - rest.CONF_BODY_ON: "custom on text", - rest.CONF_BODY_OFF: "custom off text", - } - }, - ) - assert aioclient_mock.call_count == 1 - assert_setup_component(1, SWITCH_DOMAIN) + assert aioclient_mock.call_count == 1 -class TestRestSwitch: - """Tests for REST switch platform.""" +async def test_setup(hass, aioclient_mock): + """Test setup with valid configuration.""" + aioclient_mock.get("http://localhost", status=HTTP_OK) + assert await async_setup_component( + hass, + SWITCH_DOMAIN, + { + SWITCH_DOMAIN: { + CONF_PLATFORM: rest.DOMAIN, + CONF_NAME: "foo", + CONF_RESOURCE: "http://localhost", + CONF_HEADERS: {"Content-type": CONTENT_TYPE_JSON}, + rest.CONF_BODY_ON: "custom on text", + rest.CONF_BODY_OFF: "custom off text", + } + }, + ) + assert aioclient_mock.call_count == 1 + assert_setup_component(1, SWITCH_DOMAIN) - def setup_method(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.name = "foo" - self.method = "post" - self.resource = "http://localhost/" - self.state_resource = self.resource - self.headers = {"Content-type": CONTENT_TYPE_JSON} - self.auth = None - self.body_on = Template("on", self.hass) - self.body_off = Template("off", self.hass) - self.switch = rest.RestSwitch( - self.name, - self.resource, - self.state_resource, - self.method, - self.headers, - self.auth, - self.body_on, - self.body_off, - None, - 10, - True, - ) - self.switch.hass = self.hass - def teardown_method(self): - """Stop everything that was started.""" - self.hass.stop() +async def test_setup_with_state_resource(hass, aioclient_mock): + """Test setup with valid configuration.""" + aioclient_mock.get("http://localhost", status=HTTP_NOT_FOUND) + aioclient_mock.get("http://localhost/state", status=HTTP_OK) + assert await async_setup_component( + hass, + SWITCH_DOMAIN, + { + SWITCH_DOMAIN: { + CONF_PLATFORM: rest.DOMAIN, + CONF_NAME: "foo", + CONF_RESOURCE: "http://localhost", + rest.CONF_STATE_RESOURCE: "http://localhost/state", + CONF_HEADERS: {"Content-type": CONTENT_TYPE_JSON}, + rest.CONF_BODY_ON: "custom on text", + rest.CONF_BODY_OFF: "custom off text", + } + }, + ) + assert aioclient_mock.call_count == 1 + assert_setup_component(1, SWITCH_DOMAIN) - def test_name(self): - """Test the name.""" - assert self.name == self.switch.name - def test_is_on_before_update(self): - """Test is_on in initial state.""" - assert self.switch.is_on is None +"""Tests for REST switch platform.""" - def test_turn_on_success(self, aioclient_mock): - """Test turn_on.""" - aioclient_mock.post(self.resource, status=HTTP_OK) - asyncio.run_coroutine_threadsafe( - self.switch.async_turn_on(), self.hass.loop - ).result() - assert self.body_on.template == aioclient_mock.mock_calls[-1][2].decode() - assert self.switch.is_on +def _setup_test_switch(hass): + body_on = Template("on", hass) + body_off = Template("off", hass) + switch = rest.RestSwitch( + NAME, + RESOURCE, + STATE_RESOURCE, + METHOD, + HEADERS, + AUTH, + body_on, + body_off, + None, + 10, + True, + ) + switch.hass = hass + return switch, body_on, body_off - def test_turn_on_status_not_ok(self, aioclient_mock): - """Test turn_on when error status returned.""" - aioclient_mock.post(self.resource, status=HTTP_INTERNAL_SERVER_ERROR) - asyncio.run_coroutine_threadsafe( - self.switch.async_turn_on(), self.hass.loop - ).result() - assert self.body_on.template == aioclient_mock.mock_calls[-1][2].decode() - assert self.switch.is_on is None +def test_name(hass): + """Test the name.""" + switch, body_on, body_off = _setup_test_switch(hass) + assert NAME == switch.name - def test_turn_on_timeout(self, aioclient_mock): - """Test turn_on when timeout occurs.""" - aioclient_mock.post(self.resource, status=HTTP_INTERNAL_SERVER_ERROR) - asyncio.run_coroutine_threadsafe( - self.switch.async_turn_on(), self.hass.loop - ).result() - assert self.switch.is_on is None +def test_is_on_before_update(hass): + """Test is_on in initial state.""" + switch, body_on, body_off = _setup_test_switch(hass) + assert switch.is_on is None - def test_turn_off_success(self, aioclient_mock): - """Test turn_off.""" - aioclient_mock.post(self.resource, status=HTTP_OK) - asyncio.run_coroutine_threadsafe( - self.switch.async_turn_off(), self.hass.loop - ).result() - assert self.body_off.template == aioclient_mock.mock_calls[-1][2].decode() - assert not self.switch.is_on +async def test_turn_on_success(hass, aioclient_mock): + """Test turn_on.""" + aioclient_mock.post(RESOURCE, status=HTTP_OK) + switch, body_on, body_off = _setup_test_switch(hass) + await switch.async_turn_on() - def test_turn_off_status_not_ok(self, aioclient_mock): - """Test turn_off when error status returned.""" - aioclient_mock.post(self.resource, status=HTTP_INTERNAL_SERVER_ERROR) - asyncio.run_coroutine_threadsafe( - self.switch.async_turn_off(), self.hass.loop - ).result() + assert body_on.template == aioclient_mock.mock_calls[-1][2].decode() + assert switch.is_on - assert self.body_off.template == aioclient_mock.mock_calls[-1][2].decode() - assert self.switch.is_on is None - def test_turn_off_timeout(self, aioclient_mock): - """Test turn_off when timeout occurs.""" - aioclient_mock.post(self.resource, exc=asyncio.TimeoutError()) - asyncio.run_coroutine_threadsafe( - self.switch.async_turn_on(), self.hass.loop - ).result() +async def test_turn_on_status_not_ok(hass, aioclient_mock): + """Test turn_on when error status returned.""" + aioclient_mock.post(RESOURCE, status=HTTP_INTERNAL_SERVER_ERROR) + switch, body_on, body_off = _setup_test_switch(hass) + await switch.async_turn_on() - assert self.switch.is_on is None + assert body_on.template == aioclient_mock.mock_calls[-1][2].decode() + assert switch.is_on is None - def test_update_when_on(self, aioclient_mock): - """Test update when switch is on.""" - aioclient_mock.get(self.resource, text=self.body_on.template) - asyncio.run_coroutine_threadsafe( - self.switch.async_update(), self.hass.loop - ).result() - assert self.switch.is_on +async def test_turn_on_timeout(hass, aioclient_mock): + """Test turn_on when timeout occurs.""" + aioclient_mock.post(RESOURCE, status=HTTP_INTERNAL_SERVER_ERROR) + switch, body_on, body_off = _setup_test_switch(hass) + await switch.async_turn_on() - def test_update_when_off(self, aioclient_mock): - """Test update when switch is off.""" - aioclient_mock.get(self.resource, text=self.body_off.template) - asyncio.run_coroutine_threadsafe( - self.switch.async_update(), self.hass.loop - ).result() + assert switch.is_on is None - assert not self.switch.is_on - def test_update_when_unknown(self, aioclient_mock): - """Test update when unknown status returned.""" - aioclient_mock.get(self.resource, text="unknown status") - asyncio.run_coroutine_threadsafe( - self.switch.async_update(), self.hass.loop - ).result() +async def test_turn_off_success(hass, aioclient_mock): + """Test turn_off.""" + aioclient_mock.post(RESOURCE, status=HTTP_OK) + switch, body_on, body_off = _setup_test_switch(hass) + await switch.async_turn_off() - assert self.switch.is_on is None + assert body_off.template == aioclient_mock.mock_calls[-1][2].decode() + assert not switch.is_on - def test_update_timeout(self, aioclient_mock): - """Test update when timeout occurs.""" - aioclient_mock.get(self.resource, exc=asyncio.TimeoutError()) - asyncio.run_coroutine_threadsafe( - self.switch.async_update(), self.hass.loop - ).result() - assert self.switch.is_on is None +async def test_turn_off_status_not_ok(hass, aioclient_mock): + """Test turn_off when error status returned.""" + aioclient_mock.post(RESOURCE, status=HTTP_INTERNAL_SERVER_ERROR) + switch, body_on, body_off = _setup_test_switch(hass) + await switch.async_turn_off() + + assert body_off.template == aioclient_mock.mock_calls[-1][2].decode() + assert switch.is_on is None + + +async def test_turn_off_timeout(hass, aioclient_mock): + """Test turn_off when timeout occurs.""" + aioclient_mock.post(RESOURCE, exc=asyncio.TimeoutError()) + switch, body_on, body_off = _setup_test_switch(hass) + await switch.async_turn_on() + + assert switch.is_on is None + + +async def test_update_when_on(hass, aioclient_mock): + """Test update when switch is on.""" + switch, body_on, body_off = _setup_test_switch(hass) + aioclient_mock.get(RESOURCE, text=body_on.template) + await switch.async_update() + + assert switch.is_on + + +async def test_update_when_off(hass, aioclient_mock): + """Test update when switch is off.""" + switch, body_on, body_off = _setup_test_switch(hass) + aioclient_mock.get(RESOURCE, text=body_off.template) + await switch.async_update() + + assert not switch.is_on + + +async def test_update_when_unknown(hass, aioclient_mock): + """Test update when unknown status returned.""" + aioclient_mock.get(RESOURCE, text="unknown status") + switch, body_on, body_off = _setup_test_switch(hass) + await switch.async_update() + + assert switch.is_on is None + + +async def test_update_timeout(hass, aioclient_mock): + """Test update when timeout occurs.""" + aioclient_mock.get(RESOURCE, exc=asyncio.TimeoutError()) + switch, body_on, body_off = _setup_test_switch(hass) + await switch.async_update() + + assert switch.is_on is None diff --git a/tests/components/rflink/conftest.py b/tests/components/rflink/conftest.py new file mode 100644 index 00000000000..f33c8ab89db --- /dev/null +++ b/tests/components/rflink/conftest.py @@ -0,0 +1,2 @@ +"""rflink conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/rfxtrx/conftest.py b/tests/components/rfxtrx/conftest.py index 82c4bd7aacd..563fb362e5a 100644 --- a/tests/components/rfxtrx/conftest.py +++ b/tests/components/rfxtrx/conftest.py @@ -9,6 +9,7 @@ from homeassistant.util.dt import utcnow from tests.async_mock import patch from tests.common import MockConfigEntry, async_fire_time_changed +from tests.components.light.conftest import mock_light_profiles # noqa def create_rfx_test_cfg(device="abcd", automatic_add=False, devices=None): diff --git a/tests/components/ring/conftest.py b/tests/components/ring/conftest.py index 5df85662ac8..f2e05189dea 100644 --- a/tests/components/ring/conftest.py +++ b/tests/components/ring/conftest.py @@ -5,6 +5,7 @@ import pytest import requests_mock from tests.common import load_fixture +from tests.components.light.conftest import mock_light_profiles # noqa @pytest.fixture(name="requests_mock") diff --git a/tests/components/ring/test_config_flow.py b/tests/components/ring/test_config_flow.py index 1be0a05fc5e..fc2b490f560 100644 --- a/tests/components/ring/test_config_flow.py +++ b/tests/components/ring/test_config_flow.py @@ -30,6 +30,7 @@ async def test_form(hass): result["flow_id"], {"username": "hello@home-assistant.io", "password": "test-password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "hello@home-assistant.io" @@ -37,7 +38,6 @@ async def test_form(hass): "username": "hello@home-assistant.io", "token": {"access_token": "mock-token"}, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/risco/test_binary_sensor.py b/tests/components/risco/test_binary_sensor.py index 9aa56f64e51..50b9c43c5c3 100644 --- a/tests/components/risco/test_binary_sensor.py +++ b/tests/components/risco/test_binary_sensor.py @@ -1,51 +1,19 @@ """Tests for the Risco binary sensors.""" -import pytest - from homeassistant.components.risco import CannotConnectError, UnauthorizedError from homeassistant.components.risco.const import DOMAIN from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.helpers.entity_component import async_update_entity from .util import TEST_CONFIG, TEST_SITE_UUID, setup_risco +from .util import two_zone_alarm # noqa: F401 -from tests.async_mock import MagicMock, PropertyMock, patch +from tests.async_mock import PropertyMock, patch from tests.common import MockConfigEntry FIRST_ENTITY_ID = "binary_sensor.zone_0" SECOND_ENTITY_ID = "binary_sensor.zone_1" -def _zone_mock(): - return MagicMock( - triggered=False, - bypassed=False, - ) - - -@pytest.fixture -def two_zone_alarm(): - """Fixture to mock alarm with two zones.""" - zone_mocks = {0: _zone_mock(), 1: _zone_mock()} - alarm_mock = MagicMock() - with patch.object( - zone_mocks[0], "id", new_callable=PropertyMock(return_value=0) - ), patch.object( - zone_mocks[0], "name", new_callable=PropertyMock(return_value="Zone 0") - ), patch.object( - zone_mocks[1], "id", new_callable=PropertyMock(return_value=1) - ), patch.object( - zone_mocks[1], "name", new_callable=PropertyMock(return_value="Zone 1") - ), patch.object( - alarm_mock, - "zones", - new_callable=PropertyMock(return_value=zone_mocks), - ), patch( - "homeassistant.components.risco.RiscoAPI.get_state", - return_value=alarm_mock, - ): - yield alarm_mock - - async def test_cannot_connect(hass): """Test connection error.""" @@ -78,7 +46,7 @@ async def test_unauthorized(hass): assert not registry.async_is_registered(SECOND_ENTITY_ID) -async def test_setup(hass, two_zone_alarm): +async def test_setup(hass, two_zone_alarm): # noqa: F811 """Test entity setup.""" registry = await hass.helpers.entity_registry.async_get_registry() @@ -116,9 +84,10 @@ async def _check_state(hass, alarm, triggered, bypassed, entity_id, zone_id): expected_triggered = STATE_ON if triggered else STATE_OFF assert hass.states.get(entity_id).state == expected_triggered assert hass.states.get(entity_id).attributes["bypassed"] == bypassed + assert hass.states.get(entity_id).attributes["zone_id"] == zone_id -async def test_states(hass, two_zone_alarm): +async def test_states(hass, two_zone_alarm): # noqa: F811 """Test the various alarm states.""" await setup_risco(hass) @@ -132,7 +101,7 @@ async def test_states(hass, two_zone_alarm): await _check_state(hass, two_zone_alarm, False, False, SECOND_ENTITY_ID, 1) -async def test_bypass(hass, two_zone_alarm): +async def test_bypass(hass, two_zone_alarm): # noqa: F811 """Test bypassing a zone.""" await setup_risco(hass) with patch("homeassistant.components.risco.RiscoAPI.bypass_zone") as mock: @@ -145,7 +114,7 @@ async def test_bypass(hass, two_zone_alarm): mock.assert_awaited_once_with(0, True) -async def test_unbypass(hass, two_zone_alarm): +async def test_unbypass(hass, two_zone_alarm): # noqa: F811 """Test unbypassing a zone.""" await setup_risco(hass) with patch("homeassistant.components.risco.RiscoAPI.bypass_zone") as mock: diff --git a/tests/components/risco/test_config_flow.py b/tests/components/risco/test_config_flow.py index 47fd0927cb1..ba14a52553e 100644 --- a/tests/components/risco/test_config_flow.py +++ b/tests/components/risco/test_config_flow.py @@ -66,11 +66,11 @@ async def test_form(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], TEST_DATA ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == TEST_SITE_NAME assert result2["data"] == TEST_DATA - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 mock_close.assert_awaited_once() diff --git a/tests/components/risco/test_sensor.py b/tests/components/risco/test_sensor.py index cc76c0b970b..acb92088478 100644 --- a/tests/components/risco/test_sensor.py +++ b/tests/components/risco/test_sensor.py @@ -1,6 +1,4 @@ """Tests for the Risco event sensors.""" -import pytest - from homeassistant.components.risco import ( LAST_EVENT_TIMESTAMP_KEY, CannotConnectError, @@ -9,6 +7,7 @@ from homeassistant.components.risco import ( from homeassistant.components.risco.const import DOMAIN, EVENTS_COORDINATOR from .util import TEST_CONFIG, setup_risco +from .util import two_zone_alarm # noqa: F401 from tests.async_mock import MagicMock, patch from tests.common import MockConfigEntry @@ -60,7 +59,7 @@ TEST_EVENTS = [ name="Alarm is on", text="Yes it is.", partition_id=0, - zone_id=12, + zone_id=1, user_id=None, group=None, priority=0, @@ -106,16 +105,6 @@ CATEGORIES_TO_EVENTS = { } -@pytest.fixture -def emptry_alarm(): - """Fixture to mock an empty alarm.""" - with patch( - "homeassistant.components.risco.RiscoAPI.get_state", - return_value=MagicMock(paritions={}, zones={}), - ): - yield - - async def test_cannot_connect(hass): """Test connection error.""" @@ -151,23 +140,29 @@ async def test_unauthorized(hass): def _check_state(hass, category, entity_id): - event = TEST_EVENTS[CATEGORIES_TO_EVENTS[category]] - assert hass.states.get(entity_id).state == event.time - assert hass.states.get(entity_id).attributes["category_id"] == event.category_id - assert hass.states.get(entity_id).attributes["category_name"] == event.category_name - assert hass.states.get(entity_id).attributes["type_id"] == event.type_id - assert hass.states.get(entity_id).attributes["type_name"] == event.type_name - assert hass.states.get(entity_id).attributes["name"] == event.name - assert hass.states.get(entity_id).attributes["text"] == event.text - assert hass.states.get(entity_id).attributes["partition_id"] == event.partition_id - assert hass.states.get(entity_id).attributes["zone_id"] == event.zone_id - assert hass.states.get(entity_id).attributes["user_id"] == event.user_id - assert hass.states.get(entity_id).attributes["group"] == event.group - assert hass.states.get(entity_id).attributes["priority"] == event.priority - assert hass.states.get(entity_id).attributes["raw"] == event.raw + event_index = CATEGORIES_TO_EVENTS[category] + event = TEST_EVENTS[event_index] + state = hass.states.get(entity_id) + assert state.state == event.time + assert state.attributes["category_id"] == event.category_id + assert state.attributes["category_name"] == event.category_name + assert state.attributes["type_id"] == event.type_id + assert state.attributes["type_name"] == event.type_name + assert state.attributes["name"] == event.name + assert state.attributes["text"] == event.text + assert state.attributes["partition_id"] == event.partition_id + assert state.attributes["zone_id"] == event.zone_id + assert state.attributes["user_id"] == event.user_id + assert state.attributes["group"] == event.group + assert state.attributes["priority"] == event.priority + assert state.attributes["raw"] == event.raw + if event_index == 2: + assert state.attributes["zone_entity_id"] == "binary_sensor.zone_1" + else: + assert "zone_entity_id" not in state.attributes -async def test_setup(hass, emptry_alarm): +async def test_setup(hass, two_zone_alarm): # noqa: F811 """Test entity setup.""" registry = await hass.helpers.entity_registry.async_get_registry() diff --git a/tests/components/risco/util.py b/tests/components/risco/util.py index a60be70e861..704c12fb846 100644 --- a/tests/components/risco/util.py +++ b/tests/components/risco/util.py @@ -1,8 +1,10 @@ """Utilities for Risco tests.""" +from pytest import fixture + from homeassistant.components.risco.const import DOMAIN from homeassistant.const import CONF_PASSWORD, CONF_PIN, CONF_USERNAME -from tests.async_mock import PropertyMock, patch +from tests.async_mock import MagicMock, PropertyMock, patch from tests.common import MockConfigEntry TEST_CONFIG = { @@ -35,3 +37,34 @@ async def setup_risco(hass, options={}): await hass.async_block_till_done() return config_entry + + +def _zone_mock(): + return MagicMock( + triggered=False, + bypassed=False, + ) + + +@fixture +def two_zone_alarm(): + """Fixture to mock alarm with two zones.""" + zone_mocks = {0: _zone_mock(), 1: _zone_mock()} + alarm_mock = MagicMock() + with patch.object( + zone_mocks[0], "id", new_callable=PropertyMock(return_value=0) + ), patch.object( + zone_mocks[0], "name", new_callable=PropertyMock(return_value="Zone 0") + ), patch.object( + zone_mocks[1], "id", new_callable=PropertyMock(return_value=1) + ), patch.object( + zone_mocks[1], "name", new_callable=PropertyMock(return_value="Zone 1") + ), patch.object( + alarm_mock, + "zones", + new_callable=PropertyMock(return_value=zone_mocks), + ), patch( + "homeassistant.components.risco.RiscoAPI.get_state", + return_value=alarm_mock, + ): + yield alarm_mock diff --git a/tests/components/roku/test_config_flow.py b/tests/components/roku/test_config_flow.py index 58acc7a6bdf..a3cda6afa69 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 @@ -76,6 +76,7 @@ async def test_form( result = await hass.config_entries.flow.async_configure( flow_id=result["flow_id"], user_input=user_input ) + await hass.async_block_till_done() assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == UPNP_FRIENDLY_NAME @@ -83,7 +84,6 @@ async def test_form( assert result["data"] assert result["data"][CONF_HOST] == HOST - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -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 - ) - - assert result["type"] == RESULT_TYPE_CREATE_ENTRY - assert result["title"] == UPNP_FRIENDLY_NAME - - assert result["data"] - assert result["data"][CONF_HOST] == HOST - - await hass.async_block_till_done() - 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: @@ -216,6 +188,7 @@ async def test_ssdp_discovery( result = await hass.config_entries.flow.async_configure( flow_id=result["flow_id"], user_input={} ) + await hass.async_block_till_done() assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == UPNP_FRIENDLY_NAME @@ -224,6 +197,5 @@ async def test_ssdp_discovery( assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_NAME] == UPNP_FRIENDLY_NAME - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/roku/test_media_player.py b/tests/components/roku/test_media_player.py index b4ce1811c91..23dd9dbc6c8 100644 --- a/tests/components/roku/test_media_player.py +++ b/tests/components/roku/test_media_player.py @@ -539,18 +539,14 @@ async def test_media_browse(hass, aioclient_mock, hass_ws_client): assert msg["result"]["children"][0]["media_content_type"] == MEDIA_TYPE_APP assert msg["result"]["children"][0]["media_content_id"] == "tvinput.hdmi2" assert ( - msg["result"]["children"][0]["thumbnail"] - == "http://192.168.1.161:8060/query/icon/tvinput.hdmi2" + "/browse_media/app/tvinput.hdmi2" in msg["result"]["children"][0]["thumbnail"] ) assert msg["result"]["children"][0]["can_play"] assert msg["result"]["children"][3]["title"] == "Roku Channel Store" assert msg["result"]["children"][3]["media_content_type"] == MEDIA_TYPE_APP assert msg["result"]["children"][3]["media_content_id"] == "11" - assert ( - msg["result"]["children"][3]["thumbnail"] - == "http://192.168.1.161:8060/query/icon/11" - ) + assert "/browse_media/app/11" in msg["result"]["children"][3]["thumbnail"] assert msg["result"]["children"][3]["can_play"] # test channels diff --git a/tests/components/roomba/test_config_flow.py b/tests/components/roomba/test_config_flow.py index b2ad3a74235..d2af07070bb 100644 --- a/tests/components/roomba/test_config_flow.py +++ b/tests/components/roomba/test_config_flow.py @@ -62,6 +62,7 @@ async def test_form(hass): result["flow_id"], VALID_CONFIG, ) + await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["title"] == "myroomba" @@ -74,7 +75,6 @@ async def test_form(hass): CONF_HOST: "1.2.3.4", CONF_PASSWORD: "password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -126,6 +126,7 @@ async def test_form_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data=VALID_YAML_CONFIG.copy(), ) + await hass.async_block_till_done() assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["result"].unique_id == "blid" @@ -138,7 +139,6 @@ async def test_form_import(hass): CONF_PASSWORD: "password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/roon/test_config_flow.py b/tests/components/roon/test_config_flow.py index aae655fb9c5..7ffac08d9f6 100644 --- a/tests/components/roon/test_config_flow.py +++ b/tests/components/roon/test_config_flow.py @@ -51,11 +51,11 @@ async def test_form_and_auth(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={} ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Roon Labs Music Player" assert result2["data"] == {"host": "1.1.1.1", "api_key": "good_token"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -136,11 +136,11 @@ async def test_form_host_already_exists(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={} ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Roon Labs Music Player" assert result2["data"] == {"host": "1.1.1.1", "api_key": "good_token"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 2 diff --git a/tests/components/ruckus_unleashed/test_config_flow.py b/tests/components/ruckus_unleashed/test_config_flow.py index 8348ec4f2a8..39112dd44aa 100644 --- a/tests/components/ruckus_unleashed/test_config_flow.py +++ b/tests/components/ruckus_unleashed/test_config_flow.py @@ -39,11 +39,11 @@ async def test_form(hass): result["flow_id"], CONFIG, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == DEFAULT_TITLE assert result2["data"] == CONFIG - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/sense/test_config_flow.py b/tests/components/sense/test_config_flow.py index 4cda15f7303..44bd9c7265c 100644 --- a/tests/components/sense/test_config_flow.py +++ b/tests/components/sense/test_config_flow.py @@ -26,6 +26,7 @@ async def test_form(hass): result["flow_id"], {"timeout": "6", "email": "test-email", "password": "test-password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "test-email" @@ -34,7 +35,6 @@ async def test_form(hass): "email": "test-email", "password": "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/sharkiq/test_vacuum.py b/tests/components/sharkiq/test_vacuum.py index 3b40011b8e6..c548b59f5ba 100644 --- a/tests/components/sharkiq/test_vacuum.py +++ b/tests/components/sharkiq/test_vacuum.py @@ -4,7 +4,7 @@ import enum from typing import Any, Iterable, List, Optional import pytest -from sharkiqpy import AylaApi, SharkIqAuthError, SharkIqVacuum +from sharkiqpy import AylaApi, SharkIqAuthError, SharkIqNotAuthedError, SharkIqVacuum from homeassistant.components.homeassistant import SERVICE_UPDATE_ENTITY from homeassistant.components.sharkiq import DOMAIN @@ -217,9 +217,11 @@ async def test_locate(hass): [ (None, True), (SharkIqAuthError, False), + (SharkIqNotAuthedError, False), (RuntimeError, False), ], ) +@patch("sharkiqpy.ayla_api.AylaApi", MockAyla) async def test_coordinator_updates( hass: HomeAssistant, side_effect: Optional[Exception], success: bool ) -> None: diff --git a/tests/components/shelly/test_config_flow.py b/tests/components/shelly/test_config_flow.py index 280688a0618..1796847bd74 100644 --- a/tests/components/shelly/test_config_flow.py +++ b/tests/components/shelly/test_config_flow.py @@ -43,7 +43,6 @@ async def test_form(hass): "aioshelly.Device.create", new=AsyncMock( return_value=Mock( - shutdown=AsyncMock(), settings=MOCK_SETTINGS, ) ), @@ -57,13 +56,13 @@ async def test_form(hass): result["flow_id"], {"host": "1.1.1.1"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Test name" assert result2["data"] == { "host": "1.1.1.1", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -88,7 +87,6 @@ async def test_title_without_name_and_prefix(hass): "aioshelly.Device.create", new=AsyncMock( return_value=Mock( - shutdown=AsyncMock(), settings=settings, ) ), @@ -102,13 +100,13 @@ async def test_title_without_name_and_prefix(hass): result["flow_id"], {"host": "1.1.1.1"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "shelly1pm-12345" assert result2["data"] == { "host": "1.1.1.1", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -137,7 +135,6 @@ async def test_form_auth(hass): "aioshelly.Device.create", new=AsyncMock( return_value=Mock( - shutdown=AsyncMock(), settings=MOCK_SETTINGS, ) ), @@ -151,6 +148,7 @@ async def test_form_auth(hass): result2["flow_id"], {"username": "test username", "password": "test password"}, ) + await hass.async_block_till_done() assert result3["type"] == "create_entry" assert result3["title"] == "Test name" @@ -159,7 +157,6 @@ async def test_form_auth(hass): "username": "test username", "password": "test password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -309,7 +306,6 @@ async def test_zeroconf(hass): "aioshelly.Device.create", new=AsyncMock( return_value=Mock( - shutdown=AsyncMock(), settings=MOCK_SETTINGS, ) ), @@ -323,13 +319,13 @@ async def test_zeroconf(hass): result["flow_id"], {}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Test name" assert result2["data"] == { "host": "1.1.1.1", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -466,7 +462,6 @@ async def test_zeroconf_require_auth(hass): "aioshelly.Device.create", new=AsyncMock( return_value=Mock( - shutdown=AsyncMock(), settings=MOCK_SETTINGS, ) ), @@ -480,6 +475,7 @@ async def test_zeroconf_require_auth(hass): result2["flow_id"], {"username": "test username", "password": "test password"}, ) + await hass.async_block_till_done() assert result3["type"] == "create_entry" assert result3["title"] == "Test name" @@ -488,7 +484,6 @@ async def test_zeroconf_require_auth(hass): "username": "test username", "password": "test password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/smart_meter_texas/test_config_flow.py b/tests/components/smart_meter_texas/test_config_flow.py index 729cb0a90b2..4908a50e57d 100644 --- a/tests/components/smart_meter_texas/test_config_flow.py +++ b/tests/components/smart_meter_texas/test_config_flow.py @@ -36,11 +36,11 @@ async def test_form(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], TEST_LOGIN ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == TEST_LOGIN[CONF_USERNAME] assert result2["data"] == TEST_LOGIN - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/smarthab/test_config_flow.py b/tests/components/smarthab/test_config_flow.py index d15fe58999e..6b8c58b1f70 100644 --- a/tests/components/smarthab/test_config_flow.py +++ b/tests/components/smarthab/test_config_flow.py @@ -28,6 +28,7 @@ async def test_form(hass): result["flow_id"], {CONF_EMAIL: "mock@example.com", CONF_PASSWORD: "test-password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "mock@example.com" @@ -35,7 +36,6 @@ async def test_form(hass): CONF_EMAIL: "mock@example.com", CONF_PASSWORD: "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -115,6 +115,7 @@ async def test_import(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=imported_conf ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "mock@example.com" @@ -122,6 +123,5 @@ async def test_import(hass): CONF_EMAIL: "mock@example.com", CONF_PASSWORD: "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/smartthings/conftest.py b/tests/components/smartthings/conftest.py index ecab269c1a2..8588c81654e 100644 --- a/tests/components/smartthings/conftest.py +++ b/tests/components/smartthings/conftest.py @@ -47,6 +47,7 @@ from homeassistant.setup import async_setup_component from tests.async_mock import Mock, patch from tests.common import MockConfigEntry +from tests.components.light.conftest import mock_light_profiles # noqa COMPONENT_PREFIX = "homeassistant.components.smartthings." diff --git a/tests/components/solarlog/test_config_flow.py b/tests/components/solarlog/test_config_flow.py index 9cf0e2932ec..8266adfd417 100644 --- a/tests/components/solarlog/test_config_flow.py +++ b/tests/components/solarlog/test_config_flow.py @@ -34,11 +34,11 @@ async def test_form(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], {"host": HOST, "name": NAME} ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "solarlog_test_1_2_3" assert result2["data"] == {"host": "http://1.1.1.1"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/spider/test_config_flow.py b/tests/components/spider/test_config_flow.py index 3bf7dd790b2..ca1b37434d1 100644 --- a/tests/components/spider/test_config_flow.py +++ b/tests/components/spider/test_config_flow.py @@ -42,6 +42,7 @@ async def test_user(hass, spider): result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input=SPIDER_USER_DATA ) + await hass.async_block_till_done() assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["title"] == DOMAIN @@ -49,7 +50,6 @@ async def test_user(hass, spider): assert result["data"][CONF_PASSWORD] == PASSWORD assert not result["result"].unique_id - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -69,6 +69,7 @@ async def test_import(hass, spider): context={"source": config_entries.SOURCE_IMPORT}, data=SPIDER_USER_DATA, ) + await hass.async_block_till_done() assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["title"] == DOMAIN @@ -76,7 +77,6 @@ async def test_import(hass, spider): assert result["data"][CONF_PASSWORD] == PASSWORD assert not result["result"].unique_id - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/ssdp/test_init.py b/tests/components/ssdp/test_init.py index b6c8266b5da..008995cd78d 100644 --- a/tests/components/ssdp/test_init.py +++ b/tests/components/ssdp/test_init.py @@ -10,7 +10,7 @@ from homeassistant.components import ssdp from tests.common import mock_coro -async def test_scan_match_st(hass): +async def test_scan_match_st(hass, caplog): """Test matching based on ST.""" scanner = ssdp.Scanner(hass, {"mock-domain": [{"st": "mock-st"}]}) @@ -38,6 +38,7 @@ async def test_scan_match_st(hass): ssdp.ATTR_SSDP_SERVER: "mock-server", ssdp.ATTR_SSDP_EXT: "", } + assert "Failed to fetch ssdp data" not in caplog.text @pytest.mark.parametrize( diff --git a/tests/components/stream/test_hls.py b/tests/components/stream/test_hls.py index 863513c8157..16d2d724f22 100644 --- a/tests/components/stream/test_hls.py +++ b/tests/components/stream/test_hls.py @@ -147,7 +147,9 @@ async def test_stream_keepalive(hass): with patch("av.open") as av_open, patch( "homeassistant.components.stream.worker.time" - ) as mock_time: + ) as mock_time, patch( + "homeassistant.components.stream.worker.STREAM_RESTART_INCREMENT", 0 + ): av_open.side_effect = av.error.InvalidDataError(-2, "error") mock_time.time.side_effect = time_side_effect # Request stream diff --git a/tests/components/switch/conftest.py b/tests/components/switch/conftest.py new file mode 100644 index 00000000000..d69757a9b1b --- /dev/null +++ b/tests/components/switch/conftest.py @@ -0,0 +1,2 @@ +"""switch conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/synology_dsm/test_config_flow.py b/tests/components/synology_dsm/test_config_flow.py index fd060ce3529..f895ee7e7dc 100644 --- a/tests/components/synology_dsm/test_config_flow.py +++ b/tests/components/synology_dsm/test_config_flow.py @@ -10,15 +10,18 @@ from synology_dsm.exceptions import ( from homeassistant import data_entry_flow, setup from homeassistant.components import ssdp +from homeassistant.components.synology_dsm import _async_setup_services from homeassistant.components.synology_dsm.config_flow import CONF_OTP_CODE from homeassistant.components.synology_dsm.const import ( CONF_VOLUMES, DEFAULT_PORT, DEFAULT_PORT_SSL, DEFAULT_SCAN_INTERVAL, - DEFAULT_SSL, DEFAULT_TIMEOUT, + DEFAULT_USE_SSL, + DEFAULT_VERIFY_SSL, DOMAIN, + SERVICES, ) from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_SSDP, SOURCE_USER from homeassistant.const import ( @@ -31,6 +34,7 @@ from homeassistant.const import ( CONF_SSL, CONF_TIMEOUT, CONF_USERNAME, + CONF_VERIFY_SSL, ) from homeassistant.helpers.typing import HomeAssistantType @@ -42,7 +46,8 @@ SERIAL = "mySerial" HOST_2 = "nas.worldwide.me" SERIAL_2 = "mySerial2" PORT = 1234 -SSL = True +USE_SSL = True +VERIFY_SSL = False USERNAME = "Home_Assistant" PASSWORD = "password" DEVICE_TOKEN = "Dév!cè_T0k€ñ" @@ -124,7 +129,8 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): data={ CONF_HOST: HOST, CONF_PORT: PORT, - CONF_SSL: SSL, + CONF_SSL: USE_SSL, + CONF_VERIFY_SSL: VERIFY_SSL, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD, }, @@ -134,7 +140,8 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): 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_SSL] == USE_SSL + assert result["data"][CONF_VERIFY_SSL] == VERIFY_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_MAC] == MACS @@ -150,6 +157,7 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): data={ CONF_HOST: HOST, CONF_SSL: False, + CONF_VERIFY_SSL: VERIFY_SSL, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD, }, @@ -160,6 +168,7 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_PORT] == DEFAULT_PORT assert not result["data"][CONF_SSL] + assert result["data"][CONF_VERIFY_SSL] == VERIFY_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_MAC] == MACS @@ -201,7 +210,8 @@ async def test_user_2sa(hass: HomeAssistantType, service_2sa: MagicMock): assert result["title"] == HOST assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_PORT] == DEFAULT_PORT_SSL - assert result["data"][CONF_SSL] == DEFAULT_SSL + assert result["data"][CONF_SSL] == DEFAULT_USE_SSL + assert result["data"][CONF_VERIFY_SSL] == DEFAULT_VERIFY_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_MAC] == MACS @@ -225,7 +235,8 @@ async def test_user_vdsm(hass: HomeAssistantType, service_vdsm: MagicMock): data={ CONF_HOST: HOST, CONF_PORT: PORT, - CONF_SSL: SSL, + CONF_SSL: USE_SSL, + CONF_VERIFY_SSL: VERIFY_SSL, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD, }, @@ -235,7 +246,8 @@ async def test_user_vdsm(hass: HomeAssistantType, service_vdsm: MagicMock): 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_SSL] == USE_SSL + assert result["data"][CONF_VERIFY_SSL] == VERIFY_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_MAC] == MACS @@ -257,7 +269,8 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): assert result["title"] == HOST assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_PORT] == DEFAULT_PORT_SSL - assert result["data"][CONF_SSL] == DEFAULT_SSL + assert result["data"][CONF_SSL] == DEFAULT_USE_SSL + assert result["data"][CONF_VERIFY_SSL] == DEFAULT_VERIFY_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_MAC] == MACS @@ -273,7 +286,8 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): data={ CONF_HOST: HOST_2, CONF_PORT: PORT, - CONF_SSL: SSL, + CONF_SSL: USE_SSL, + CONF_VERIFY_SSL: VERIFY_SSL, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD, CONF_DISKS: ["sda", "sdb", "sdc"], @@ -285,7 +299,8 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): assert result["title"] == HOST_2 assert result["data"][CONF_HOST] == HOST_2 assert result["data"][CONF_PORT] == PORT - assert result["data"][CONF_SSL] == SSL + assert result["data"][CONF_SSL] == USE_SSL + assert result["data"][CONF_VERIFY_SSL] == VERIFY_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_MAC] == MACS @@ -434,7 +449,8 @@ async def test_form_ssdp(hass: HomeAssistantType, service: MagicMock): assert result["title"] == "192.168.1.5" assert result["data"][CONF_HOST] == "192.168.1.5" assert result["data"][CONF_PORT] == 5001 - assert result["data"][CONF_SSL] == DEFAULT_SSL + assert result["data"][CONF_SSL] == DEFAULT_USE_SSL + assert result["data"][CONF_VERIFY_SSL] == DEFAULT_VERIFY_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_MAC] == MACS @@ -482,3 +498,23 @@ async def test_options_flow(hass: HomeAssistantType, service: MagicMock): assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert config_entry.options[CONF_SCAN_INTERVAL] == 2 assert config_entry.options[CONF_TIMEOUT] == 30 + + +async def test_services_registered(hass: HomeAssistantType): + """Test if all services are registered.""" + with patch( + "homeassistant.core.ServiceRegistry.async_register", return_value=Mock(True) + ) as async_register: + await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={ + CONF_HOST: HOST, + CONF_PORT: PORT, + CONF_SSL: USE_SSL, + CONF_USERNAME: USERNAME, + CONF_PASSWORD: PASSWORD, + }, + ) + await _async_setup_services(hass) + assert async_register.call_count == len(SERVICES) diff --git a/tests/components/system_health/test_init.py b/tests/components/system_health/test_init.py index bfed115eee2..28f54c81c42 100644 --- a/tests/components/system_health/test_init.py +++ b/tests/components/system_health/test_init.py @@ -1,38 +1,67 @@ """Tests for the system health component init.""" import asyncio -from unittest.mock import Mock -import pytest +from aiohttp.client_exceptions import ClientError +from homeassistant.components import system_health from homeassistant.setup import async_setup_component -from tests.common import mock_coro +from tests.async_mock import AsyncMock, Mock, patch +from tests.common import get_system_health_info, mock_platform -@pytest.fixture -def mock_system_info(hass): - """Mock system info.""" - hass.helpers.system_info.async_get_system_info = Mock( - return_value=mock_coro({"hello": True}) - ) - - -async def test_info_endpoint_return_info(hass, hass_ws_client, mock_system_info): - """Test that the info endpoint works.""" - assert await async_setup_component(hass, "system_health", {}) +async def gather_system_health_info(hass, hass_ws_client): + """Gather all info.""" client = await hass_ws_client(hass) resp = await client.send_json({"id": 6, "type": "system_health/info"}) + + # Confirm subscription resp = await client.receive_json() assert resp["success"] - data = resp["result"] + + data = {} + + # Get initial data + resp = await client.receive_json() + assert resp["event"]["type"] == "initial" + data = resp["event"]["data"] + + while True: + resp = await client.receive_json() + event = resp["event"] + + if event["type"] == "finish": + break + + assert event["type"] == "update" + + if event["success"]: + data[event["domain"]]["info"][event["key"]] = event["data"] + else: + data[event["domain"]]["info"][event["key"]] = event["error"] + + return data + + +async def test_info_endpoint_return_info(hass, hass_ws_client): + """Test that the info endpoint works.""" + assert await async_setup_component(hass, "homeassistant", {}) + + with patch( + "homeassistant.components.homeassistant.system_health.system_health_info", + return_value={"hello": True}, + ): + assert await async_setup_component(hass, "system_health", {}) + + data = await gather_system_health_info(hass, hass_ws_client) assert len(data) == 1 data = data["homeassistant"] - assert data == {"hello": True} + assert data == {"info": {"hello": True}} -async def test_info_endpoint_register_callback(hass, hass_ws_client, mock_system_info): +async def test_info_endpoint_register_callback(hass, hass_ws_client): """Test that the info endpoint allows registering callbacks.""" async def mock_info(hass): @@ -40,21 +69,17 @@ async def test_info_endpoint_register_callback(hass, hass_ws_client, mock_system hass.components.system_health.async_register_info("lovelace", mock_info) assert await async_setup_component(hass, "system_health", {}) - client = await hass_ws_client(hass) + data = await gather_system_health_info(hass, hass_ws_client) - resp = await client.send_json({"id": 6, "type": "system_health/info"}) - resp = await client.receive_json() - assert resp["success"] - data = resp["result"] - - assert len(data) == 2 + assert len(data) == 1 data = data["lovelace"] - assert data == {"storage": "YAML"} + assert data == {"info": {"storage": "YAML"}} + + # Test our test helper works + assert await get_system_health_info(hass, "lovelace") == {"storage": "YAML"} -async def test_info_endpoint_register_callback_timeout( - hass, hass_ws_client, mock_system_info -): +async def test_info_endpoint_register_callback_timeout(hass, hass_ws_client): """Test that the info endpoint timing out.""" async def mock_info(hass): @@ -62,21 +87,14 @@ async def test_info_endpoint_register_callback_timeout( hass.components.system_health.async_register_info("lovelace", mock_info) assert await async_setup_component(hass, "system_health", {}) - client = await hass_ws_client(hass) + data = await gather_system_health_info(hass, hass_ws_client) - resp = await client.send_json({"id": 6, "type": "system_health/info"}) - resp = await client.receive_json() - assert resp["success"] - data = resp["result"] - - assert len(data) == 2 + assert len(data) == 1 data = data["lovelace"] - assert data == {"error": "Fetching info timed out"} + assert data == {"info": {"error": {"type": "failed", "error": "timeout"}}} -async def test_info_endpoint_register_callback_exc( - hass, hass_ws_client, mock_system_info -): +async def test_info_endpoint_register_callback_exc(hass, hass_ws_client): """Test that the info endpoint requires auth.""" async def mock_info(hass): @@ -84,13 +102,58 @@ async def test_info_endpoint_register_callback_exc( hass.components.system_health.async_register_info("lovelace", mock_info) assert await async_setup_component(hass, "system_health", {}) - client = await hass_ws_client(hass) + data = await gather_system_health_info(hass, hass_ws_client) - resp = await client.send_json({"id": 6, "type": "system_health/info"}) - resp = await client.receive_json() - assert resp["success"] - data = resp["result"] - - assert len(data) == 2 + assert len(data) == 1 data = data["lovelace"] - assert data == {"error": "TEST ERROR"} + assert data == {"info": {"error": {"type": "failed", "error": "unknown"}}} + + +async def test_platform_loading(hass, hass_ws_client, aioclient_mock): + """Test registering via platform.""" + aioclient_mock.get("http://example.com/status", text="") + aioclient_mock.get("http://example.com/status_fail", exc=ClientError) + hass.config.components.add("fake_integration") + mock_platform( + hass, + "fake_integration.system_health", + Mock( + async_register=lambda hass, register: register.async_register_info( + AsyncMock( + return_value={ + "hello": "info", + "server_reachable": system_health.async_check_can_reach_url( + hass, "http://example.com/status" + ), + "server_fail_reachable": system_health.async_check_can_reach_url( + hass, + "http://example.com/status_fail", + more_info="http://more-info-url.com", + ), + "async_crash": AsyncMock(side_effect=ValueError)(), + } + ), + "/config/fake_integration", + ) + ), + ) + + assert await async_setup_component(hass, "system_health", {}) + data = await gather_system_health_info(hass, hass_ws_client) + + assert data["fake_integration"] == { + "info": { + "hello": "info", + "server_reachable": "ok", + "server_fail_reachable": { + "type": "failed", + "error": "unreachable", + "more_info": "http://more-info-url.com", + }, + "async_crash": { + "type": "failed", + "error": "unknown", + }, + }, + "manage_url": "/config/fake_integration", + } diff --git a/tests/components/tado/test_config_flow.py b/tests/components/tado/test_config_flow.py index 9bd3db5e46b..ce4af05b79c 100644 --- a/tests/components/tado/test_config_flow.py +++ b/tests/components/tado/test_config_flow.py @@ -42,6 +42,7 @@ async def test_form(hass): result["flow_id"], {"username": "test-username", "password": "test-password"}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "myhome" @@ -49,7 +50,6 @@ async def test_form(hass): "username": "test-username", "password": "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -74,6 +74,7 @@ async def test_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data={"username": "test-username", "password": "test-password"}, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "myhome" @@ -81,7 +82,6 @@ async def test_import(hass): "username": "test-username", "password": "test-password", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/tasmota/conftest.py b/tests/components/tasmota/conftest.py index 09a3bfa4d63..fadf8a44648 100644 --- a/tests/components/tasmota/conftest.py +++ b/tests/components/tasmota/conftest.py @@ -1,5 +1,4 @@ """Test fixtures for Tasmota component.""" - from hatasmota.discovery import get_status_sensor_entities import pytest @@ -17,6 +16,7 @@ from tests.common import ( mock_device_registry, mock_registry, ) +from tests.components.light.conftest import mock_light_profiles # noqa @pytest.fixture diff --git a/tests/components/tasmota/test_binary_sensor.py b/tests/components/tasmota/test_binary_sensor.py index 52ab88b0ecb..3f444e75bdc 100644 --- a/tests/components/tasmota/test_binary_sensor.py +++ b/tests/components/tasmota/test_binary_sensor.py @@ -4,8 +4,8 @@ from datetime import timedelta import json from hatasmota.utils import ( + get_topic_stat_result, get_topic_stat_status, - get_topic_stat_switch, get_topic_tele_sensor, get_topic_tele_will, ) @@ -51,53 +51,164 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota): ) await hass.async_block_till_done() - state = hass.states.get("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_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("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_OFF assert not state.attributes.get(ATTR_ASSUMED_STATE) # Test normal state update - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1", '{"STATE":"ON"}') - state = hass.states.get("binary_sensor.test") + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"ON"}}' + ) + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_ON - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1", '{"STATE":"OFF"}') - state = hass.states.get("binary_sensor.test") + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"OFF"}}' + ) + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_OFF # Test periodic state update async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/SENSOR", '{"Switch1":"ON"}') - state = hass.states.get("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_ON async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/SENSOR", '{"Switch1":"OFF"}') - state = hass.states.get("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_OFF # Test polled state update async_fire_mqtt_message( - hass, "tasmota_49A3BC/stat/STATUS8", '{"StatusSNS":{"Switch1":"ON"}}' + hass, "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"Switch1":"ON"}}' ) - state = hass.states.get("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_ON async_fire_mqtt_message( - hass, "tasmota_49A3BC/stat/STATUS8", '{"StatusSNS":{"Switch1":"OFF"}}' + hass, "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"Switch1":"OFF"}}' ) - state = hass.states.get("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") + assert state.state == STATE_OFF + + +async def test_controlling_state_via_mqtt_switchname(hass, mqtt_mock, setup_tasmota): + """Test state update via MQTT.""" + config = copy.deepcopy(DEFAULT_CONFIG) + config["swc"][0] = 1 + config["swn"][0] = "Custom Name" + mac = config["mac"] + + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/config", + json.dumps(config), + ) + await hass.async_block_till_done() + + state = hass.states.get("binary_sensor.custom_name") + 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("binary_sensor.custom_name") + assert state.state == STATE_OFF + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + # Test normal state update + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Custom Name":{"Action":"ON"}}' + ) + state = hass.states.get("binary_sensor.custom_name") + assert state.state == STATE_ON + + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Custom Name":{"Action":"OFF"}}' + ) + state = hass.states.get("binary_sensor.custom_name") + assert state.state == STATE_OFF + + # Test periodic state update + async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/SENSOR", '{"Custom Name":"ON"}') + state = hass.states.get("binary_sensor.custom_name") + assert state.state == STATE_ON + + async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/SENSOR", '{"Custom Name":"OFF"}') + state = hass.states.get("binary_sensor.custom_name") + assert state.state == STATE_OFF + + # Test polled state update + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"Custom Name":"ON"}}' + ) + state = hass.states.get("binary_sensor.custom_name") + assert state.state == STATE_ON + + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"Custom Name":"OFF"}}' + ) + state = hass.states.get("binary_sensor.custom_name") + assert state.state == STATE_OFF + + +async def test_pushon_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota): + """Test state update via MQTT.""" + config = copy.deepcopy(DEFAULT_CONFIG) + config["swc"][0] = 13 + mac = config["mac"] + + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/config", + json.dumps(config), + ) + await hass.async_block_till_done() + + state = hass.states.get("binary_sensor.tasmota_binary_sensor_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("binary_sensor.tasmota_binary_sensor_1") + assert state.state == STATE_OFF + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + # Test normal state update + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"ON"}}' + ) + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") + assert state.state == STATE_ON + + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"OFF"}}' + ) + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") + assert state.state == STATE_OFF + + # Test periodic state update is ignored + async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/SENSOR", '{"Switch1":"ON"}') + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") + assert state.state == STATE_OFF + + # Test polled state update is ignored + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"Switch1":"ON"}}' + ) + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_OFF async def test_friendly_names(hass, mqtt_mock, setup_tasmota): """Test state update via MQTT.""" config = copy.deepcopy(DEFAULT_CONFIG) - config["rl"][0] = 1 config["swc"][0] = 1 config["swc"][1] = 1 + config["swn"][1] = "Beer" mac = config["mac"] async_fire_mqtt_message( @@ -141,21 +252,25 @@ async def test_off_delay(hass, mqtt_mock, setup_tasmota): async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") await hass.async_block_till_done() assert events == ["off"] - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1", '{"STATE":"ON"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"ON"}}' + ) await hass.async_block_till_done() - state = hass.states.get("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_ON assert events == ["off", "on"] - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1", '{"STATE":"ON"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"ON"}}' + ) await hass.async_block_till_done() - state = hass.states.get("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_ON assert events == ["off", "on", "on"] async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=1)) await hass.async_block_till_done() - state = hass.states.get("binary_sensor.test") + state = hass.states.get("binary_sensor.tasmota_binary_sensor_1") assert state.state == STATE_OFF assert events == ["off", "on", "on", "off"] @@ -166,6 +281,7 @@ async def test_availability_when_connection_lost( """Test availability after MQTT disconnection.""" config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 1 + config["swn"][0] = "Test" await help_test_availability_when_connection_lost( hass, mqtt_client_mock, mqtt_mock, binary_sensor.DOMAIN, config ) @@ -175,6 +291,7 @@ async def test_availability(hass, mqtt_mock, setup_tasmota): """Test availability.""" config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 1 + config["swn"][0] = "Test" await help_test_availability(hass, mqtt_mock, binary_sensor.DOMAIN, config) @@ -182,6 +299,7 @@ async def test_availability_discovery_update(hass, mqtt_mock, setup_tasmota): """Test availability discovery update.""" config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 1 + config["swn"][0] = "Test" await help_test_availability_discovery_update( hass, mqtt_mock, binary_sensor.DOMAIN, config ) @@ -193,9 +311,16 @@ async def test_availability_poll_state( """Test polling after MQTT connection (re)established.""" config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 1 + config["swn"][0] = "Test" poll_topic = "tasmota_49A3BC/cmnd/STATUS" await help_test_availability_poll_state( - hass, mqtt_client_mock, mqtt_mock, binary_sensor.DOMAIN, config, poll_topic, "8" + hass, + mqtt_client_mock, + mqtt_mock, + binary_sensor.DOMAIN, + config, + poll_topic, + "10", ) @@ -205,6 +330,8 @@ async def test_discovery_removal_binary_sensor(hass, mqtt_mock, caplog, setup_ta config2 = copy.deepcopy(DEFAULT_CONFIG) config1["swc"][0] = 1 config2["swc"][0] = 0 + config1["swn"][0] = "Test" + config2["swn"][0] = "Test" await help_test_discovery_removal( hass, mqtt_mock, caplog, binary_sensor.DOMAIN, config1, config2 @@ -217,6 +344,7 @@ async def test_discovery_update_unchanged_binary_sensor( """Test update of discovered binary_sensor.""" config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 1 + config["swn"][0] = "Test" with patch( "homeassistant.components.tasmota.binary_sensor.TasmotaBinarySensor.discovery_update" ) as discovery_update: @@ -239,10 +367,11 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock, setup_tasmota): """Test MQTT subscriptions are managed when entity_id is updated.""" config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 1 + config["swn"][0] = "Test" topics = [ - get_topic_stat_switch(config, 0), + get_topic_stat_result(config), get_topic_tele_sensor(config), - get_topic_stat_status(config, 8), + get_topic_stat_status(config, 10), get_topic_tele_will(config), ] await help_test_entity_id_update_subscriptions( @@ -254,6 +383,7 @@ async def test_entity_id_update_discovery_update(hass, mqtt_mock, setup_tasmota) """Test MQTT discovery update when entity_id is updated.""" config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 1 + config["swn"][0] = "Test" await help_test_entity_id_update_discovery_update( hass, mqtt_mock, binary_sensor.DOMAIN, config ) diff --git a/tests/components/tasmota/test_common.py b/tests/components/tasmota/test_common.py index 665249f312a..04346f915c4 100644 --- a/tests/components/tasmota/test_common.py +++ b/tests/components/tasmota/test_common.py @@ -24,41 +24,6 @@ from tests.async_mock import ANY from tests.common import async_fire_mqtt_message DEFAULT_CONFIG = { - "ip": "192.168.15.10", - "dn": "Tasmota", - "fn": ["Test", "Beer", "Milk", "Four", None], - "hn": "tasmota_49A3BC-0956", - "lk": 1, # RGB + white channels linked to a single light - "mac": "00000049A3BC", - "md": "Sonoff Basic", - "ofln": "Offline", - "onln": "Online", - "state": ["OFF", "ON", "TOGGLE", "HOLD"], - "sw": "8.4.0.2", - "t": "tasmota_49A3BC", - "ft": "%topic%/%prefix%/", - "tp": ["cmnd", "stat", "tele"], - "rl": [0, 0, 0, 0, 0, 0, 0, 0], - "swc": [-1, -1, -1, -1, -1, -1, -1, -1], - "btn": [0, 0, 0, 0], - "so": { - "11": 0, # Swap button single and double press functionality - "13": 0, # Allow immediate action on single button press - "17": 1, # Show Color string as hex or comma-separated - "20": 0, # Update of Dimmer/Color/CT without turning power on - "30": 0, # Enforce Home Assistant auto-discovery as light - "68": 0, # Multi-channel PWM instead of a single light - "73": 0, # Enable Buttons decoupling and send multi-press and hold MQTT messages - "80": 0, # Blinds and shutters support - "82": 0, # Reduce the CT range from 153..500 to 200.380 - }, - "ty": 0, # Tuya MCU - "lt_st": 0, - "ver": 1, -} - - -DEFAULT_CONFIG_9_0_0_4 = { "ip": "192.168.15.10", "dn": "Tasmota", "fn": ["Test", "Beer", "Milk", "Four", None], @@ -96,6 +61,41 @@ DEFAULT_CONFIG_9_0_0_4 = { } +DEFAULT_CONFIG_9_0_0_3 = { + "ip": "192.168.15.10", + "dn": "Tasmota", + "fn": ["Test", "Beer", "Milk", "Four", None], + "hn": "tasmota_49A3BC-0956", + "lk": 1, # RGB + white channels linked to a single light + "mac": "00000049A3BC", + "md": "Sonoff Basic", + "ofln": "Offline", + "onln": "Online", + "state": ["OFF", "ON", "TOGGLE", "HOLD"], + "sw": "8.4.0.2", + "t": "tasmota_49A3BC", + "ft": "%topic%/%prefix%/", + "tp": ["cmnd", "stat", "tele"], + "rl": [0, 0, 0, 0, 0, 0, 0, 0], + "swc": [-1, -1, -1, -1, -1, -1, -1, -1], + "btn": [0, 0, 0, 0], + "so": { + "11": 0, # Swap button single and double press functionality + "13": 0, # Allow immediate action on single button press + "17": 1, # Show Color string as hex or comma-separated + "20": 0, # Update of Dimmer/Color/CT without turning power on + "30": 0, # Enforce Home Assistant auto-discovery as light + "68": 0, # Multi-channel PWM instead of a single light + "73": 0, # Enable Buttons decoupling and send multi-press and hold MQTT messages + "80": 0, # Blinds and shutters support + "82": 0, # Reduce the CT range from 153..500 to 200.380 + }, + "ty": 0, # Tuya MCU + "lt_st": 0, + "ver": 1, +} + + async def help_test_availability_when_connection_lost( hass, mqtt_client_mock, diff --git a/tests/components/tasmota/test_device_trigger.py b/tests/components/tasmota/test_device_trigger.py index b027b2c095d..09c3d691b09 100644 --- a/tests/components/tasmota/test_device_trigger.py +++ b/tests/components/tasmota/test_device_trigger.py @@ -142,6 +142,7 @@ async def test_discover_bad_triggers( mac=None, source=None, subtype=None, + switchname=None, trigger_topic=None, type=None, ) @@ -245,6 +246,7 @@ async def test_if_fires_on_mqtt_message( config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 0 config["swc"][2] = 9 + config["swn"][2] = "custom_switch" mac = config["mac"] async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config)) @@ -289,13 +291,17 @@ async def test_if_fires_on_mqtt_message( ) # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 assert calls[0].data["some"] == "short_press" # Fake long press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH3T", '{"TRIG":"HOLD"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"custom_switch":{"Action":"HOLD"}}' + ) await hass.async_block_till_done() assert len(calls) == 2 assert calls[1].data["some"] == "long_press" @@ -314,6 +320,7 @@ async def test_if_fires_on_mqtt_message_late_discover( config2 = copy.deepcopy(DEFAULT_CONFIG) config2["swc"][0] = 0 config2["swc"][3] = 9 + config2["swn"][3] = "custom_switch" async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config1)) await hass.async_block_till_done() @@ -361,13 +368,17 @@ async def test_if_fires_on_mqtt_message_late_discover( await hass.async_block_till_done() # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 assert calls[0].data["some"] == "short_press" # Fake long press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH4T", '{"TRIG":"HOLD"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"custom_switch":{"Action":"HOLD"}}' + ) await hass.async_block_till_done() assert len(calls) == 2 assert calls[1].data["some"] == "double_press" @@ -414,7 +425,9 @@ async def test_if_fires_on_mqtt_message_after_update( ) # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 @@ -422,11 +435,15 @@ async def test_if_fires_on_mqtt_message_after_update( async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config2)) await hass.async_block_till_done() - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 - async_fire_mqtt_message(hass, "tasmota_49A3BC/status/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/status/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 2 @@ -434,11 +451,15 @@ async def test_if_fires_on_mqtt_message_after_update( async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config2)) await hass.async_block_till_done() - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 2 - async_fire_mqtt_message(hass, "tasmota_49A3BC/status/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/status/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 3 @@ -527,7 +548,9 @@ async def test_not_fires_on_mqtt_message_after_remove_by_mqtt( ) # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 @@ -536,7 +559,9 @@ async def test_not_fires_on_mqtt_message_after_remove_by_mqtt( async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config)) await hass.async_block_till_done() - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 @@ -545,7 +570,9 @@ async def test_not_fires_on_mqtt_message_after_remove_by_mqtt( async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config)) await hass.async_block_till_done() - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 2 @@ -590,7 +617,9 @@ async def test_not_fires_on_mqtt_message_after_remove_from_registry( ) # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 @@ -598,7 +627,9 @@ async def test_not_fires_on_mqtt_message_after_remove_from_registry( device_reg.async_remove_device(device_entry.id) await hass.async_block_till_done() - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 @@ -637,7 +668,9 @@ async def test_attach_remove(hass, device_reg, mqtt_mock, setup_tasmota): ) # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 assert calls[0] == "event 'tasmota_event'" @@ -647,7 +680,9 @@ async def test_attach_remove(hass, device_reg, mqtt_mock, setup_tasmota): await hass.async_block_till_done() # Verify the triggers are no longer active - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 @@ -688,7 +723,9 @@ async def test_attach_remove_late(hass, device_reg, mqtt_mock, setup_tasmota): ) # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 0 @@ -696,7 +733,9 @@ async def test_attach_remove_late(hass, device_reg, mqtt_mock, setup_tasmota): await hass.async_block_till_done() # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 assert calls[0] == "event 'tasmota_event'" @@ -706,7 +745,9 @@ async def test_attach_remove_late(hass, device_reg, mqtt_mock, setup_tasmota): await hass.async_block_till_done() # Verify the triggers are no longer active - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 @@ -754,7 +795,9 @@ async def test_attach_remove_late2(hass, device_reg, mqtt_mock, setup_tasmota): await hass.async_block_till_done() # Verify the triggers is not active - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 0 @@ -866,7 +909,9 @@ async def test_attach_remove_config_entry(hass, device_reg, mqtt_mock, setup_tas ) # Fake short press. - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 assert calls[0] == "event 'tasmota_event'" @@ -877,6 +922,8 @@ async def test_attach_remove_config_entry(hass, device_reg, mqtt_mock, setup_tas await hass.async_block_till_done() # Verify the triggers are no longer active - async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1T", '{"TRIG":"TOGGLE"}') + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' + ) await hass.async_block_till_done() assert len(calls) == 1 diff --git a/tests/components/tasmota/test_discovery.py b/tests/components/tasmota/test_discovery.py index ba288ef93ae..b6a51a38daf 100644 --- a/tests/components/tasmota/test_discovery.py +++ b/tests/components/tasmota/test_discovery.py @@ -6,7 +6,7 @@ from homeassistant.components.tasmota.const import DEFAULT_PREFIX from homeassistant.components.tasmota.discovery import ALREADY_DISCOVERED from .conftest import setup_tasmota_helper -from .test_common import DEFAULT_CONFIG, DEFAULT_CONFIG_9_0_0_4 +from .test_common import DEFAULT_CONFIG, DEFAULT_CONFIG_9_0_0_3 from tests.async_mock import patch from tests.common import async_fire_mqtt_message @@ -136,7 +136,7 @@ async def test_device_discover_deprecated( hass, mqtt_mock, caplog, device_reg, entity_reg, setup_tasmota ): """Test setting up a device with deprecated discovery message.""" - config = copy.deepcopy(DEFAULT_CONFIG_9_0_0_4) + config = copy.deepcopy(DEFAULT_CONFIG_9_0_0_3) mac = config["mac"] async_fire_mqtt_message( diff --git a/tests/components/tasmota/test_init.py b/tests/components/tasmota/test_init.py new file mode 100644 index 00000000000..39d99872741 --- /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 diff --git a/tests/components/tasmota/test_mixins.py b/tests/components/tasmota/test_mixins.py index a90d4c01fd7..5f4ef443475 100644 --- a/tests/components/tasmota/test_mixins.py +++ b/tests/components/tasmota/test_mixins.py @@ -23,7 +23,7 @@ async def test_availability_poll_state_once( config["swc"][0] = 1 config["swc"][1] = 1 poll_payload_relay = "" - poll_payload_switch = "8" + poll_payload_switch = "10" poll_topic_relay = "tasmota_49A3BC/cmnd/STATE" poll_topic_switch = "tasmota_49A3BC/cmnd/STATUS" diff --git a/tests/components/tasmota/test_sensor.py b/tests/components/tasmota/test_sensor.py index e5d55b75a3a..4c8de9e339d 100644 --- a/tests/components/tasmota/test_sensor.py +++ b/tests/components/tasmota/test_sensor.py @@ -1,8 +1,10 @@ """The tests for the Tasmota sensor platform.""" import copy +import datetime from datetime import timedelta import json +import hatasmota from hatasmota.utils import ( get_topic_stat_status, get_topic_tele_sensor, @@ -29,7 +31,7 @@ from .test_common import ( help_test_entity_id_update_subscriptions, ) -from tests.async_mock import patch +from tests.async_mock import Mock, patch from tests.common import async_fire_mqtt_message, async_fire_time_changed DEFAULT_SENSOR_CONFIG = { @@ -124,7 +126,7 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota): # Test polled state update async_fire_mqtt_message( hass, - "tasmota_49A3BC/stat/STATUS8", + "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"DHT11":{"Temperature":20.0}}}', ) state = hass.states.get("sensor.tasmota_dht11_temperature") @@ -169,7 +171,7 @@ async def test_nested_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): # Test polled state update async_fire_mqtt_message( hass, - "tasmota_49A3BC/stat/STATUS8", + "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"TX23":{"Speed":{"Act":"23.4"}}}}', ) state = hass.states.get("sensor.tasmota_tx23_speed_act") @@ -214,7 +216,7 @@ async def test_indexed_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): # Test polled state update async_fire_mqtt_message( hass, - "tasmota_49A3BC/stat/STATUS8", + "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"ENERGY":{"TotalTariff":[5.6,7.8]}}}', ) state = hass.states.get("sensor.tasmota_energy_totaltariff_1") @@ -259,6 +261,7 @@ async def test_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): async_fire_mqtt_message( hass, "tasmota_49A3BC/tele/STATE", '{"Wifi":{"Signal":20.5}}' ) + await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == "20.5" @@ -268,10 +271,142 @@ async def test_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): "tasmota_49A3BC/stat/STATUS11", '{"StatusSTS":{"Wifi":{"Signal":20.0}}}', ) + await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == "20.0" +@pytest.mark.parametrize("status_sensor_disabled", [False]) +async def test_single_shot_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): + """Test state update via MQTT.""" + entity_reg = await hass.helpers.entity_registry.async_get_registry() + + # Pre-enable the status sensor + entity_reg.async_get_or_create( + sensor.DOMAIN, + "tasmota", + "00000049A3BC_status_sensor_status_sensor_status_restart_reason", + suggested_object_id="tasmota_status", + disabled_by=None, + ) + + 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() + await hass.async_block_till_done() + + state = hass.states.get("sensor.tasmota_status") + 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") + assert state.state == STATE_UNKNOWN + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + # Test polled state update + async_fire_mqtt_message( + hass, + "tasmota_49A3BC/stat/STATUS1", + '{"StatusPRM":{"RestartReason":"Some reason"}}', + ) + await hass.async_block_till_done() + state = hass.states.get("sensor.tasmota_status") + assert state.state == "Some reason" + + # Test polled state update is ignored + async_fire_mqtt_message( + hass, + "tasmota_49A3BC/stat/STATUS1", + '{"StatusPRM":{"RestartReason":"Another reason"}}', + ) + await hass.async_block_till_done() + state = hass.states.get("sensor.tasmota_status") + assert state.state == "Some reason" + + # Device signals online again + async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") + await hass.async_block_till_done() + state = hass.states.get("sensor.tasmota_status") + assert state.state == "Some reason" + + # Test polled state update + async_fire_mqtt_message( + hass, + "tasmota_49A3BC/stat/STATUS1", + '{"StatusPRM":{"RestartReason":"Another reason"}}', + ) + await hass.async_block_till_done() + state = hass.states.get("sensor.tasmota_status") + assert state.state == "Another reason" + + # Test polled state update is ignored + async_fire_mqtt_message( + hass, + "tasmota_49A3BC/stat/STATUS1", + '{"StatusPRM":{"RestartReason":"Third reason"}}', + ) + await hass.async_block_till_done() + state = hass.states.get("sensor.tasmota_status") + assert state.state == "Another reason" + + +@pytest.mark.parametrize("status_sensor_disabled", [False]) +@patch.object(hatasmota.status_sensor, "datetime", Mock(wraps=datetime.datetime)) +async def test_restart_time_status_sensor_state_via_mqtt( + hass, mqtt_mock, setup_tasmota +): + """Test state update via MQTT.""" + entity_reg = await hass.helpers.entity_registry.async_get_registry() + + # Pre-enable the status sensor + entity_reg.async_get_or_create( + sensor.DOMAIN, + "tasmota", + "00000049A3BC_status_sensor_status_sensor_last_restart_time", + suggested_object_id="tasmota_status", + disabled_by=None, + ) + + 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() + await hass.async_block_till_done() + + state = hass.states.get("sensor.tasmota_status") + 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") + assert state.state == STATE_UNKNOWN + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + # Test polled state update + utc_now = datetime.datetime(2020, 11, 11, 8, 0, 0, tzinfo=dt.UTC) + hatasmota.status_sensor.datetime.now.return_value = utc_now + async_fire_mqtt_message( + hass, + "tasmota_49A3BC/stat/STATUS11", + '{"StatusSTS":{"UptimeSec":"3600"}}', + ) + await hass.async_block_till_done() + state = hass.states.get("sensor.tasmota_status") + assert state.state == "2020-11-11T07:00:00+00:00" + + async def test_attributes(hass, mqtt_mock, setup_tasmota): """Test correct attributes for sensors.""" config = copy.deepcopy(DEFAULT_CONFIG) @@ -301,7 +436,7 @@ async def test_attributes(hass, mqtt_mock, setup_tasmota): assert state.attributes.get("device_class") == "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" + assert state.attributes.get("unit_of_measurement") == "°C" state = hass.states.get("sensor.tasmota_beer_CarbonDioxide") assert state.attributes.get("device_class") is None @@ -371,7 +506,7 @@ async def test_indexed_sensor_attributes(hass, mqtt_mock, setup_tasmota): assert state.attributes.get("device_class") == "temperature" 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" + assert state.attributes.get("unit_of_measurement") == "°C" state = hass.states.get("sensor.tasmota_dummy2_carbondioxide_1") assert state.attributes.get("device_class") is None @@ -412,11 +547,7 @@ async def test_enable_status_sensor(hass, mqtt_mock, setup_tasmota): async_fire_time_changed( hass, - dt.utcnow() - + timedelta( - seconds=config_entries.EntityRegistryDisabledHandler.RELOAD_AFTER_UPDATE_DELAY - + 1 - ), + dt.utcnow() + timedelta(seconds=config_entries.RELOAD_AFTER_UPDATE_DELAY + 1), ) await hass.async_block_till_done() @@ -497,7 +628,7 @@ async def test_availability_poll_state( sensor.DOMAIN, config, poll_topic, - "8", + "10", sensor_config, ) @@ -559,7 +690,7 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock, setup_tasmota): sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG) topics = [ get_topic_tele_sensor(config), - get_topic_stat_status(config, 8), + get_topic_stat_status(config, 10), get_topic_tele_will(config), ] await help_test_entity_id_update_subscriptions( diff --git a/tests/components/template/conftest.py b/tests/components/template/conftest.py new file mode 100644 index 00000000000..8e3491b160a --- /dev/null +++ b/tests/components/template/conftest.py @@ -0,0 +1,2 @@ +"""template conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/template/test_sensor.py b/tests/components/template/test_sensor.py index 681794e910f..c39fb474bca 100644 --- a/tests/components/template/test_sensor.py +++ b/tests/components/template/test_sensor.py @@ -946,3 +946,40 @@ async def test_self_referencing_icon_with_no_loop(hass, caplog): assert state.state == "extreme" assert state.attributes[ATTR_ICON] == "mdi:hazard-lights" assert "Template loop detected" not in caplog.text + + +async def test_duplicate_templates(hass): + """Test template entity where the value and friendly name as the same template.""" + hass.states.async_set("sensor.test_state", "Abc") + + with assert_setup_component(1, sensor.DOMAIN): + assert await async_setup_component( + hass, + sensor.DOMAIN, + { + "sensor": { + "platform": "template", + "sensors": { + "test_template_sensor": { + "value_template": "{{ states.sensor.test_state.state }}", + "friendly_name_template": "{{ states.sensor.test_state.state }}", + } + }, + } + }, + ) + + await hass.async_block_till_done() + await hass.async_start() + await hass.async_block_till_done() + + state = hass.states.get("sensor.test_template_sensor") + assert state.attributes["friendly_name"] == "Abc" + assert state.state == "Abc" + + hass.states.async_set("sensor.test_state", "Def") + await hass.async_block_till_done() + + state = hass.states.get("sensor.test_template_sensor") + assert state.attributes["friendly_name"] == "Def" + assert state.state == "Def" diff --git a/tests/components/tesla/test_config_flow.py b/tests/components/tesla/test_config_flow.py index 8b75fd904b9..59cdf910bf4 100644 --- a/tests/components/tesla/test_config_flow.py +++ b/tests/components/tesla/test_config_flow.py @@ -42,6 +42,7 @@ async def test_form(hass): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_PASSWORD: "test", CONF_USERNAME: "test@email.com"} ) + await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["title"] == "test@email.com" @@ -49,7 +50,6 @@ async def test_form(hass): CONF_TOKEN: "test-refresh-token", CONF_ACCESS_TOKEN: "test-access-token", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/tplink/conftest.py b/tests/components/tplink/conftest.py new file mode 100644 index 00000000000..d1800513486 --- /dev/null +++ b/tests/components/tplink/conftest.py @@ -0,0 +1,2 @@ +"""tplink conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/tradfri/conftest.py b/tests/components/tradfri/conftest.py index a944f836dea..c95bf2c036c 100644 --- a/tests/components/tradfri/conftest.py +++ b/tests/components/tradfri/conftest.py @@ -4,6 +4,7 @@ import pytest from . import MOCK_GATEWAY_ID from tests.async_mock import Mock, patch +from tests.components.light.conftest import mock_light_profiles # noqa # pylint: disable=protected-access diff --git a/tests/components/tuya/test_config_flow.py b/tests/components/tuya/test_config_flow.py index 81154a368ff..e1b9bd3466c 100644 --- a/tests/components/tuya/test_config_flow.py +++ b/tests/components/tuya/test_config_flow.py @@ -47,6 +47,7 @@ async def test_user(hass, tuya): result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input=TUYA_USER_DATA ) + await hass.async_block_till_done() assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["title"] == USERNAME @@ -56,7 +57,6 @@ async def test_user(hass, tuya): assert result["data"][CONF_PLATFORM] == TUYA_PLATFORM assert not result["result"].unique_id - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -76,6 +76,7 @@ async def test_import(hass, tuya): context={"source": config_entries.SOURCE_IMPORT}, data=TUYA_USER_DATA, ) + await hass.async_block_till_done() assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["title"] == USERNAME @@ -85,7 +86,6 @@ async def test_import(hass, tuya): assert result["data"][CONF_PLATFORM] == TUYA_PLATFORM assert not result["result"].unique_id - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/unifi/test_config_flow.py b/tests/components/unifi/test_config_flow.py index 8b935d7744b..87233f9983c 100644 --- a/tests/components/unifi/test_config_flow.py +++ b/tests/components/unifi/test_config_flow.py @@ -8,6 +8,7 @@ from homeassistant.components.unifi.const import ( CONF_BLOCK_CLIENT, CONF_CONTROLLER, CONF_DETECTION_TIME, + CONF_DPI_RESTRICTIONS, CONF_IGNORE_WIRED_BUG, CONF_POE_CLIENTS, CONF_SITE_ID, @@ -72,6 +73,14 @@ WLANS = [ {"name": "SSID 2", "name_combine_enabled": False, "name_combine_suffix": "_IOT"}, ] +DPI_GROUPS = [ + { + "_id": "5ba29dd8e3c58f026e9d7c4a", + "name": "Default", + "site_id": "5ba29dd4e3c58f026e9d7c38", + }, +] + async def test_flow_works(hass, aioclient_mock, mock_discovery): """Test config flow.""" @@ -307,7 +316,12 @@ async def test_flow_fails_unknown_problem(hass, aioclient_mock): async def test_advanced_option_flow(hass): """Test advanced config flow options.""" controller = await setup_unifi_integration( - hass, clients_response=CLIENTS, devices_response=DEVICES, wlans_response=WLANS + hass, + clients_response=CLIENTS, + devices_response=DEVICES, + wlans_response=WLANS, + dpigroup_response=DPI_GROUPS, + dpiapp_response=[], ) result = await hass.config_entries.options.async_init( @@ -336,7 +350,11 @@ async def test_advanced_option_flow(hass): result = await hass.config_entries.options.async_configure( result["flow_id"], - user_input={CONF_BLOCK_CLIENT: [CLIENTS[0]["mac"]], CONF_POE_CLIENTS: False}, + user_input={ + CONF_BLOCK_CLIENT: [CLIENTS[0]["mac"]], + CONF_POE_CLIENTS: False, + CONF_DPI_RESTRICTIONS: False, + }, ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM @@ -359,6 +377,7 @@ async def test_advanced_option_flow(hass): CONF_DETECTION_TIME: 100, CONF_IGNORE_WIRED_BUG: False, CONF_POE_CLIENTS: False, + CONF_DPI_RESTRICTIONS: False, CONF_BLOCK_CLIENT: [CLIENTS[0]["mac"]], CONF_ALLOW_BANDWIDTH_SENSORS: True, CONF_ALLOW_UPTIME_SENSORS: True, @@ -368,7 +387,11 @@ async def test_advanced_option_flow(hass): async def test_simple_option_flow(hass): """Test simple config flow options.""" controller = await setup_unifi_integration( - hass, clients_response=CLIENTS, wlans_response=WLANS + hass, + clients_response=CLIENTS, + wlans_response=WLANS, + dpigroup_response=DPI_GROUPS, + dpiapp_response=[], ) result = await hass.config_entries.options.async_init( diff --git a/tests/components/unifi/test_controller.py b/tests/components/unifi/test_controller.py index 5fee4a85f9a..83732601cd6 100644 --- a/tests/components/unifi/test_controller.py +++ b/tests/components/unifi/test_controller.py @@ -81,6 +81,8 @@ async def setup_unifi_integration( devices_response=None, clients_all_response=None, wlans_response=None, + dpigroup_response=None, + dpiapp_response=None, known_wireless_clients=None, controllers=None, ): @@ -116,6 +118,14 @@ async def setup_unifi_integration( if wlans_response: mock_wlans_responses.append(wlans_response) + mock_dpigroup_responses = deque() + if dpigroup_response: + mock_dpigroup_responses.append(dpigroup_response) + + mock_dpiapp_responses = deque() + if dpiapp_response: + mock_dpiapp_responses.append(dpiapp_response) + mock_requests = [] async def mock_request(self, method, path, json=None): @@ -129,6 +139,10 @@ async def setup_unifi_integration( return mock_client_all_responses.popleft() if path == "/rest/wlanconf" and mock_wlans_responses: return mock_wlans_responses.popleft() + if path == "/rest/dpigroup" and mock_dpigroup_responses: + return mock_dpigroup_responses.popleft() + if path == "/rest/dpiapp" and mock_dpiapp_responses: + return mock_dpiapp_responses.popleft() return {} with patch("aiounifi.Controller.check_unifi_os", return_value=True), patch( diff --git a/tests/components/unifi/test_sensor.py b/tests/components/unifi/test_sensor.py index 690b9d77899..dc2fea634c9 100644 --- a/tests/components/unifi/test_sensor.py +++ b/tests/components/unifi/test_sensor.py @@ -71,7 +71,7 @@ async def test_no_clients(hass): }, ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 0 @@ -88,7 +88,7 @@ async def test_sensors(hass): clients_response=CLIENTS, ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6 wired_client_rx = hass.states.get("sensor.wired_client_name_rx") diff --git a/tests/components/unifi/test_switch.py b/tests/components/unifi/test_switch.py index 6c4fc25d828..903db479d34 100644 --- a/tests/components/unifi/test_switch.py +++ b/tests/components/unifi/test_switch.py @@ -9,6 +9,8 @@ from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.components.unifi.const import ( CONF_BLOCK_CLIENT, + CONF_DPI_RESTRICTIONS, + CONF_POE_CLIENTS, CONF_TRACK_CLIENTS, CONF_TRACK_DEVICES, DOMAIN as UNIFI_DOMAIN, @@ -251,6 +253,35 @@ EVENT_CLIENT_2_CONNECTED = { } +DPI_GROUPS = [ + { + "_id": "5ba29dd8e3c58f026e9d7c4a", + "attr_no_delete": True, + "attr_hidden_id": "Default", + "name": "Default", + "site_id": "name", + }, + { + "_id": "5f976f4ae3c58f018ec7dff6", + "name": "Block Media Streaming", + "site_id": "name", + "dpiapp_ids": ["5f976f62e3c58f018ec7e17d"], + }, +] + +DPI_APPS = [ + { + "_id": "5f976f62e3c58f018ec7e17d", + "apps": [], + "blocked": True, + "cats": ["4"], + "enabled": True, + "log": True, + "site_id": "name", + } +] + + async def test_platform_manually_configured(hass): """Test that we do not discover anything or try to set up a controller.""" assert ( @@ -266,10 +297,14 @@ async def test_no_clients(hass): """Test the update_clients function when no clients are found.""" controller = await setup_unifi_integration( hass, - options={CONF_TRACK_CLIENTS: False, CONF_TRACK_DEVICES: False}, + options={ + CONF_TRACK_CLIENTS: False, + CONF_TRACK_DEVICES: False, + CONF_DPI_RESTRICTIONS: False, + }, ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 @@ -282,7 +317,7 @@ async def test_controller_not_client(hass): devices_response=[DEVICE_1], ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 cloudkey = hass.states.get("switch.cloud_key") assert cloudkey is None @@ -300,7 +335,7 @@ async def test_not_admin(hass): devices_response=[DEVICE_1], ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 @@ -316,10 +351,12 @@ async def test_switches(hass): clients_response=[CLIENT_1, CLIENT_4], devices_response=[DEVICE_1], clients_all_response=[BLOCKED, UNBLOCKED, CLIENT_1], + dpigroup_response=DPI_GROUPS, + dpiapp_response=DPI_APPS, ) - assert len(controller.mock_requests) == 4 - assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 3 + assert len(controller.mock_requests) == 6 + assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 4 switch_1 = hass.states.get("switch.poe_client_1") assert switch_1 is not None @@ -340,11 +377,15 @@ async def test_switches(hass): assert unblocked is not None assert unblocked.state == "on" + dpi_switch = hass.states.get("switch.block_media_streaming") + assert dpi_switch is not None + assert dpi_switch.state == "on" + await hass.services.async_call( SWITCH_DOMAIN, "turn_off", {"entity_id": "switch.block_client_1"}, blocking=True ) - assert len(controller.mock_requests) == 5 - assert controller.mock_requests[4] == { + assert len(controller.mock_requests) == 7 + assert controller.mock_requests[6] == { "json": {"mac": "00:00:00:00:01:01", "cmd": "block-sta"}, "method": "post", "path": "/cmd/stamgr", @@ -353,13 +394,39 @@ async def test_switches(hass): await hass.services.async_call( SWITCH_DOMAIN, "turn_on", {"entity_id": "switch.block_client_1"}, blocking=True ) - assert len(controller.mock_requests) == 6 - assert controller.mock_requests[5] == { + assert len(controller.mock_requests) == 8 + assert controller.mock_requests[7] == { "json": {"mac": "00:00:00:00:01:01", "cmd": "unblock-sta"}, "method": "post", "path": "/cmd/stamgr", } + await hass.services.async_call( + SWITCH_DOMAIN, + "turn_off", + {"entity_id": "switch.block_media_streaming"}, + blocking=True, + ) + assert len(controller.mock_requests) == 9 + assert controller.mock_requests[8] == { + "json": {"enabled": False}, + "method": "put", + "path": "/rest/dpiapp/5f976f62e3c58f018ec7e17d", + } + + await hass.services.async_call( + SWITCH_DOMAIN, + "turn_on", + {"entity_id": "switch.block_media_streaming"}, + blocking=True, + ) + assert len(controller.mock_requests) == 10 + assert controller.mock_requests[9] == { + "json": {"enabled": True}, + "method": "put", + "path": "/rest/dpiapp/5f976f62e3c58f018ec7e17d", + } + async def test_remove_switches(hass): """Test the update_items function with some clients.""" @@ -443,8 +510,8 @@ async def test_block_switches(hass): await hass.services.async_call( SWITCH_DOMAIN, "turn_off", {"entity_id": "switch.block_client_1"}, blocking=True ) - assert len(controller.mock_requests) == 5 - assert controller.mock_requests[4] == { + assert len(controller.mock_requests) == 7 + assert controller.mock_requests[6] == { "json": {"mac": "00:00:00:00:01:01", "cmd": "block-sta"}, "method": "post", "path": "/cmd/stamgr", @@ -453,8 +520,8 @@ async def test_block_switches(hass): await hass.services.async_call( SWITCH_DOMAIN, "turn_on", {"entity_id": "switch.block_client_1"}, blocking=True ) - assert len(controller.mock_requests) == 6 - assert controller.mock_requests[5] == { + assert len(controller.mock_requests) == 8 + assert controller.mock_requests[7] == { "json": {"mac": "00:00:00:00:01:01", "cmd": "unblock-sta"}, "method": "post", "path": "/cmd/stamgr", @@ -469,10 +536,11 @@ async def test_new_client_discovered_on_block_control(hass): CONF_BLOCK_CLIENT: [BLOCKED["mac"]], CONF_TRACK_CLIENTS: False, CONF_TRACK_DEVICES: False, + CONF_DPI_RESTRICTIONS: False, }, ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 blocked = hass.states.get("switch.block_client_1") @@ -541,6 +609,30 @@ async def test_option_block_clients(hass): assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 +async def test_option_remove_switches(hass): + """Test removal of DPI switch when options updated.""" + controller = await setup_unifi_integration( + hass, + options={ + CONF_TRACK_CLIENTS: False, + CONF_TRACK_DEVICES: False, + }, + clients_response=[CLIENT_1], + devices_response=[DEVICE_1], + dpigroup_response=DPI_GROUPS, + dpiapp_response=DPI_APPS, + ) + assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 + + # Disable DPI Switches + hass.config_entries.async_update_entry( + controller.config_entry, + options={CONF_DPI_RESTRICTIONS: False, CONF_POE_CLIENTS: False}, + ) + await hass.async_block_till_done() + assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 + + async def test_new_client_discovered_on_poe_control(hass): """Test if 2nd update has a new client.""" controller = await setup_unifi_integration( @@ -550,7 +642,7 @@ async def test_new_client_discovered_on_poe_control(hass): devices_response=[DEVICE_1], ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1 controller.api.websocket._data = { @@ -576,9 +668,9 @@ async def test_new_client_discovered_on_poe_control(hass): await hass.services.async_call( SWITCH_DOMAIN, "turn_off", {"entity_id": "switch.poe_client_1"}, blocking=True ) - assert len(controller.mock_requests) == 5 + assert len(controller.mock_requests) == 7 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 - assert controller.mock_requests[4] == { + assert controller.mock_requests[6] == { "json": { "port_overrides": [{"port_idx": 1, "portconf_id": "1a1", "poe_mode": "off"}] }, @@ -589,8 +681,8 @@ async def test_new_client_discovered_on_poe_control(hass): await hass.services.async_call( SWITCH_DOMAIN, "turn_on", {"entity_id": "switch.poe_client_1"}, blocking=True ) - assert len(controller.mock_requests) == 6 - assert controller.mock_requests[4] == { + assert len(controller.mock_requests) == 8 + assert controller.mock_requests[7] == { "json": { "port_overrides": [ {"port_idx": 1, "portconf_id": "1a1", "poe_mode": "auto"} @@ -613,7 +705,7 @@ async def test_ignore_multiple_poe_clients_on_same_port(hass): devices_response=[DEVICE_1], ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 3 switch_1 = hass.states.get("switch.poe_client_1") @@ -664,7 +756,7 @@ async def test_restoring_client(hass): clients_all_response=[CLIENT_1], ) - assert len(controller.mock_requests) == 4 + assert len(controller.mock_requests) == 6 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 device_1 = hass.states.get("switch.client_1") diff --git a/tests/components/upb/test_config_flow.py b/tests/components/upb/test_config_flow.py index f0b44a4bad8..0c874399f88 100644 --- a/tests/components/upb/test_config_flow.py +++ b/tests/components/upb/test_config_flow.py @@ -59,6 +59,7 @@ async def test_full_upb_flow_with_serial_port(hass): "file_path": "upb.upe", }, ) + await hass.async_block_till_done() assert flow["type"] == "form" assert flow["errors"] == {} @@ -68,7 +69,6 @@ async def test_full_upb_flow_with_serial_port(hass): "host": "serial:///dev/ttyS0:115200", "file_path": "upb.upe", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -125,12 +125,12 @@ async def test_form_import(hass): context={"source": config_entries.SOURCE_IMPORT}, data={"host": "tcp://42.4.2.42", "file_path": "upb.upe"}, ) + await hass.async_block_till_done() assert result["type"] == "create_entry" assert result["title"] == "UPB" assert result["data"] == {"host": "tcp://42.4.2.42", "file_path": "upb.upe"} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/vera/conftest.py b/tests/components/vera/conftest.py index 193c0733736..c20dc4ed499 100644 --- a/tests/components/vera/conftest.py +++ b/tests/components/vera/conftest.py @@ -1,10 +1,10 @@ """Fixtures for tests.""" - import pytest from .common import ComponentFactory from tests.async_mock import patch +from tests.components.light.conftest import mock_light_profiles # noqa @pytest.fixture() diff --git a/tests/components/vilfo/test_config_flow.py b/tests/components/vilfo/test_config_flow.py index f14ec123ba5..ca77b199cfa 100644 --- a/tests/components/vilfo/test_config_flow.py +++ b/tests/components/vilfo/test_config_flow.py @@ -38,7 +38,6 @@ async def test_form(hass): "access_token": "test-token", } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/vizio/test_config_flow.py b/tests/components/vizio/test_config_flow.py index 32469fabd05..e966188afd2 100644 --- a/tests/components/vizio/test_config_flow.py +++ b/tests/components/vizio/test_config_flow.py @@ -856,6 +856,21 @@ async def test_zeroconf_ignore( assert result["type"] == data_entry_flow.RESULT_TYPE_FORM +async def test_zeroconf_no_unique_id( + hass: HomeAssistantType, + vizio_no_unique_id: pytest.fixture, +) -> None: + """Test zeroconf discovery aborts when unique_id is None.""" + + discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy() + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "cannot_connect" + + async def test_zeroconf_abort_when_ignored( hass: HomeAssistantType, vizio_connect: pytest.fixture, diff --git a/tests/components/volumio/test_config_flow.py b/tests/components/volumio/test_config_flow.py index a80d527b3f8..477ef25cb87 100644 --- a/tests/components/volumio/test_config_flow.py +++ b/tests/components/volumio/test_config_flow.py @@ -50,12 +50,12 @@ async def test_form(hass): result["flow_id"], TEST_CONNECTION, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "TestVolumio" assert result2["data"] == {**TEST_SYSTEM_INFO, **TEST_CONNECTION} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -118,6 +118,7 @@ async def test_empty_system_info(hass): result["flow_id"], TEST_CONNECTION, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == TEST_CONNECTION["host"] @@ -128,7 +129,6 @@ async def test_empty_system_info(hass): "id": None, } - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -191,6 +191,7 @@ async def test_discovery(hass): result["flow_id"], user_input={}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == TEST_DISCOVERY_RESULT["name"] @@ -199,7 +200,6 @@ async def test_discovery(hass): assert result2["result"] assert result2["result"].unique_id == TEST_DISCOVERY_RESULT["id"] - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/webhook/test_trigger.py b/tests/components/webhook/test_trigger.py index 30601ef6bec..bb3cb680743 100644 --- a/tests/components/webhook/test_trigger.py +++ b/tests/components/webhook/test_trigger.py @@ -12,6 +12,7 @@ async def setup_http(hass): """Set up http.""" assert await async_setup_component(hass, "http", {}) assert await async_setup_component(hass, "webhook", {}) + await hass.async_block_till_done() async def test_webhook_json(hass, aiohttp_client): @@ -38,10 +39,12 @@ async def test_webhook_json(hass, aiohttp_client): } }, ) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) await client.post("/api/webhook/json_webhook", json={"hello": "world"}) + await hass.async_block_till_done() assert len(events) == 1 assert events[0].data["hello"] == "yo world" @@ -71,10 +74,12 @@ async def test_webhook_post(hass, aiohttp_client): } }, ) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) await client.post("/api/webhook/post_webhook", data={"hello": "world"}) + await hass.async_block_till_done() assert len(events) == 1 assert events[0].data["hello"] == "yo world" @@ -104,10 +109,12 @@ async def test_webhook_query(hass, aiohttp_client): } }, ) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) await client.post("/api/webhook/query_webhook?hello=world") + await hass.async_block_till_done() assert len(events) == 1 assert events[0].data["hello"] == "yo world" @@ -137,10 +144,12 @@ async def test_webhook_reload(hass, aiohttp_client): } }, ) + await hass.async_block_till_done() client = await aiohttp_client(hass.http.app) await client.post("/api/webhook/post_webhook", data={"hello": "world"}) + await hass.async_block_till_done() assert len(events) == 1 assert events[0].data["hello"] == "yo world" @@ -163,8 +172,10 @@ async def test_webhook_reload(hass, aiohttp_client): "reload", blocking=True, ) + await hass.async_block_till_done() await client.post("/api/webhook/post_webhook", data={"hello": "world"}) + await hass.async_block_till_done() assert len(events) == 2 assert events[1].data["hello"] == "yo2 world" diff --git a/tests/components/websocket_api/test_connection.py b/tests/components/websocket_api/test_connection.py index 5890fc9a2fa..55126ff1333 100644 --- a/tests/components/websocket_api/test_connection.py +++ b/tests/components/websocket_api/test_connection.py @@ -1,4 +1,10 @@ """Test WebSocket Connection class.""" +import asyncio +import logging + +import voluptuous as vol + +from homeassistant import exceptions from homeassistant.components import websocket_api from homeassistant.components.websocket_api import const @@ -20,3 +26,32 @@ async def test_send_big_result(hass, websocket_client): assert msg["type"] == const.TYPE_RESULT assert msg["success"] assert msg["result"] == {"big": "result"} + + +async def test_exception_handling(): + """Test handling of exceptions.""" + send_messages = [] + conn = websocket_api.ActiveConnection( + logging.getLogger(__name__), None, send_messages.append, None, None + ) + + for (exc, code, err) in ( + (exceptions.Unauthorized(), websocket_api.ERR_UNAUTHORIZED, "Unauthorized"), + ( + vol.Invalid("Invalid something"), + websocket_api.ERR_INVALID_FORMAT, + "Invalid something. Got {'id': 5}", + ), + (asyncio.TimeoutError(), websocket_api.ERR_TIMEOUT, "Timeout"), + ( + exceptions.HomeAssistantError("Failed to do X"), + websocket_api.ERR_UNKNOWN_ERROR, + "Failed to do X", + ), + (ValueError("Really bad"), websocket_api.ERR_UNKNOWN_ERROR, "Unknown error"), + ): + send_messages.clear() + conn.async_handle_exception({"id": 5}, exc) + assert len(send_messages) == 1 + assert send_messages[0]["error"]["code"] == code + assert send_messages[0]["error"]["message"] == err diff --git a/tests/components/wilight/conftest.py b/tests/components/wilight/conftest.py new file mode 100644 index 00000000000..a8fd13553dd --- /dev/null +++ b/tests/components/wilight/conftest.py @@ -0,0 +1,2 @@ +"""wilight conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/wled/conftest.py b/tests/components/wled/conftest.py new file mode 100644 index 00000000000..31b71a92f19 --- /dev/null +++ b/tests/components/wled/conftest.py @@ -0,0 +1,2 @@ +"""wled conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/wled/test_light.py b/tests/components/wled/test_light.py index e2db58b1246..fbcc6ca71b6 100644 --- a/tests/components/wled/test_light.py +++ b/tests/components/wled/test_light.py @@ -23,6 +23,7 @@ from homeassistant.components.wled.const import ( ATTR_SPEED, DOMAIN, SERVICE_EFFECT, + SERVICE_PRESET, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -587,3 +588,46 @@ async def test_effect_service_error( state = hass.states.get("light.wled_rgb_light_segment_0") assert state.state == STATE_ON assert "Invalid response from API" in caplog.text + + +async def test_preset_service( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> None: + """Test the preset service of a WLED light.""" + await init_integration(hass, aioclient_mock) + + with patch("wled.WLED.preset") as light_mock: + await hass.services.async_call( + DOMAIN, + SERVICE_PRESET, + { + ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", + ATTR_PRESET: 1, + }, + blocking=True, + ) + await hass.async_block_till_done() + light_mock.assert_called_once_with( + preset=1, + ) + + +async def test_preset_service_error( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, caplog +) -> None: + """Test error handling of the WLED preset service.""" + aioclient_mock.post("http://192.168.1.123:80/json/state", text="", status=400) + await init_integration(hass, aioclient_mock) + + with patch("homeassistant.components.wled.WLED.update"): + await hass.services.async_call( + DOMAIN, + SERVICE_PRESET, + {ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_PRESET: 1}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get("light.wled_rgb_light_segment_0") + assert state.state == STATE_ON + assert "Invalid response from API" in caplog.text diff --git a/tests/components/workday/test_binary_sensor.py b/tests/components/workday/test_binary_sensor.py index 1c4ebb29b5a..7d50ec2994c 100644 --- a/tests/components/workday/test_binary_sensor.py +++ b/tests/components/workday/test_binary_sensor.py @@ -75,6 +75,16 @@ class TestWorkdaySetup: } } + self.config_remove_holidays = { + "binary_sensor": { + "platform": "workday", + "country": "US", + "workdays": ["mon", "tue", "wed", "thu", "fri"], + "excludes": ["sat", "sun", "holiday"], + "remove_holidays": ["2020-12-25", "2020-11-26"], + } + } + self.config_tomorrow = { "binary_sensor": {"platform": "workday", "country": "DE", "days_offset": 1} } @@ -298,3 +308,15 @@ class TestWorkdaySetup: assert binary_sensor.day_to_string(1) == "tue" assert binary_sensor.day_to_string(7) == "holiday" assert binary_sensor.day_to_string(8) is None + + # Freeze time to test Fri, but remove holiday - December 25, 2020 + @patch(FUNCTION_PATH, return_value=date(2020, 12, 25)) + def test_config_remove_holidays_xmas(self, mock_date): + """Test if removed holidays are reported correctly.""" + with assert_setup_component(1, "binary_sensor"): + setup_component(self.hass, "binary_sensor", self.config_remove_holidays) + + self.hass.start() + + entity = self.hass.states.get("binary_sensor.workday_sensor") + assert entity.state == "on" diff --git a/tests/components/yeelight/__init__.py b/tests/components/yeelight/__init__.py index a2f5b935947..9f811586a77 100644 --- a/tests/components/yeelight/__init__.py +++ b/tests/components/yeelight/__init__.py @@ -1,5 +1,5 @@ """Tests for the Yeelight integration.""" -from yeelight import BulbType +from yeelight import BulbException, BulbType from yeelight.main import _MODEL_SPECS from homeassistant.components.yeelight import ( @@ -8,6 +8,7 @@ from homeassistant.components.yeelight import ( CONF_SAVE_ON_CHANGE, DOMAIN, NIGHTLIGHT_SWITCH_TYPE_LIGHT, + YeelightScanner, ) from homeassistant.const import CONF_DEVICES, CONF_ID, CONF_NAME @@ -27,7 +28,8 @@ CAPABILITIES = { "name": "", } -NAME = f"yeelight_{MODEL}_{ID}" +NAME = "name" +UNIQUE_NAME = f"yeelight_{MODEL}_{ID}" MODULE = "homeassistant.components.yeelight" MODULE_CONFIG_FLOW = f"{MODULE}.config_flow" @@ -53,9 +55,10 @@ PROPERTIES = { "current_brightness": "30", } -ENTITY_BINARY_SENSOR = f"binary_sensor.{NAME}_nightlight" -ENTITY_LIGHT = f"light.{NAME}" -ENTITY_NIGHTLIGHT = f"light.{NAME}_nightlight" +ENTITY_BINARY_SENSOR = f"binary_sensor.{UNIQUE_NAME}_nightlight" +ENTITY_LIGHT = f"light.{UNIQUE_NAME}" +ENTITY_NIGHTLIGHT = f"light.{UNIQUE_NAME}_nightlight" +ENTITY_AMBILIGHT = f"light.{UNIQUE_NAME}_ambilight" YAML_CONFIGURATION = { DOMAIN: { @@ -80,6 +83,9 @@ def _mocked_bulb(cannot_connect=False): type(bulb).get_capabilities = MagicMock( return_value=None if cannot_connect else CAPABILITIES ) + type(bulb).get_properties = MagicMock( + side_effect=BulbException if cannot_connect else None + ) type(bulb).get_model_specs = MagicMock(return_value=_MODEL_SPECS[MODEL]) bulb.capabilities = CAPABILITIES @@ -92,6 +98,8 @@ def _mocked_bulb(cannot_connect=False): def _patch_discovery(prefix, no_device=False): + YeelightScanner._scanner = None # Clear class scanner to reset hass + def _mocked_discovery(timeout=2, interface=False): if no_device: return [] diff --git a/tests/components/yeelight/conftest.py b/tests/components/yeelight/conftest.py new file mode 100644 index 00000000000..3e65a60f374 --- /dev/null +++ b/tests/components/yeelight/conftest.py @@ -0,0 +1,2 @@ +"""yeelight conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/yeelight/test_binary_sensor.py b/tests/components/yeelight/test_binary_sensor.py index b3281168077..8b2ec835722 100644 --- a/tests/components/yeelight/test_binary_sensor.py +++ b/tests/components/yeelight/test_binary_sensor.py @@ -4,10 +4,12 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_component from homeassistant.setup import async_setup_component -from . import ENTITY_BINARY_SENSOR, MODULE, PROPERTIES, YAML_CONFIGURATION, _mocked_bulb +from . import MODULE, NAME, PROPERTIES, YAML_CONFIGURATION, _mocked_bulb from tests.async_mock import patch +ENTITY_BINARY_SENSOR = f"binary_sensor.{NAME}_nightlight" + async def test_nightlight(hass: HomeAssistant): """Test nightlight sensor.""" diff --git a/tests/components/yeelight/test_config_flow.py b/tests/components/yeelight/test_config_flow.py index 921011a510d..10191a5f6c7 100644 --- a/tests/components/yeelight/test_config_flow.py +++ b/tests/components/yeelight/test_config_flow.py @@ -25,6 +25,7 @@ from . import ( MODULE, MODULE_CONFIG_FLOW, NAME, + UNIQUE_NAME, _mocked_bulb, _patch_discovery, ) @@ -33,7 +34,6 @@ from tests.async_mock import MagicMock, patch from tests.common import MockConfigEntry DEFAULT_CONFIG = { - CONF_NAME: NAME, CONF_MODEL: "", CONF_TRANSITION: DEFAULT_TRANSITION, CONF_MODE_MUSIC: DEFAULT_MODE_MUSIC, @@ -67,9 +67,8 @@ async def test_discovery(hass: HomeAssistant): result3 = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_DEVICE: ID} ) - assert result3["type"] == "create_entry" - assert result3["title"] == NAME + assert result3["title"] == UNIQUE_NAME assert result3["data"] == {CONF_ID: ID} await hass.async_block_till_done() mock_setup.assert_called_once() @@ -126,6 +125,7 @@ async def test_import(hass: HomeAssistant): DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=config ) type(mocked_bulb).get_capabilities.assert_called_once() + type(mocked_bulb).get_properties.assert_called_once() assert result["type"] == "abort" assert result["reason"] == "cannot_connect" @@ -203,7 +203,9 @@ async def test_manual(hass: HomeAssistant): result4 = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_HOST: IP_ADDRESS} ) + await hass.async_block_till_done() assert result4["type"] == "create_entry" + assert result4["title"] == IP_ADDRESS assert result4["data"] == {CONF_HOST: IP_ADDRESS} # Duplicate @@ -221,7 +223,9 @@ async def test_manual(hass: HomeAssistant): async def test_options(hass: HomeAssistant): """Test options flow.""" - config_entry = MockConfigEntry(domain=DOMAIN, data={CONF_HOST: IP_ADDRESS}) + config_entry = MockConfigEntry( + domain=DOMAIN, data={CONF_HOST: IP_ADDRESS, CONF_NAME: NAME} + ) config_entry.add_to_hass(hass) mocked_bulb = _mocked_bulb() @@ -230,16 +234,14 @@ async def test_options(hass: HomeAssistant): await hass.async_block_till_done() config = { + CONF_NAME: NAME, CONF_MODEL: "", CONF_TRANSITION: DEFAULT_TRANSITION, CONF_MODE_MUSIC: DEFAULT_MODE_MUSIC, CONF_SAVE_ON_CHANGE: DEFAULT_SAVE_ON_CHANGE, CONF_NIGHTLIGHT_SWITCH: DEFAULT_NIGHTLIGHT_SWITCH, } - assert config_entry.options == { - CONF_NAME: "", - **config, - } + assert config_entry.options == config assert hass.states.get(f"light.{NAME}_nightlight") is None result = await hass.config_entries.options.async_init(config_entry.entry_id) @@ -247,15 +249,40 @@ async def test_options(hass: HomeAssistant): assert result["step_id"] == "init" config[CONF_NIGHTLIGHT_SWITCH] = True + user_input = {**config} + user_input.pop(CONF_NAME) with patch(f"{MODULE}.Bulb", return_value=mocked_bulb): result2 = await hass.config_entries.options.async_configure( - result["flow_id"], config + result["flow_id"], user_input ) await hass.async_block_till_done() assert result2["type"] == "create_entry" - assert result2["data"] == { - CONF_NAME: "", - **config, - } + assert result2["data"] == config assert result2["data"] == config_entry.options assert hass.states.get(f"light.{NAME}_nightlight") is not None + + +async def test_manual_no_capabilities(hass: HomeAssistant): + """Test manually setup without successful get_capabilities.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + assert result["type"] == "form" + assert result["step_id"] == "user" + assert not result["errors"] + + mocked_bulb = _mocked_bulb() + type(mocked_bulb).get_capabilities = MagicMock(return_value=None) + with patch(f"{MODULE_CONFIG_FLOW}.yeelight.Bulb", return_value=mocked_bulb), patch( + f"{MODULE}.async_setup", return_value=True + ), patch( + f"{MODULE}.async_setup_entry", + return_value=True, + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_HOST: IP_ADDRESS} + ) + type(mocked_bulb).get_capabilities.assert_called_once() + type(mocked_bulb).get_properties.assert_called_once() + assert result["type"] == "create_entry" + assert result["data"] == {CONF_HOST: IP_ADDRESS} diff --git a/tests/components/yeelight/test_init.py b/tests/components/yeelight/test_init.py index 004efed8deb..d9c23cfa1a7 100644 --- a/tests/components/yeelight/test_init.py +++ b/tests/components/yeelight/test_init.py @@ -1,19 +1,27 @@ """Test Yeelight.""" +from yeelight import BulbType + from homeassistant.components.yeelight import ( + CONF_NIGHTLIGHT_SWITCH, CONF_NIGHTLIGHT_SWITCH_TYPE, DOMAIN, NIGHTLIGHT_SWITCH_TYPE_LIGHT, ) from homeassistant.const import CONF_DEVICES, CONF_NAME from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry from homeassistant.setup import async_setup_component from . import ( CONFIG_ENTRY_DATA, + ENTITY_AMBILIGHT, + ENTITY_BINARY_SENSOR, + ENTITY_LIGHT, + ENTITY_NIGHTLIGHT, + ID, IP_ADDRESS, MODULE, MODULE_CONFIG_FLOW, - NAME, _mocked_bulb, _patch_discovery, ) @@ -32,13 +40,13 @@ async def test_setup_discovery(hass: HomeAssistant): assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() - assert hass.states.get(f"binary_sensor.{NAME}_nightlight") is not None - assert hass.states.get(f"light.{NAME}") is not None + assert hass.states.get(ENTITY_BINARY_SENSOR) is not None + assert hass.states.get(ENTITY_LIGHT) is not None # Unload assert await hass.config_entries.async_unload(config_entry.entry_id) - assert hass.states.get(f"binary_sensor.{NAME}_nightlight") is None - assert hass.states.get(f"light.{NAME}") is None + assert hass.states.get(ENTITY_BINARY_SENSOR) is None + assert hass.states.get(ENTITY_LIGHT) is None async def test_setup_import(hass: HomeAssistant): @@ -67,3 +75,60 @@ async def test_setup_import(hass: HomeAssistant): assert hass.states.get(f"binary_sensor.{name}_nightlight") is not None assert hass.states.get(f"light.{name}") is not None assert hass.states.get(f"light.{name}_nightlight") is not None + + +async def test_unique_ids_device(hass: HomeAssistant): + """Test Yeelight unique IDs from yeelight device IDs.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + data={ + **CONFIG_ENTRY_DATA, + CONF_NIGHTLIGHT_SWITCH: True, + }, + unique_id=ID, + ) + config_entry.add_to_hass(hass) + + mocked_bulb = _mocked_bulb() + mocked_bulb.bulb_type = BulbType.WhiteTempMood + with _patch_discovery(MODULE), patch(f"{MODULE}.Bulb", return_value=mocked_bulb): + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + er = await entity_registry.async_get_registry(hass) + assert er.async_get(ENTITY_BINARY_SENSOR).unique_id == f"{ID}-nightlight_sensor" + assert er.async_get(ENTITY_LIGHT).unique_id == ID + assert er.async_get(ENTITY_NIGHTLIGHT).unique_id == f"{ID}-nightlight" + assert er.async_get(ENTITY_AMBILIGHT).unique_id == f"{ID}-ambilight" + + +async def test_unique_ids_entry(hass: HomeAssistant): + """Test Yeelight unique IDs from entry IDs.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + data={ + **CONFIG_ENTRY_DATA, + CONF_NIGHTLIGHT_SWITCH: True, + }, + ) + config_entry.add_to_hass(hass) + + mocked_bulb = _mocked_bulb() + mocked_bulb.bulb_type = BulbType.WhiteTempMood + with _patch_discovery(MODULE), patch(f"{MODULE}.Bulb", return_value=mocked_bulb): + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + er = await entity_registry.async_get_registry(hass) + assert ( + er.async_get(ENTITY_BINARY_SENSOR).unique_id + == f"{config_entry.entry_id}-nightlight_sensor" + ) + assert er.async_get(ENTITY_LIGHT).unique_id == config_entry.entry_id + assert ( + er.async_get(ENTITY_NIGHTLIGHT).unique_id + == f"{config_entry.entry_id}-nightlight" + ) + assert ( + er.async_get(ENTITY_AMBILIGHT).unique_id == f"{config_entry.entry_id}-ambilight" + ) diff --git a/tests/components/yeelight/test_light.py b/tests/components/yeelight/test_light.py index 8e8916ce303..e6fe16255eb 100644 --- a/tests/components/yeelight/test_light.py +++ b/tests/components/yeelight/test_light.py @@ -71,8 +71,9 @@ from homeassistant.components.yeelight.light import ( YEELIGHT_MONO_EFFECT_LIST, YEELIGHT_TEMP_ONLY_EFFECT_LIST, ) -from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, CONF_ID, CONF_NAME +from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, CONF_NAME from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry from homeassistant.setup import async_setup_component from homeassistant.util.color import ( color_hs_to_RGB, @@ -90,6 +91,7 @@ from . import ( MODULE, NAME, PROPERTIES, + UNIQUE_NAME, _mocked_bulb, _patch_discovery, ) @@ -97,15 +99,21 @@ from . import ( from tests.async_mock import MagicMock, patch from tests.common import MockConfigEntry +CONFIG_ENTRY_DATA = { + CONF_HOST: IP_ADDRESS, + CONF_TRANSITION: DEFAULT_TRANSITION, + CONF_MODE_MUSIC: DEFAULT_MODE_MUSIC, + CONF_SAVE_ON_CHANGE: DEFAULT_SAVE_ON_CHANGE, + CONF_NIGHTLIGHT_SWITCH: DEFAULT_NIGHTLIGHT_SWITCH, +} + async def test_services(hass: HomeAssistant, caplog): """Test Yeelight services.""" config_entry = MockConfigEntry( domain=DOMAIN, data={ - CONF_ID: "", - CONF_HOST: IP_ADDRESS, - CONF_TRANSITION: DEFAULT_TRANSITION, + **CONFIG_ENTRY_DATA, CONF_MODE_MUSIC: True, CONF_SAVE_ON_CHANGE: True, CONF_NIGHTLIGHT_SWITCH: True, @@ -299,17 +307,13 @@ async def test_device_types(hass: HomeAssistant): model, target_properties, nightlight_properties=None, - name=NAME, + name=UNIQUE_NAME, entity_id=ENTITY_LIGHT, ): config_entry = MockConfigEntry( domain=DOMAIN, data={ - CONF_ID: "", - CONF_HOST: IP_ADDRESS, - CONF_TRANSITION: DEFAULT_TRANSITION, - CONF_MODE_MUSIC: DEFAULT_MODE_MUSIC, - CONF_SAVE_ON_CHANGE: DEFAULT_SAVE_ON_CHANGE, + **CONFIG_ENTRY_DATA, CONF_NIGHTLIGHT_SWITCH: False, }, ) @@ -329,6 +333,8 @@ async def test_device_types(hass: HomeAssistant): await hass.config_entries.async_unload(config_entry.entry_id) await config_entry.async_remove(hass) + registry = await entity_registry.async_get_registry(hass) + registry.async_clear_config_entry(config_entry.entry_id) # nightlight if nightlight_properties is None: @@ -336,11 +342,7 @@ async def test_device_types(hass: HomeAssistant): config_entry = MockConfigEntry( domain=DOMAIN, data={ - CONF_ID: "", - CONF_HOST: IP_ADDRESS, - CONF_TRANSITION: DEFAULT_TRANSITION, - CONF_MODE_MUSIC: DEFAULT_MODE_MUSIC, - CONF_SAVE_ON_CHANGE: DEFAULT_SAVE_ON_CHANGE, + **CONFIG_ENTRY_DATA, CONF_NIGHTLIGHT_SWITCH: True, }, ) @@ -358,6 +360,7 @@ async def test_device_types(hass: HomeAssistant): await hass.config_entries.async_unload(config_entry.entry_id) await config_entry.async_remove(hass) + registry.async_clear_config_entry(config_entry.entry_id) bright = round(255 * int(PROPERTIES["bright"]) / 100) current_brightness = round(255 * int(PROPERTIES["current_brightness"]) / 100) @@ -486,7 +489,7 @@ async def test_device_types(hass: HomeAssistant): "rgb_color": bg_rgb_color, "xy_color": bg_xy_color, }, - name=f"{NAME} ambilight", + name=f"{UNIQUE_NAME} ambilight", entity_id=f"{ENTITY_LIGHT}_ambilight", ) @@ -518,14 +521,7 @@ async def test_effects(hass: HomeAssistant): config_entry = MockConfigEntry( domain=DOMAIN, - data={ - CONF_ID: "", - CONF_HOST: IP_ADDRESS, - CONF_TRANSITION: DEFAULT_TRANSITION, - CONF_MODE_MUSIC: DEFAULT_MODE_MUSIC, - CONF_SAVE_ON_CHANGE: DEFAULT_SAVE_ON_CHANGE, - CONF_NIGHTLIGHT_SWITCH: DEFAULT_NIGHTLIGHT_SWITCH, - }, + data=CONFIG_ENTRY_DATA, ) config_entry.add_to_hass(hass) diff --git a/tests/components/zerproc/conftest.py b/tests/components/zerproc/conftest.py new file mode 100644 index 00000000000..b4c35bebc71 --- /dev/null +++ b/tests/components/zerproc/conftest.py @@ -0,0 +1,2 @@ +"""zerproc conftest.""" +from tests.components.light.conftest import mock_light_profiles # noqa diff --git a/tests/components/zerproc/test_config_flow.py b/tests/components/zerproc/test_config_flow.py index 9ffafca76db..1a607bb8c9c 100644 --- a/tests/components/zerproc/test_config_flow.py +++ b/tests/components/zerproc/test_config_flow.py @@ -29,12 +29,12 @@ async def test_flow_success(hass): result["flow_id"], {}, ) + await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "Zerproc" assert result2["data"] == {} - await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/zerproc/test_light.py b/tests/components/zerproc/test_light.py index 6d2598ae5a6..871f91d447c 100644 --- a/tests/components/zerproc/test_light.py +++ b/tests/components/zerproc/test_light.py @@ -16,6 +16,7 @@ from homeassistant.components.zerproc.light import DOMAIN from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, + ATTR_ICON, ATTR_SUPPORTED_FEATURES, STATE_OFF, STATE_ON, @@ -82,6 +83,7 @@ async def test_init(hass): assert state.attributes == { ATTR_FRIENDLY_NAME: "LEDBlue-CCDDEEFF", ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS | SUPPORT_COLOR, + ATTR_ICON: "mdi:string-lights", } state = hass.states.get("light.ledblue_33445566") @@ -89,6 +91,7 @@ async def test_init(hass): assert state.attributes == { ATTR_FRIENDLY_NAME: "LEDBlue-33445566", ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS | SUPPORT_COLOR, + ATTR_ICON: "mdi:string-lights", ATTR_BRIGHTNESS: 255, ATTR_HS_COLOR: (221.176, 100.0), ATTR_RGB_COLOR: (0, 80, 255), @@ -260,6 +263,7 @@ async def test_light_update(hass, mock_light): assert state.attributes == { ATTR_FRIENDLY_NAME: "LEDBlue-CCDDEEFF", ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS | SUPPORT_COLOR, + ATTR_ICON: "mdi:string-lights", } # Make sure no discovery calls are made while we emulate time passing @@ -277,6 +281,7 @@ async def test_light_update(hass, mock_light): assert state.attributes == { ATTR_FRIENDLY_NAME: "LEDBlue-CCDDEEFF", ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS | SUPPORT_COLOR, + ATTR_ICON: "mdi:string-lights", } with patch.object( @@ -293,6 +298,7 @@ async def test_light_update(hass, mock_light): assert state.attributes == { ATTR_FRIENDLY_NAME: "LEDBlue-CCDDEEFF", ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS | SUPPORT_COLOR, + ATTR_ICON: "mdi:string-lights", } with patch.object( @@ -309,6 +315,7 @@ async def test_light_update(hass, mock_light): assert state.attributes == { ATTR_FRIENDLY_NAME: "LEDBlue-CCDDEEFF", ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS | SUPPORT_COLOR, + ATTR_ICON: "mdi:string-lights", ATTR_BRIGHTNESS: 220, ATTR_HS_COLOR: (261.429, 31.818), ATTR_RGB_COLOR: (202, 173, 255), diff --git a/tests/components/zha/conftest.py b/tests/components/zha/conftest.py index a5aa330a813..2a2ea6a1bb0 100644 --- a/tests/components/zha/conftest.py +++ b/tests/components/zha/conftest.py @@ -1,5 +1,4 @@ """Test configuration for the ZHA component.""" - import pytest import zigpy from zigpy.application import ControllerApplication @@ -16,6 +15,7 @@ from .common import FakeDevice, FakeEndpoint, get_zha_gateway from tests.async_mock import AsyncMock, MagicMock, PropertyMock, patch from tests.common import MockConfigEntry +from tests.components.light.conftest import mock_light_profiles # noqa FIXTURE_GRP_ID = 0x1001 FIXTURE_GRP_NAME = "fixture group" diff --git a/tests/components/zha/test_channels.py b/tests/components/zha/test_channels.py index 8a6d934d373..afae1b661ab 100644 --- a/tests/components/zha/test_channels.py +++ b/tests/components/zha/test_channels.py @@ -15,6 +15,7 @@ import homeassistant.components.zha.core.registries as registries from .common import get_zha_gateway, make_zcl_header import tests.async_mock +from tests.common import async_capture_events @pytest.fixture @@ -451,10 +452,7 @@ async def test_poll_control_cluster_command(hass, poll_control_device): checkin_mock = tests.async_mock.AsyncMock() poll_control_ch = poll_control_device.channels.pools[0].all_channels["1:0x0020"] cluster = poll_control_ch.cluster - - events = [] - hass.bus.async_listen("zha_event", lambda x: events.append(x)) - await hass.async_block_till_done() + events = async_capture_events(hass, "zha_event") with mock.patch.object(poll_control_ch, "check_in_response", checkin_mock): tsn = 22 @@ -475,3 +473,4 @@ async def test_poll_control_cluster_command(hass, poll_control_device): assert data["args"][1] is mock.sentinel.args2 assert data["args"][2] is mock.sentinel.args3 assert data["unique_id"] == "00:11:22:33:44:55:66:77:1:0x0020" + assert data["device_id"] == poll_control_device.device_id diff --git a/tests/components/zwave/conftest.py b/tests/components/zwave/conftest.py index 146347620bd..5366f028328 100644 --- a/tests/components/zwave/conftest.py +++ b/tests/components/zwave/conftest.py @@ -4,6 +4,7 @@ import pytest from homeassistant.components.zwave import const from tests.async_mock import AsyncMock, MagicMock, patch +from tests.components.light.conftest import mock_light_profiles # noqa from tests.mock.zwave import MockNetwork, MockNode, MockOption, MockValue diff --git a/tests/fixtures/blueprint/community_post.json b/tests/fixtures/blueprint/community_post.json new file mode 100644 index 00000000000..28684ec65f7 --- /dev/null +++ b/tests/fixtures/blueprint/community_post.json @@ -0,0 +1,783 @@ +{ + "post_stream": { + "posts": [ + { + "id": 1144853, + "name": "Paulus Schoutsen", + "username": "balloob", + "avatar_template": "/user_avatar/community.home-assistant.io/balloob/{size}/21956_2.png", + "created_at": "2020-10-16T12:20:12.688Z", + "cooked": "\u003cp\u003ehere a test topic.\u003cbr\u003e\nhere a test topic.\u003cbr\u003e\nhere a test topic.\u003cbr\u003e\nhere a test topic.\u003c/p\u003e\n\u003ch1\u003eBlock without syntax\u003c/h1\u003e\n\u003cpre\u003e\u003ccode class=\"lang-auto\"\u003eblueprint:\n domain: automation\n name: Example Blueprint from post\n input:\n trigger_event:\n service_to_call:\ntrigger:\n platform: event\n event_type: !placeholder trigger_event\naction:\n service: !placeholder service_to_call\n\u003c/code\u003e\u003c/pre\u003e", + "post_number": 1, + "post_type": 1, + "updated_at": "2020-10-20T08:24:14.189Z", + "reply_count": 0, + "reply_to_post_number": null, + "quote_count": 0, + "incoming_link_count": 0, + "reads": 2, + "readers_count": 1, + "score": 0.4, + "yours": true, + "topic_id": 236133, + "topic_slug": "test-topic", + "display_username": "Paulus Schoutsen", + "primary_group_name": null, + "primary_group_flair_url": null, + "primary_group_flair_bg_color": null, + "primary_group_flair_color": null, + "version": 2, + "can_edit": true, + "can_delete": false, + "can_recover": false, + "can_wiki": true, + "read": true, + "user_title": "Founder of Home Assistant", + "title_is_group": false, + "actions_summary": [ + { + "id": 3, + "can_act": true + }, + { + "id": 4, + "can_act": true + }, + { + "id": 8, + "can_act": true + }, + { + "id": 7, + "can_act": true + } + ], + "moderator": true, + "admin": true, + "staff": true, + "user_id": 3, + "hidden": false, + "trust_level": 2, + "deleted_at": null, + "user_deleted": false, + "edit_reason": null, + "can_view_edit_history": true, + "wiki": false, + "reviewable_id": 0, + "reviewable_score_count": 0, + "reviewable_score_pending_count": 0, + "user_created_at": "2016-03-30T07:50:25.541Z", + "user_date_of_birth": null, + "user_signature": null, + "can_accept_answer": false, + "can_unaccept_answer": false, + "accepted_answer": false + }, + { + "id": 1144854, + "name": "Paulus Schoutsen", + "username": "balloob", + "avatar_template": "/user_avatar/community.home-assistant.io/balloob/{size}/21956_2.png", + "created_at": "2020-10-16T12:20:17.535Z", + "cooked": "", + "post_number": 2, + "post_type": 3, + "updated_at": "2020-10-16T12:20:17.535Z", + "reply_count": 0, + "reply_to_post_number": null, + "quote_count": 0, + "incoming_link_count": 1, + "reads": 2, + "readers_count": 1, + "score": 5.4, + "yours": true, + "topic_id": 236133, + "topic_slug": "test-topic", + "display_username": "Paulus Schoutsen", + "primary_group_name": null, + "primary_group_flair_url": null, + "primary_group_flair_bg_color": null, + "primary_group_flair_color": null, + "version": 1, + "can_edit": true, + "can_delete": true, + "can_recover": false, + "can_wiki": true, + "read": true, + "user_title": "Founder of Home Assistant", + "title_is_group": false, + "actions_summary": [ + { + "id": 3, + "can_act": true + }, + { + "id": 4, + "can_act": true + }, + { + "id": 8, + "can_act": true + }, + { + "id": 7, + "can_act": true + } + ], + "moderator": true, + "admin": true, + "staff": true, + "user_id": 3, + "hidden": false, + "trust_level": 2, + "deleted_at": null, + "user_deleted": false, + "edit_reason": null, + "can_view_edit_history": true, + "wiki": false, + "action_code": "visible.disabled", + "reviewable_id": 0, + "reviewable_score_count": 0, + "reviewable_score_pending_count": 0, + "user_created_at": "2016-03-30T07:50:25.541Z", + "user_date_of_birth": null, + "user_signature": null, + "can_accept_answer": false, + "can_unaccept_answer": false, + "accepted_answer": false + }, + { + "id": 1144872, + "name": "Paulus Schoutsen", + "username": "balloob", + "avatar_template": "/user_avatar/community.home-assistant.io/balloob/{size}/21956_2.png", + "created_at": "2020-10-16T12:27:53.926Z", + "cooked": "\u003cp\u003eTest reply!\u003c/p\u003e", + "post_number": 3, + "post_type": 1, + "updated_at": "2020-10-16T12:27:53.926Z", + "reply_count": 0, + "reply_to_post_number": null, + "quote_count": 0, + "incoming_link_count": 0, + "reads": 2, + "readers_count": 1, + "score": 0.4, + "yours": true, + "topic_id": 236133, + "topic_slug": "test-topic", + "display_username": "Paulus Schoutsen", + "primary_group_name": null, + "primary_group_flair_url": null, + "primary_group_flair_bg_color": null, + "primary_group_flair_color": null, + "version": 1, + "can_edit": true, + "can_delete": true, + "can_recover": false, + "can_wiki": true, + "read": true, + "user_title": "Founder of Home Assistant", + "title_is_group": false, + "actions_summary": [ + { + "id": 3, + "can_act": true + }, + { + "id": 4, + "can_act": true + }, + { + "id": 8, + "can_act": true + }, + { + "id": 7, + "can_act": true + } + ], + "moderator": true, + "admin": true, + "staff": true, + "user_id": 3, + "hidden": false, + "trust_level": 2, + "deleted_at": null, + "user_deleted": false, + "edit_reason": null, + "can_view_edit_history": true, + "wiki": false, + "reviewable_id": 0, + "reviewable_score_count": 0, + "reviewable_score_pending_count": 0, + "user_created_at": "2016-03-30T07:50:25.541Z", + "user_date_of_birth": null, + "user_signature": null, + "can_accept_answer": false, + "can_unaccept_answer": false, + "accepted_answer": false + } + ], + "stream": [ + 1144853, + 1144854, + 1144872 + ] + }, + "timeline_lookup": [ + [ + 1, + 3 + ] + ], + "suggested_topics": [ + { + "id": 17750, + "title": "Tutorial: Creating your first add-on", + "fancy_title": "Tutorial: Creating your first add-on", + "slug": "tutorial-creating-your-first-add-on", + "posts_count": 26, + "reply_count": 14, + "highest_post_number": 27, + "image_url": null, + "created_at": "2017-05-14T07:51:33.946Z", + "last_posted_at": "2020-07-28T11:29:27.892Z", + "bumped": true, + "bumped_at": "2020-07-28T11:29:27.892Z", + "archetype": "regular", + "unseen": false, + "last_read_post_number": 18, + "unread": 7, + "new_posts": 2, + "pinned": false, + "unpinned": null, + "visible": true, + "closed": false, + "archived": false, + "notification_level": 2, + "bookmarked": false, + "liked": false, + "thumbnails": null, + "tags": [], + "like_count": 9, + "views": 4355, + "category_id": 25, + "featured_link": null, + "has_accepted_answer": false, + "posters": [ + { + "extras": null, + "description": "Original Poster", + "user": { + "id": 3, + "username": "balloob", + "name": "Paulus Schoutsen", + "avatar_template": "/user_avatar/community.home-assistant.io/balloob/{size}/21956_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 9852, + "username": "JSCSJSCS", + "name": "", + "avatar_template": "/user_avatar/community.home-assistant.io/jscsjscs/{size}/38256_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 11494, + "username": "so3n", + "name": "", + "avatar_template": "/user_avatar/community.home-assistant.io/so3n/{size}/46007_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 9094, + "username": "IoTnerd", + "name": "Balázs Suhajda", + "avatar_template": "/user_avatar/community.home-assistant.io/iotnerd/{size}/33526_2.png" + } + }, + { + "extras": "latest", + "description": "Most Recent Poster", + "user": { + "id": 73134, + "username": "diord", + "name": "", + "avatar_template": "/letter_avatar/diord/{size}/5_70a404e2c8e633b245e797a566d32dc7.png" + } + } + ] + }, + { + "id": 65981, + "title": "Lovelace: Button card", + "fancy_title": "Lovelace: Button card", + "slug": "lovelace-button-card", + "posts_count": 4608, + "reply_count": 3522, + "highest_post_number": 4691, + "image_url": null, + "created_at": "2018-08-28T00:18:19.312Z", + "last_posted_at": "2020-10-20T07:33:29.523Z", + "bumped": true, + "bumped_at": "2020-10-20T07:33:29.523Z", + "archetype": "regular", + "unseen": false, + "last_read_post_number": 1938, + "unread": 369, + "new_posts": 2384, + "pinned": false, + "unpinned": null, + "visible": true, + "closed": false, + "archived": false, + "notification_level": 2, + "bookmarked": false, + "liked": false, + "thumbnails": null, + "tags": [], + "like_count": 1700, + "views": 184752, + "category_id": 34, + "featured_link": null, + "has_accepted_answer": false, + "posters": [ + { + "extras": null, + "description": "Original Poster", + "user": { + "id": 25984, + "username": "kuuji", + "name": "Alexandre", + "avatar_template": "/user_avatar/community.home-assistant.io/kuuji/{size}/41093_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 2019, + "username": "iantrich", + "name": "Ian", + "avatar_template": "/user_avatar/community.home-assistant.io/iantrich/{size}/154042_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 33228, + "username": "jimz011", + "name": "Jim", + "avatar_template": "/user_avatar/community.home-assistant.io/jimz011/{size}/62413_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 4931, + "username": "petro", + "name": "Petro", + "avatar_template": "/user_avatar/community.home-assistant.io/petro/{size}/47791_2.png" + } + }, + { + "extras": "latest", + "description": "Most Recent Poster", + "user": { + "id": 26227, + "username": "RomRider", + "name": "", + "avatar_template": "/user_avatar/community.home-assistant.io/romrider/{size}/41384_2.png" + } + } + ] + }, + { + "id": 10564, + "title": "Professional/Commercial Use?", + "fancy_title": "Professional/Commercial Use?", + "slug": "professional-commercial-use", + "posts_count": 54, + "reply_count": 37, + "highest_post_number": 54, + "image_url": null, + "created_at": "2017-01-27T05:01:57.453Z", + "last_posted_at": "2020-10-20T07:03:57.895Z", + "bumped": true, + "bumped_at": "2020-10-20T07:03:57.895Z", + "archetype": "regular", + "unseen": false, + "last_read_post_number": 7, + "unread": 0, + "new_posts": 47, + "pinned": false, + "unpinned": null, + "visible": true, + "closed": false, + "archived": false, + "notification_level": 2, + "bookmarked": false, + "liked": false, + "thumbnails": null, + "tags": [], + "like_count": 21, + "views": 10695, + "category_id": 17, + "featured_link": null, + "has_accepted_answer": false, + "posters": [ + { + "extras": null, + "description": "Original Poster", + "user": { + "id": 4758, + "username": "oobie11", + "name": "Bryan", + "avatar_template": "/user_avatar/community.home-assistant.io/oobie11/{size}/37858_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 18386, + "username": "pitp2", + "name": "", + "avatar_template": "/letter_avatar/pitp2/{size}/5_70a404e2c8e633b245e797a566d32dc7.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 23116, + "username": "jortegamx", + "name": "Jake", + "avatar_template": "/user_avatar/community.home-assistant.io/jortegamx/{size}/45515_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 39038, + "username": "orif73", + "name": "orif73", + "avatar_template": "/letter_avatar/orif73/{size}/5_70a404e2c8e633b245e797a566d32dc7.png" + } + }, + { + "extras": "latest", + "description": "Most Recent Poster", + "user": { + "id": 41040, + "username": "devastator", + "name": "", + "avatar_template": "/letter_avatar/devastator/{size}/5_70a404e2c8e633b245e797a566d32dc7.png" + } + } + ] + }, + { + "id": 219480, + "title": "What the heck is with the 'latest state change' not being kept after restart?", + "fancy_title": "What the heck is with the \u0026lsquo;latest state change\u0026rsquo; not being kept after restart?", + "slug": "what-the-heck-is-with-the-latest-state-change-not-being-kept-after-restart", + "posts_count": 37, + "reply_count": 13, + "highest_post_number": 38, + "image_url": "https://community-assets.home-assistant.io/original/3X/3/4/349d096b209d40d5f424b64e970bcf360332cc7f.png", + "created_at": "2020-08-18T13:10:09.367Z", + "last_posted_at": "2020-10-20T00:32:07.312Z", + "bumped": true, + "bumped_at": "2020-10-20T00:32:07.312Z", + "archetype": "regular", + "unseen": false, + "last_read_post_number": 8, + "unread": 0, + "new_posts": 30, + "pinned": false, + "unpinned": null, + "visible": true, + "closed": false, + "archived": false, + "notification_level": 2, + "bookmarked": false, + "liked": false, + "thumbnails": [ + { + "max_width": null, + "max_height": null, + "width": 469, + "height": 59, + "url": "https://community-assets.home-assistant.io/original/3X/3/4/349d096b209d40d5f424b64e970bcf360332cc7f.png" + } + ], + "tags": [], + "like_count": 26, + "views": 1722, + "category_id": 52, + "featured_link": null, + "has_accepted_answer": false, + "posters": [ + { + "extras": null, + "description": "Original Poster", + "user": { + "id": 3124, + "username": "andriej", + "name": "", + "avatar_template": "/user_avatar/community.home-assistant.io/andriej/{size}/24457_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 15052, + "username": "Misiu", + "name": "", + "avatar_template": "/user_avatar/community.home-assistant.io/misiu/{size}/20752_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 4629, + "username": "lolouk44", + "name": "lolouk44", + "avatar_template": "/user_avatar/community.home-assistant.io/lolouk44/{size}/119845_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 51736, + "username": "hmoffatt", + "name": "Hamish Moffatt", + "avatar_template": "/user_avatar/community.home-assistant.io/hmoffatt/{size}/88700_2.png" + } + }, + { + "extras": "latest", + "description": "Most Recent Poster", + "user": { + "id": 78711, + "username": "Astrosteve", + "name": "Steve", + "avatar_template": "/letter_avatar/astrosteve/{size}/5_70a404e2c8e633b245e797a566d32dc7.png" + } + } + ] + }, + { + "id": 162594, + "title": "A different take on designing a Lovelace UI", + "fancy_title": "A different take on designing a Lovelace UI", + "slug": "a-different-take-on-designing-a-lovelace-ui", + "posts_count": 641, + "reply_count": 425, + "highest_post_number": 654, + "image_url": null, + "created_at": "2020-01-11T23:09:25.207Z", + "last_posted_at": "2020-10-19T23:32:15.555Z", + "bumped": true, + "bumped_at": "2020-10-19T23:32:15.555Z", + "archetype": "regular", + "unseen": false, + "last_read_post_number": 7, + "unread": 32, + "new_posts": 615, + "pinned": false, + "unpinned": null, + "visible": true, + "closed": false, + "archived": false, + "notification_level": 2, + "bookmarked": false, + "liked": false, + "thumbnails": null, + "tags": [], + "like_count": 453, + "views": 68547, + "category_id": 9, + "featured_link": null, + "has_accepted_answer": false, + "posters": [ + { + "extras": null, + "description": "Original Poster", + "user": { + "id": 11256, + "username": "Mattias_Persson", + "name": "Mattias Persson", + "avatar_template": "/user_avatar/community.home-assistant.io/mattias_persson/{size}/14773_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 27634, + "username": "Jason_hill", + "name": "Jason Hill", + "avatar_template": "/user_avatar/community.home-assistant.io/jason_hill/{size}/93218_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 46782, + "username": "Martin_Pejstrup", + "name": "mpejstrup", + "avatar_template": "/user_avatar/community.home-assistant.io/martin_pejstrup/{size}/78412_2.png" + } + }, + { + "extras": null, + "description": "Frequent Poster", + "user": { + "id": 46841, + "username": "spudje", + "name": "", + "avatar_template": "/letter_avatar/spudje/{size}/5_70a404e2c8e633b245e797a566d32dc7.png" + } + }, + { + "extras": "latest", + "description": "Most Recent Poster", + "user": { + "id": 20924, + "username": "Diego_Santos", + "name": "Diego Santos", + "avatar_template": "/user_avatar/community.home-assistant.io/diego_santos/{size}/29096_2.png" + } + } + ] + } + ], + "tags": [], + "id": 236133, + "title": "Test Topic", + "fancy_title": "Test Topic", + "posts_count": 3, + "created_at": "2020-10-16T12:20:12.580Z", + "views": 13, + "reply_count": 0, + "like_count": 0, + "last_posted_at": "2020-10-16T12:27:53.926Z", + "visible": false, + "closed": false, + "archived": false, + "has_summary": false, + "archetype": "regular", + "slug": "test-topic", + "category_id": 1, + "word_count": 37, + "deleted_at": null, + "user_id": 3, + "featured_link": null, + "pinned_globally": false, + "pinned_at": null, + "pinned_until": null, + "image_url": null, + "draft": null, + "draft_key": "topic_236133", + "draft_sequence": 8, + "posted": true, + "unpinned": null, + "pinned": false, + "current_post_number": 1, + "highest_post_number": 3, + "last_read_post_number": 3, + "last_read_post_id": 1144872, + "deleted_by": null, + "has_deleted": false, + "actions_summary": [ + { + "id": 4, + "count": 0, + "hidden": false, + "can_act": true + }, + { + "id": 8, + "count": 0, + "hidden": false, + "can_act": true + }, + { + "id": 7, + "count": 0, + "hidden": false, + "can_act": true + } + ], + "chunk_size": 20, + "bookmarked": false, + "topic_timer": null, + "private_topic_timer": null, + "message_bus_last_id": 5, + "participant_count": 1, + "show_read_indicator": false, + "thumbnails": null, + "can_vote": false, + "vote_count": null, + "user_voted": false, + "details": { + "notification_level": 3, + "notifications_reason_id": 1, + "can_move_posts": true, + "can_edit": true, + "can_delete": true, + "can_remove_allowed_users": true, + "can_invite_to": true, + "can_invite_via_email": true, + "can_create_post": true, + "can_reply_as_new_topic": true, + "can_flag_topic": true, + "can_convert_topic": true, + "can_review_topic": true, + "can_remove_self_id": 3, + "participants": [ + { + "id": 3, + "username": "balloob", + "name": "Paulus Schoutsen", + "avatar_template": "/user_avatar/community.home-assistant.io/balloob/{size}/21956_2.png", + "post_count": 3, + "primary_group_name": null, + "primary_group_flair_url": null, + "primary_group_flair_color": null, + "primary_group_flair_bg_color": null + } + ], + "created_by": { + "id": 3, + "username": "balloob", + "name": "Paulus Schoutsen", + "avatar_template": "/user_avatar/community.home-assistant.io/balloob/{size}/21956_2.png" + }, + "last_poster": { + "id": 3, + "username": "balloob", + "name": "Paulus Schoutsen", + "avatar_template": "/user_avatar/community.home-assistant.io/balloob/{size}/21956_2.png" + } + } +} diff --git a/tests/fixtures/color_extractor_file.txt b/tests/fixtures/color_extractor_file.txt new file mode 100644 index 00000000000..cd3858fda70 --- /dev/null +++ b/tests/fixtures/color_extractor_file.txt @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUZS32JtD5qAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg== \ No newline at end of file diff --git a/tests/fixtures/color_extractor_url.txt b/tests/fixtures/color_extractor_url.txt new file mode 100644 index 00000000000..e6c2856d4c2 --- /dev/null +++ b/tests/fixtures/color_extractor_url.txt @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUyZJaYaJT2AAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg== \ No newline at end of file diff --git a/tests/fixtures/homematicip_cloud.json b/tests/fixtures/homematicip_cloud.json index 4060ca7a820..9c2a1b1e371 100644 --- a/tests/fixtures/homematicip_cloud.json +++ b/tests/fixtures/homematicip_cloud.json @@ -14,6 +14,248 @@ } }, "devices": { + "3014F711A000000BAD0CAAAA": { + "availableFirmwareVersion": "2.2.18", + "connectionType": "HMIP_LAN", + "firmwareVersion": "2.2.18", + "firmwareVersionInteger": 131602, + "functionalChannels": { + "0": { + "accessPointPriority": 0, + "busConfigMismatch": null, + "carrierSenseLevel": 2.0, + "coProFaulty": false, + "coProRestartNeeded": false, + "coProUpdateFailure": false, + "configPending": false, + "deviceId": "3014F711A000000BAD0CAAAA", + "deviceOverheated": false, + "deviceOverloaded": false, + "devicePowerFailureDetected": false, + "deviceUndervoltage": false, + "dutyCycle": false, + "dutyCycleLevel": 8.0, + "functionalChannelType": "ACCESS_CONTROLLER_CHANNEL", + "groupIndex": 0, + "groups": [], + "index": 0, + "label": "", + "lowBat": null, + "multicastRoutingEnabled": false, + "powerShortCircuit": null, + "routerModuleEnabled": false, + "routerModuleSupported": false, + "rssiDeviceValue": null, + "rssiPeerValue": null, + "shortCircuitDataLine": null, + "signalBrightness": 1.0, + "supportedOptionalFeatures": { + "IFeatureBusConfigMismatch": false, + "IFeatureDeviceCoProError": false, + "IFeatureDeviceCoProRestart": false, + "IFeatureDeviceCoProUpdate": false, + "IFeatureDeviceIdentify": false, + "IFeatureDeviceOverheated": false, + "IFeatureDeviceOverloaded": false, + "IFeatureDevicePowerFailure": false, + "IFeatureDeviceTemperatureOutOfRange": false, + "IFeatureDeviceUndervoltage": false, + "IFeatureMulticastRouter": false, + "IFeaturePowerShortCircuit": false, + "IFeatureRssiValue": false, + "IFeatureShortCircuitDataLine": false, + "IOptionalFeatureDutyCycle": true, + "IOptionalFeatureLowBat": false + }, + "temperatureOutOfRange": false, + "unreach": false + } + }, + "homeId": "00000000-0000-0000-0000-000000000001", + "id": "3014F711A000000BAD0CAAAA", + "label": "AP1", + "lastStatusUpdate": 1604522238580, + "liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED", + "manufacturerCode": 1, + "modelId": 270, + "modelType": "HmIP-HAP", + "oem": "eQ-3", + "permanentlyReachable": true, + "serializedGlobalTradeItemNumber": "3014F711A000000BAD0CAAAA", + "type": "HOME_CONTROL_ACCESS_POINT", + "updateState": "BACKGROUND_UPDATE_NOT_SUPPORTED" + }, + "3014F711A000000BAD0C0DED": { + "availableFirmwareVersion": "2.2.18", + "connectionType": "HMIP_LAN", + "firmwareVersion": "2.2.18", + "firmwareVersionInteger": 131602, + "functionalChannels": { + "0": { + "accessPointPriority": 1, + "busConfigMismatch": null, + "carrierSenseLevel": 2.0, + "coProFaulty": false, + "coProRestartNeeded": false, + "coProUpdateFailure": false, + "configPending": false, + "deviceId": "3014F711A000000BAD0C0DED", + "deviceOverheated": false, + "deviceOverloaded": false, + "devicePowerFailureDetected": false, + "deviceUndervoltage": false, + "dutyCycle": false, + "dutyCycleLevel": 8.0, + "functionalChannelType": "ACCESS_CONTROLLER_CHANNEL", + "groupIndex": 0, + "groups": [], + "index": 0, + "label": "", + "lowBat": null, + "multicastRoutingEnabled": false, + "powerShortCircuit": null, + "routerModuleEnabled": false, + "routerModuleSupported": false, + "rssiDeviceValue": null, + "rssiPeerValue": null, + "shortCircuitDataLine": null, + "signalBrightness": 1.0, + "supportedOptionalFeatures": { + "IFeatureBusConfigMismatch": false, + "IFeatureDeviceCoProError": false, + "IFeatureDeviceCoProRestart": false, + "IFeatureDeviceCoProUpdate": false, + "IFeatureDeviceIdentify": false, + "IFeatureDeviceOverheated": false, + "IFeatureDeviceOverloaded": false, + "IFeatureDevicePowerFailure": false, + "IFeatureDeviceTemperatureOutOfRange": false, + "IFeatureDeviceUndervoltage": false, + "IFeatureMulticastRouter": false, + "IFeaturePowerShortCircuit": false, + "IFeatureRssiValue": false, + "IFeatureShortCircuitDataLine": false, + "IOptionalFeatureDutyCycle": true, + "IOptionalFeatureLowBat": false + }, + "temperatureOutOfRange": false, + "unreach": false + } + }, + "homeId": "00000000-0000-0000-0000-000000000001", + "id": "3014F711A000000BAD0C0DED", + "label": "HOME_CONTROL_ACCESS_POINT", + "lastStatusUpdate": 1604522238580, + "liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED", + "manufacturerCode": 1, + "modelId": 270, + "modelType": "HmIP-HAP", + "oem": "eQ-3", + "permanentlyReachable": true, + "serializedGlobalTradeItemNumber": "3014F711A000000BAD0C0DED", + "type": "HOME_CONTROL_ACCESS_POINT", + "updateState": "BACKGROUND_UPDATE_NOT_SUPPORTED" + }, + "3014F71100BLIND_MODULE00": { + "availableFirmwareVersion": "0.0.0", + "connectionType": "HMIP_RF", + "firmwareVersion": "1.0.4", + "firmwareVersionInteger": 65540, + "functionalChannels": { + "0": { + "busConfigMismatch": null, + "coProFaulty": false, + "coProRestartNeeded": false, + "coProUpdateFailure": false, + "configPending": false, + "deviceId": "3014F71100BLIND_MODULE00", + "deviceOverheated": false, + "deviceOverloaded": false, + "devicePowerFailureDetected": false, + "deviceUndervoltage": false, + "dutyCycle": false, + "functionalChannelType": "DEVICE_BASE", + "groupIndex": 0, + "groups": [ + ], + "index": 0, + "label": "", + "lowBat": false, + "multicastRoutingEnabled": false, + "powerShortCircuit": null, + "routerModuleEnabled": false, + "routerModuleSupported": false, + "rssiDeviceValue": -85, + "rssiPeerValue": -78, + "shortCircuitDataLine": null, + "supportedOptionalFeatures": { + "IFeatureBusConfigMismatch": false, + "IFeatureDeviceCoProError": false, + "IFeatureDeviceCoProRestart": false, + "IFeatureDeviceCoProUpdate": false, + "IFeatureDeviceIdentify": false, + "IFeatureDeviceOverheated": false, + "IFeatureDeviceOverloaded": false, + "IFeatureDevicePowerFailure": false, + "IFeatureDeviceTemperatureOutOfRange": false, + "IFeatureDeviceUndervoltage": false, + "IFeatureMulticastRouter": false, + "IFeaturePowerShortCircuit": false, + "IFeatureRssiValue": true, + "IFeatureShortCircuitDataLine": false, + "IOptionalFeatureDutyCycle": true, + "IOptionalFeatureLowBat": true + }, + "temperatureOutOfRange": false, + "unreach": false + }, + "1": { + "automationDriveSpeed": "SLOW_SPEED", + "deviceId": "3014F71100BLIND_MODULE00", + "favoritePrimaryShadingPosition": 0.5, + "favoriteSecondaryShadingPosition": 0.5, + "functionalChannelType": "SHADING_CHANNEL", + "groupIndex": 1, + "groups": [ + ], + "identifyOemSupported": true, + "index": 1, + "label": "", + "manualDriveSpeed": "NOMINAL_SPEED", + "previousPrimaryShadingLevel": null, + "previousSecondaryShadingLevel": null, + "primaryCloseAdjustable": true, + "primaryOpenAdjustable": true, + "primaryShadingLevel": 0.94956, + "primaryShadingStateType": "POSITION_USED", + "processing": false, + "productId": 10, + "profileMode": "AUTOMATIC", + "secondaryCloseAdjustable": false, + "secondaryOpenAdjustable": false, + "secondaryShadingLevel": null, + "secondaryShadingStateType": "NOT_EXISTENT", + "shadingDriveVersion": null, + "shadingPackagePosition": "TOP", + "shadingPositionAdjustmentActive": null, + "shadingPositionAdjustmentClientId": null, + "userDesiredProfileMode": "AUTOMATIC" + } + }, + "homeId": "00000000-0000-0000-0000-000000000001", + "id": "3014F71100BLIND_MODULE00", + "label": "Sonnenschutz Balkont\u00fcr", + "lastStatusUpdate": 1600002124559, + "liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED", + "manufacturerCode": 7, + "modelId": 1, + "modelType": "HmIP-HDM1", + "oem": "HunterDouglas", + "permanentlyReachable": true, + "serializedGlobalTradeItemNumber": "3014F71100BLIND_MODULE00", + "type": "BLIND_MODULE", + "updateState": "UP_TO_DATE" + }, "3014F7110TILTVIBRATIONSENSOR": { "availableFirmwareVersion": "0.0.0", "connectionType": "HMIP_RF", @@ -7307,6 +7549,11 @@ }, "home": { "accessPointUpdateStates": { + "3014F711A000000BAD0CAAAA": { + "accessPointUpdateState": "UP_TO_DATE", + "successfulUpdateTimestamp": 0, + "updateStateChangedTimestamp": 0 + }, "3014F711A000000BAD0C0DED": { "accessPointUpdateState": "UP_TO_DATE", "successfulUpdateTimestamp": 0, @@ -7449,4 +7696,4 @@ "windSpeed": 8.568 } } -} \ No newline at end of file +} diff --git a/tests/fixtures/plugwise/stretch_v31/get_all_devices.json b/tests/fixtures/plugwise/stretch_v31/get_all_devices.json new file mode 100644 index 00000000000..f40e902d5a9 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_all_devices.json @@ -0,0 +1 @@ +{"cfe95cf3de1948c0b8955125bf754614": {"name": "Droger (52559)", "types": {"py/set": ["plug", "power"]}, "class": "dryer", "location": 0}, "aac7b735042c4832ac9ff33aae4f453b": {"name": "Vaatwasser (2a1ab)", "types": {"py/set": ["plug", "power"]}, "class": "dishwasher", "location": 0}, "5871317346d045bc9f6b987ef25ee638": {"name": "Boiler (1EB31)", "types": {"py/set": ["plug", "power"]}, "class": "water_heater_vessel", "location": 0}, "059e4d03c7a34d278add5c7a4a781d19": {"name": "Wasmachine (52AC1)", "types": {"py/set": ["plug", "power"]}, "class": "washingmachine", "location": 0}, "e1c884e7dede431dadee09506ec4f859": {"name": "Koelkast (92C4A)", "types": {"py/set": ["plug", "power"]}, "class": "refrigerator", "location": 0}, "d950b314e9d8499f968e6db8d82ef78c": {"name": "Stroomvreters", "types": {"py/set": ["switch_group"]}, "class": "switching", "members": [], "location": null}} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/059e4d03c7a34d278add5c7a4a781d19.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/059e4d03c7a34d278add5c7a4a781d19.json new file mode 100644 index 00000000000..b08f6d6093a --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/059e4d03c7a34d278add5c7a4a781d19.json @@ -0,0 +1 @@ +{"electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/5871317346d045bc9f6b987ef25ee638.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/5871317346d045bc9f6b987ef25ee638.json new file mode 100644 index 00000000000..529c8b76d95 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/5871317346d045bc9f6b987ef25ee638.json @@ -0,0 +1 @@ +{"electricity_consumed": 1.19, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/aac7b735042c4832ac9ff33aae4f453b.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/aac7b735042c4832ac9ff33aae4f453b.json new file mode 100644 index 00000000000..35ce04f51cf --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/aac7b735042c4832ac9ff33aae4f453b.json @@ -0,0 +1 @@ +{"electricity_consumed": 0.0, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/cfe95cf3de1948c0b8955125bf754614.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/cfe95cf3de1948c0b8955125bf754614.json new file mode 100644 index 00000000000..42de4d3338b --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/cfe95cf3de1948c0b8955125bf754614.json @@ -0,0 +1 @@ +{"electricity_consumed": 0.0, "electricity_consumed_interval": 1.06, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/d950b314e9d8499f968e6db8d82ef78c.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/d950b314e9d8499f968e6db8d82ef78c.json new file mode 100644 index 00000000000..de5baf4c9a6 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/d950b314e9d8499f968e6db8d82ef78c.json @@ -0,0 +1 @@ +{"relay": false} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/e1c884e7dede431dadee09506ec4f859.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/e1c884e7dede431dadee09506ec4f859.json new file mode 100644 index 00000000000..1a7249b68d5 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/e1c884e7dede431dadee09506ec4f859.json @@ -0,0 +1 @@ +{"electricity_consumed": 53.2, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/helpers/test_collection.py b/tests/helpers/test_collection.py index 11f1534defb..d5a8526b6da 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 diff --git a/tests/helpers/test_config_entry_oauth2_flow.py b/tests/helpers/test_config_entry_oauth2_flow.py index 691b2e93d56..7ce71defb7e 100644 --- a/tests/helpers/test_config_entry_oauth2_flow.py +++ b/tests/helpers/test_config_entry_oauth2_flow.py @@ -420,6 +420,94 @@ async def test_oauth_session(hass, flow_handler, local_impl, aioclient_mock): assert round(config_entry.data["token"]["expires_at"] - now) == 100 +async def test_oauth_session_with_clock_slightly_out_of_sync( + hass, flow_handler, local_impl, aioclient_mock +): + """Test the OAuth2 session helper when the remote clock is slightly out of sync.""" + flow_handler.async_register_implementation(hass, local_impl) + + aioclient_mock.post( + TOKEN_URL, json={"access_token": ACCESS_TOKEN_2, "expires_in": 19} + ) + + aioclient_mock.post("https://example.com", status=201) + + config_entry = MockConfigEntry( + domain=TEST_DOMAIN, + data={ + "auth_implementation": TEST_DOMAIN, + "token": { + "refresh_token": REFRESH_TOKEN, + "access_token": ACCESS_TOKEN_1, + "expires_in": 19, + "expires_at": time.time() + 19, # Forces a refresh, + "token_type": "bearer", + "random_other_data": "should_stay", + }, + }, + ) + + now = time.time() + session = config_entry_oauth2_flow.OAuth2Session(hass, config_entry, local_impl) + resp = await session.async_request("post", "https://example.com") + assert resp.status == 201 + + # Refresh token, make request + assert len(aioclient_mock.mock_calls) == 2 + + assert ( + aioclient_mock.mock_calls[1][3]["authorization"] == f"Bearer {ACCESS_TOKEN_2}" + ) + + assert config_entry.data["token"]["refresh_token"] == REFRESH_TOKEN + assert config_entry.data["token"]["access_token"] == ACCESS_TOKEN_2 + assert config_entry.data["token"]["expires_in"] == 19 + assert config_entry.data["token"]["random_other_data"] == "should_stay" + assert round(config_entry.data["token"]["expires_at"] - now) == 19 + + +async def test_oauth_session_no_token_refresh_needed( + hass, flow_handler, local_impl, aioclient_mock +): + """Test the OAuth2 session helper when no refresh is needed.""" + flow_handler.async_register_implementation(hass, local_impl) + + aioclient_mock.post("https://example.com", status=201) + + config_entry = MockConfigEntry( + domain=TEST_DOMAIN, + data={ + "auth_implementation": TEST_DOMAIN, + "token": { + "refresh_token": REFRESH_TOKEN, + "access_token": ACCESS_TOKEN_1, + "expires_in": 500, + "expires_at": time.time() + 500, # Should NOT refresh + "token_type": "bearer", + "random_other_data": "should_stay", + }, + }, + ) + + now = time.time() + session = config_entry_oauth2_flow.OAuth2Session(hass, config_entry, local_impl) + resp = await session.async_request("post", "https://example.com") + assert resp.status == 201 + + # make request (no refresh) + assert len(aioclient_mock.mock_calls) == 1 + + assert ( + aioclient_mock.mock_calls[0][3]["authorization"] == f"Bearer {ACCESS_TOKEN_1}" + ) + + assert config_entry.data["token"]["refresh_token"] == REFRESH_TOKEN + assert config_entry.data["token"]["access_token"] == ACCESS_TOKEN_1 + assert config_entry.data["token"]["expires_in"] == 500 + assert config_entry.data["token"]["random_other_data"] == "should_stay" + assert round(config_entry.data["token"]["expires_at"] - now) == 500 + + async def test_implementation_provider(hass, local_impl): """Test providing an implementation provider.""" assert ( diff --git a/tests/helpers/test_config_validation.py b/tests/helpers/test_config_validation.py index 693785f4ea7..c829d4413f0 100644 --- a/tests/helpers/test_config_validation.py +++ b/tests/helpers/test_config_validation.py @@ -179,15 +179,21 @@ def test_entity_domain(): """Test entity domain validation.""" schema = vol.Schema(cv.entity_domain("sensor")) - options = ("invalid_entity", "cover.demo") - - for value in options: + for value in ("invalid_entity", "cover.demo"): with pytest.raises(vol.MultipleInvalid): - print(value) schema(value) assert schema("sensor.LIGHT") == "sensor.light" + schema = vol.Schema(cv.entity_domain(("sensor", "binary_sensor"))) + + for value in ("invalid_entity", "cover.demo"): + with pytest.raises(vol.MultipleInvalid): + schema(value) + + assert schema("sensor.LIGHT") == "sensor.light" + assert schema("binary_sensor.LIGHT") == "binary_sensor.light" + def test_entities_domain(): """Test entities domain validation.""" diff --git a/tests/helpers/test_device_registry.py b/tests/helpers/test_device_registry.py index 7c9e8a6e262..85ff693f261 100644 --- a/tests/helpers/test_device_registry.py +++ b/tests/helpers/test_device_registry.py @@ -458,7 +458,35 @@ async def test_loading_saving_data(hass, registry): registry.async_remove_device(orig_light2.id) - assert len(registry.devices) == 2 + orig_light3 = registry.async_get_or_create( + config_entry_id="789", + connections={(device_registry.CONNECTION_NETWORK_MAC, "34:56:AB:CD:EF:12")}, + identifiers={("hue", "abc")}, + manufacturer="manufacturer", + model="light", + ) + + registry.async_get_or_create( + config_entry_id="abc", + connections={(device_registry.CONNECTION_NETWORK_MAC, "34:56:AB:CD:EF:12")}, + identifiers={("abc", "123")}, + manufacturer="manufacturer", + model="light", + ) + + registry.async_remove_device(orig_light3.id) + + orig_light4 = registry.async_get_or_create( + config_entry_id="789", + connections={(device_registry.CONNECTION_NETWORK_MAC, "34:56:AB:CD:EF:12")}, + identifiers={("hue", "abc")}, + manufacturer="manufacturer", + model="light", + ) + + assert orig_light4.id == orig_light3.id + + assert len(registry.devices) == 3 assert len(registry.deleted_devices) == 1 orig_via = registry.async_update_device( @@ -476,9 +504,11 @@ async def test_loading_saving_data(hass, registry): new_via = registry2.async_get_device({("hue", "0123")}, set()) new_light = registry2.async_get_device({("hue", "456")}, set()) + new_light4 = registry2.async_get_device({("hue", "abc")}, set()) assert orig_via == new_via assert orig_light == new_light + assert orig_light4 == new_light4 async def test_no_unnecessary_changes(registry): @@ -841,6 +871,104 @@ async def test_restore_simple_device(hass, registry, update_events): assert update_events[3]["device_id"] == entry3.id +async def test_restore_shared_device(hass, registry, update_events): + """Make sure device id is stable for shared devices.""" + entry = registry.async_get_or_create( + config_entry_id="123", + connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + identifiers={("entry_123", "0123")}, + manufacturer="manufacturer", + model="model", + ) + + assert len(registry.devices) == 1 + assert len(registry.deleted_devices) == 0 + + registry.async_get_or_create( + config_entry_id="234", + connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + identifiers={("entry_234", "2345")}, + manufacturer="manufacturer", + model="model", + ) + + assert len(registry.devices) == 1 + assert len(registry.deleted_devices) == 0 + + registry.async_remove_device(entry.id) + + assert len(registry.devices) == 0 + assert len(registry.deleted_devices) == 1 + + entry2 = registry.async_get_or_create( + config_entry_id="123", + connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + identifiers={("entry_123", "0123")}, + manufacturer="manufacturer", + model="model", + ) + + assert entry.id == entry2.id + assert len(registry.devices) == 1 + assert len(registry.deleted_devices) == 0 + + assert isinstance(entry2.config_entries, set) + assert isinstance(entry2.connections, set) + assert isinstance(entry2.identifiers, set) + + registry.async_remove_device(entry.id) + + entry3 = registry.async_get_or_create( + config_entry_id="234", + connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + identifiers={("entry_234", "2345")}, + manufacturer="manufacturer", + model="model", + ) + + assert entry.id == entry3.id + assert len(registry.devices) == 1 + assert len(registry.deleted_devices) == 0 + + assert isinstance(entry3.config_entries, set) + assert isinstance(entry3.connections, set) + assert isinstance(entry3.identifiers, set) + + entry4 = registry.async_get_or_create( + config_entry_id="123", + connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + identifiers={("entry_123", "0123")}, + manufacturer="manufacturer", + model="model", + ) + + assert entry.id == entry4.id + assert len(registry.devices) == 1 + assert len(registry.deleted_devices) == 0 + + assert isinstance(entry4.config_entries, set) + assert isinstance(entry4.connections, set) + assert isinstance(entry4.identifiers, set) + + await hass.async_block_till_done() + + assert len(update_events) == 7 + assert update_events[0]["action"] == "create" + assert update_events[0]["device_id"] == entry.id + assert update_events[1]["action"] == "update" + assert update_events[1]["device_id"] == entry.id + assert update_events[2]["action"] == "remove" + assert update_events[2]["device_id"] == entry.id + assert update_events[3]["action"] == "create" + assert update_events[3]["device_id"] == entry.id + assert update_events[4]["action"] == "remove" + assert update_events[4]["device_id"] == entry.id + assert update_events[5]["action"] == "create" + assert update_events[5]["device_id"] == entry.id + assert update_events[1]["action"] == "update" + assert update_events[1]["device_id"] == entry.id + + async def test_get_or_create_empty_then_set_default_values(hass, registry): """Test creating an entry, then setting default name, model, manufacturer.""" entry = registry.async_get_or_create( diff --git a/tests/helpers/test_entity_registry.py b/tests/helpers/test_entity_registry.py index 8f5f8fc501b..336329396cc 100644 --- a/tests/helpers/test_entity_registry.py +++ b/tests/helpers/test_entity_registry.py @@ -154,6 +154,7 @@ async def test_loading_saving_data(hass, registry): "hue", "5678", device_id="mock-dev-id", + area_id="mock-area-id", config_entry=mock_config, capabilities={"max": 100}, supported_features=5, @@ -182,6 +183,7 @@ async def test_loading_saving_data(hass, registry): assert orig_entry2 == new_entry2 assert new_entry2.device_id == "mock-dev-id" + assert new_entry2.area_id == "mock-area-id" assert new_entry2.disabled_by == entity_registry.DISABLED_HASS assert new_entry2.capabilities == {"max": 100} assert new_entry2.supported_features == 5 @@ -330,6 +332,19 @@ async def test_removing_config_entry_id(hass, registry, update_events): assert update_events[1]["entity_id"] == entry.entity_id +async def test_removing_area_id(registry): + """Make sure we can clear area id.""" + entry = registry.async_get_or_create("light", "hue", "5678") + + entry_w_area = registry.async_update_entity(entry.entity_id, area_id="12345A") + + registry.async_clear_area_id("12345A") + entry_wo_area = registry.async_get(entry.entity_id) + + assert not entry_wo_area.area_id + assert entry_w_area != entry_wo_area + + async def test_migration(hass): """Test migration from old data to new.""" mock_config = MockConfigEntry(domain="test-platform", entry_id="test-config-id") diff --git a/tests/helpers/test_event.py b/tests/helpers/test_event.py index 8add5cc1cf3..1b9ddc52191 100644 --- a/tests/helpers/test_event.py +++ b/tests/helpers/test_event.py @@ -93,6 +93,38 @@ async def test_track_point_in_time(hass): assert len(runs) == 2 +async def test_track_point_in_time_drift_rearm(hass): + """Test tasks with the time rolling backwards.""" + specific_runs = [] + + now = dt_util.utcnow() + + time_that_will_not_match_right_away = datetime( + now.year + 1, 5, 24, 21, 59, 55, tzinfo=dt_util.UTC + ) + + async_track_point_in_utc_time( + hass, + callback(lambda x: specific_runs.append(x)), + time_that_will_not_match_right_away, + ) + + async_fire_time_changed( + hass, + datetime(now.year + 1, 5, 24, 21, 59, 00, tzinfo=dt_util.UTC), + fire_all=True, + ) + await hass.async_block_till_done() + assert len(specific_runs) == 0 + + async_fire_time_changed( + hass, + datetime(now.year + 1, 5, 24, 21, 59, 55, tzinfo=dt_util.UTC), + ) + await hass.async_block_till_done() + assert len(specific_runs) == 1 + + async def test_track_state_change_from_to_state_match(hass): """Test track_state_change with from and to state matchers.""" from_and_to_state_runs = [] @@ -2123,68 +2155,73 @@ async def test_track_template_with_time_default(hass): 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) - 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, - ) + 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, + ) - 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) - 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 + # 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 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 + 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 info.async_remove() @@ -2757,7 +2794,7 @@ async def test_periodic_task_clock_rollback(hass): fire_all=True, ) await hass.async_block_till_done() - assert len(specific_runs) == 2 + assert len(specific_runs) == 1 async_fire_time_changed( hass, @@ -2765,13 +2802,13 @@ async def test_periodic_task_clock_rollback(hass): fire_all=True, ) await hass.async_block_till_done() - assert len(specific_runs) == 3 + assert len(specific_runs) == 1 async_fire_time_changed( hass, datetime(now.year + 1, 5, 25, 2, 0, 0, 999999, tzinfo=dt_util.UTC) ) await hass.async_block_till_done() - assert len(specific_runs) == 4 + assert len(specific_runs) == 2 unsub() @@ -2779,7 +2816,7 @@ async def test_periodic_task_clock_rollback(hass): hass, datetime(now.year + 1, 5, 25, 2, 0, 0, 999999, tzinfo=dt_util.UTC) ) await hass.async_block_till_done() - assert len(specific_runs) == 4 + assert len(specific_runs) == 2 async def test_periodic_task_duplicate_time(hass): diff --git a/tests/helpers/test_placeholder.py b/tests/helpers/test_placeholder.py new file mode 100644 index 00000000000..d5978cd465a --- /dev/null +++ b/tests/helpers/test_placeholder.py @@ -0,0 +1,29 @@ +"""Test placeholders.""" +import pytest + +from homeassistant.helpers import placeholder +from homeassistant.util.yaml import Placeholder + + +def test_extract_placeholders(): + """Test extracting placeholders from data.""" + assert placeholder.extract_placeholders(Placeholder("hello")) == {"hello"} + assert placeholder.extract_placeholders( + {"info": [1, Placeholder("hello"), 2, Placeholder("world")]} + ) == {"hello", "world"} + + +def test_substitute(): + """Test we can substitute.""" + assert placeholder.substitute(Placeholder("hello"), {"hello": 5}) == 5 + + with pytest.raises(placeholder.UndefinedSubstitution): + placeholder.substitute(Placeholder("hello"), {}) + + assert ( + placeholder.substitute( + {"info": [1, Placeholder("hello"), 2, Placeholder("world")]}, + {"hello": 5, "world": 10}, + ) + == {"info": [1, 5, 2, 10]} + ) diff --git a/tests/helpers/test_service.py b/tests/helpers/test_service.py index 929df2a32e0..6f2cd4ba130 100644 --- a/tests/helpers/test_service.py +++ b/tests/helpers/test_service.py @@ -105,12 +105,32 @@ def area_mock(hass): }, ) + entity_in_own_area = ent_reg.RegistryEntry( + entity_id="light.in_own_area", + unique_id="in-own-area-id", + platform="test", + area_id="own-area", + ) entity_in_area = ent_reg.RegistryEntry( entity_id="light.in_area", unique_id="in-area-id", platform="test", device_id=device_in_area.id, ) + entity_in_other_area = ent_reg.RegistryEntry( + entity_id="light.in_other_area", + unique_id="in-other-area-id", + platform="test", + device_id=device_in_area.id, + area_id="other-area", + ) + entity_assigned_to_area = ent_reg.RegistryEntry( + entity_id="light.assigned_to_area", + unique_id="assigned-area-id", + platform="test", + device_id=device_in_area.id, + area_id="test-area", + ) entity_no_area = ent_reg.RegistryEntry( entity_id="light.no_area", unique_id="no-area-id", @@ -126,7 +146,10 @@ def area_mock(hass): mock_registry( hass, { + entity_in_own_area.entity_id: entity_in_own_area, entity_in_area.entity_id: entity_in_area, + entity_in_other_area.entity_id: entity_in_other_area, + entity_assigned_to_area.entity_id: entity_assigned_to_area, entity_no_area.entity_id: entity_no_area, entity_diff_area.entity_id: entity_diff_area, }, @@ -298,15 +321,25 @@ async def test_extract_entity_ids(hass): async def test_extract_entity_ids_from_area(hass, area_mock): """Test extract_entity_ids method with areas.""" + call = ha.ServiceCall("light", "turn_on", {"area_id": "own-area"}) + + assert { + "light.in_own_area", + } == await service.async_extract_entity_ids(hass, call) + call = ha.ServiceCall("light", "turn_on", {"area_id": "test-area"}) - assert {"light.in_area"} == await service.async_extract_entity_ids(hass, call) + assert { + "light.in_area", + "light.assigned_to_area", + } == await service.async_extract_entity_ids(hass, call) call = ha.ServiceCall("light", "turn_on", {"area_id": ["test-area", "diff-area"]}) assert { "light.in_area", "light.diff_area", + "light.assigned_to_area", } == await service.async_extract_entity_ids(hass, call) assert ( diff --git a/tests/helpers/test_storage.py b/tests/helpers/test_storage.py index 6325294033f..7fa6dd61845 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 00000000000..9a447771ea6 --- /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() diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index e3eafda52f1..fe2f23c0033 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -13,7 +13,6 @@ from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, LENGTH_METERS, MASS_GRAMS, - MATCH_ALL, PRESSURE_PA, TEMP_CELSIUS, VOLUME_LITERS, @@ -24,14 +23,7 @@ from homeassistant.setup import async_setup_component 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( diff --git a/tests/helpers/test_translation.py b/tests/helpers/test_translation.py index 440b3d75439..e8c5c756d59 100644 --- a/tests/helpers/test_translation.py +++ b/tests/helpers/test_translation.py @@ -5,7 +5,6 @@ import pathlib import pytest -from homeassistant.const import EVENT_COMPONENT_LOADED from homeassistant.generated import config_flows from homeassistant.helpers import translation from homeassistant.loader import async_get_integration @@ -22,16 +21,16 @@ def mock_config_flows(): yield flows -def test_flatten(): +def test_recursive_flatten(): """Test the flatten function.""" data = {"parent1": {"child1": "data1", "child2": "data2"}, "parent2": "data3"} - flattened = translation.flatten(data) + flattened = translation.recursive_flatten("prefix.", data) assert flattened == { - "parent1.child1": "data1", - "parent1.child2": "data2", - "parent2": "data3", + "prefix.parent1.child1": "data1", + "prefix.parent1.child2": "data2", + "prefix.parent2": "data3", } @@ -149,33 +148,77 @@ async def test_get_translations_loads_config_flows(hass, mock_config_flows): return_value="bla.json", ), patch( "homeassistant.helpers.translation.load_translations_files", - return_value={"component1": {"hello": "world"}}, + return_value={"component1": {"title": "world"}}, ), patch( "homeassistant.helpers.translation.async_get_integration", return_value=integration, ): translations = await translation.async_get_translations( - hass, "en", "hello", config_flow=True + hass, "en", "title", config_flow=True + ) + translations_again = await translation.async_get_translations( + hass, "en", "title", config_flow=True ) + assert translations == translations_again + assert translations == { - "component.component1.hello": "world", + "component.component1.title": "world", } assert "component1" not in hass.config.components + mock_config_flows.append("component2") + integration = Mock(file_path=pathlib.Path(__file__)) + integration.name = "Component 2" + + with patch( + "homeassistant.helpers.translation.component_translation_path", + return_value="bla.json", + ), patch( + "homeassistant.helpers.translation.load_translations_files", + return_value={"component2": {"title": "world"}}, + ), patch( + "homeassistant.helpers.translation.async_get_integration", + return_value=integration, + ): + translations = await translation.async_get_translations( + hass, "en", "title", config_flow=True + ) + translations_again = await translation.async_get_translations( + hass, "en", "title", config_flow=True + ) + + assert translations == translations_again + + assert translations == { + "component.component1.title": "world", + "component.component2.title": "world", + } + + translations_all_cached = await translation.async_get_translations( + hass, "en", "title", config_flow=True + ) + assert translations == translations_all_cached + + assert "component1" not in hass.config.components + assert "component2" not in hass.config.components + async def test_get_translations_while_loading_components(hass): """Test the get translations helper loads config flow translations.""" integration = Mock(file_path=pathlib.Path(__file__)) integration.name = "Component 1" hass.config.components.add("component1") + load_count = 0 def mock_load_translation_files(files): """Mock load translation files.""" + nonlocal load_count + load_count += 1 # Mimic race condition by loading a component during setup setup_component(hass, "persistent_notification", {}) - return {"component1": {"hello": "world"}} + return {"component1": {"title": "world"}} with patch( "homeassistant.helpers.translation.component_translation_path", @@ -187,11 +230,15 @@ async def test_get_translations_while_loading_components(hass): "homeassistant.helpers.translation.async_get_integration", return_value=integration, ): - translations = await translation.async_get_translations(hass, "en", "hello") + tasks = [ + translation.async_get_translations(hass, "en", "title") for _ in range(5) + ] + all_translations = await asyncio.gather(*tasks) - assert translations == { - "component.component1.hello": "world", + assert all_translations[0] == { + "component.component1.title": "world", } + assert load_count == 1 async def test_get_translation_categories(hass): @@ -211,17 +258,13 @@ async def test_get_translation_categories(hass): async def test_translation_merging(hass, caplog): """Test we merge translations of two integrations.""" hass.config.components.add("sensor.moon") - hass.config.components.add("sensor.season") hass.config.components.add("sensor") translations = await translation.async_get_translations(hass, "en", "state") assert "component.sensor.state.moon__phase.first_quarter" in translations - assert "component.sensor.state.season__season.summer" in translations - # Clear cache - hass.bus.async_fire(EVENT_COMPONENT_LOADED) - await hass.async_block_till_done() + hass.config.components.add("sensor.season") # Patch in some bad translation data @@ -247,27 +290,91 @@ async def test_translation_merging(hass, caplog): ) +async def test_translation_merging_loaded_apart(hass, caplog): + """Test we merge translations of two integrations when they are not loaded at the same time.""" + hass.config.components.add("sensor") + + translations = await translation.async_get_translations(hass, "en", "state") + + assert "component.sensor.state.moon__phase.first_quarter" not in translations + + hass.config.components.add("sensor.moon") + + translations = await translation.async_get_translations(hass, "en", "state") + + assert "component.sensor.state.moon__phase.first_quarter" in translations + + translations = await translation.async_get_translations( + hass, "en", "state", integration="sensor" + ) + + assert "component.sensor.state.moon__phase.first_quarter" in translations + + async def test_caching(hass): """Test we cache data.""" hass.config.components.add("sensor") + hass.config.components.add("light") # Patch with same method so we can count invocations with patch( - "homeassistant.helpers.translation.merge_resources", - side_effect=translation.merge_resources, + "homeassistant.helpers.translation._merge_resources", + side_effect=translation._merge_resources, ) as mock_merge: - await translation.async_get_translations(hass, "en", "state") + load1 = await translation.async_get_translations(hass, "en", "state") assert len(mock_merge.mock_calls) == 1 - await translation.async_get_translations(hass, "en", "state") + load2 = await translation.async_get_translations(hass, "en", "state") assert len(mock_merge.mock_calls) == 1 - # This event clears the cache so we should record another call - hass.bus.async_fire(EVENT_COMPONENT_LOADED) - await hass.async_block_till_done() + assert load1 == load2 - await translation.async_get_translations(hass, "en", "state") - assert len(mock_merge.mock_calls) == 2 + for key in load1: + assert key.startswith("component.sensor.state.") or key.startswith( + "component.light.state." + ) + + load_sensor_only = await translation.async_get_translations( + hass, "en", "state", integration="sensor" + ) + assert load_sensor_only + for key in load_sensor_only: + assert key.startswith("component.sensor.state.") + + load_light_only = await translation.async_get_translations( + hass, "en", "state", integration="light" + ) + assert load_light_only + for key in load_light_only: + assert key.startswith("component.light.state.") + + hass.config.components.add("media_player") + + # Patch with same method so we can count invocations + with patch( + "homeassistant.helpers.translation._build_resources", + side_effect=translation._build_resources, + ) as mock_build: + load_sensor_only = await translation.async_get_translations( + hass, "en", "title", integration="sensor" + ) + assert load_sensor_only + for key in load_sensor_only: + assert key == "component.sensor.title" + assert len(mock_build.mock_calls) == 0 + + assert await translation.async_get_translations( + hass, "en", "title", integration="sensor" + ) + assert len(mock_build.mock_calls) == 0 + + load_light_only = await translation.async_get_translations( + hass, "en", "title", integration="media_player" + ) + assert load_light_only + for key in load_light_only: + assert key == "component.media_player.title" + assert len(mock_build.mock_calls) > 1 async def test_custom_component_translations(hass): diff --git a/tests/helpers/test_update_coordinator.py b/tests/helpers/test_update_coordinator.py index 72b9bff60f1..90567456bfb 100644 --- a/tests/helpers/test_update_coordinator.py +++ b/tests/helpers/test_update_coordinator.py @@ -250,3 +250,37 @@ async def test_coordinator_entity(crd): with patch("homeassistant.helpers.entity.Entity.enabled", False): await entity.async_update() assert entity.available is False + + +async def test_async_set_updated_data(crd): + """Test async_set_updated_data for update coordinator.""" + assert crd.data is None + + with patch.object(crd._debounced_refresh, "async_cancel") as mock_cancel: + crd.async_set_updated_data(100) + + # Test we cancel any pending refresh + assert len(mock_cancel.mock_calls) == 1 + + # Test data got updated + assert crd.data == 100 + assert crd.last_update_success is True + + # Make sure we didn't schedule a refresh because we have 0 listeners + assert crd._unsub_refresh is None + + updates = [] + + def update_callback(): + updates.append(crd.data) + + crd.async_add_listener(update_callback) + crd.async_set_updated_data(200) + assert updates == [200] + assert crd._unsub_refresh is not None + + old_refresh = crd._unsub_refresh + + crd.async_set_updated_data(300) + # We have created a new refresh listener + assert crd._unsub_refresh is not old_refresh diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index 6c2df29985c..59e1b0754c0 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -861,12 +861,45 @@ async def test_entry_options(hass, manager): flow.handler = entry.entry_id # Used to keep reference to config entry - await manager.options.async_finish_flow(flow, {"data": {"second": True}}) + await manager.options.async_finish_flow( + flow, + {"data": {"second": True}, "type": data_entry_flow.RESULT_TYPE_CREATE_ENTRY}, + ) assert entry.data == {"first": True} assert entry.options == {"second": True} +async def test_entry_options_abort(hass, manager): + """Test that we can abort options flow.""" + entry = MockConfigEntry(domain="test", data={"first": True}, options=None) + entry.add_to_manager(manager) + + class TestFlow: + """Test flow.""" + + @staticmethod + @callback + def async_get_options_flow(config_entry): + """Test options flow.""" + + class OptionsFlowHandler(data_entry_flow.FlowHandler): + """Test options flow handler.""" + + return OptionsFlowHandler() + + config_entries.HANDLERS["test"] = TestFlow() + flow = await manager.options.async_create_flow( + entry.entry_id, context={"source": "test"}, data=None + ) + + flow.handler = entry.entry_id # Used to keep reference to config entry + + assert await manager.options.async_finish_flow( + flow, {"type": data_entry_flow.RESULT_TYPE_ABORT, "reason": "test"} + ) + + async def test_entry_setup_succeed(hass, manager): """Test that we can setup an entry.""" entry = MockConfigEntry(domain="comp", state=config_entries.ENTRY_STATE_NOT_LOADED) @@ -1156,11 +1189,7 @@ async def test_reload_entry_entity_registry_works(hass): async_fire_time_changed( hass, - dt.utcnow() - + timedelta( - seconds=config_entries.EntityRegistryDisabledHandler.RELOAD_AFTER_UPDATE_DELAY - + 1 - ), + dt.utcnow() + timedelta(seconds=config_entries.RELOAD_AFTER_UPDATE_DELAY + 1), ) await hass.async_block_till_done() diff --git a/tests/test_core.py b/tests/test_core.py index 119c0269ba7..f08de049efa 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -906,7 +906,7 @@ def test_config_defaults(): assert config.allowlist_external_urls == set() assert config.media_dirs == {} assert config.safe_mode is False - assert config.legacy_templates is True + assert config.legacy_templates is False def test_config_path_with_file(): @@ -1584,3 +1584,21 @@ async def test_reserving_states(hass): assert hass.states.async_available("light.bedroom") is False hass.states.async_remove("light.bedroom") assert hass.states.async_available("light.bedroom") is True + + +async def test_state_change_events_match_state_time(hass): + """Test last_updated and timed_fired only call utcnow once.""" + + events = [] + + @ha.callback + def _event_listener(event): + events.append(event) + + hass.bus.async_listen(ha.EVENT_STATE_CHANGED, _event_listener) + + hass.states.async_set("light.bedroom", "on") + await hass.async_block_till_done() + state = hass.states.get("light.bedroom") + + assert state.last_updated == events[0].time_fired diff --git a/tests/test_data_entry_flow.py b/tests/test_data_entry_flow.py index 64b8587fe7c..b2fd9c8e34b 100644 --- a/tests/test_data_entry_flow.py +++ b/tests/test_data_entry_flow.py @@ -285,6 +285,76 @@ async def test_external_step(hass, manager): assert result["title"] == "Hello" +async def test_show_progress(hass, manager): + """Test show progress logic.""" + manager.hass = hass + + @manager.mock_reg_handler("test") + class TestFlow(data_entry_flow.FlowHandler): + VERSION = 5 + data = None + task_one_done = False + + async def async_step_init(self, user_input=None): + if not user_input: + if not self.task_one_done: + self.task_one_done = True + progress_action = "task_one" + else: + progress_action = "task_two" + return self.async_show_progress( + step_id="init", + progress_action=progress_action, + ) + + self.data = user_input + return self.async_show_progress_done(next_step_id="finish") + + async def async_step_finish(self, user_input=None): + return self.async_create_entry(title=self.data["title"], data=self.data) + + events = async_capture_events( + hass, data_entry_flow.EVENT_DATA_ENTRY_FLOW_PROGRESSED + ) + + result = await manager.async_init("test") + assert result["type"] == data_entry_flow.RESULT_TYPE_SHOW_PROGRESS + assert result["progress_action"] == "task_one" + assert len(manager.async_progress()) == 1 + + # Mimic task one done and moving to task two + # Called by integrations: `hass.config_entries.flow.async_configure(…)` + result = await manager.async_configure(result["flow_id"]) + assert result["type"] == data_entry_flow.RESULT_TYPE_SHOW_PROGRESS + assert result["progress_action"] == "task_two" + + await hass.async_block_till_done() + assert len(events) == 1 + assert events[0].data == { + "handler": "test", + "flow_id": result["flow_id"], + "refresh": True, + } + + # Mimic task two done and continuing step + # Called by integrations: `hass.config_entries.flow.async_configure(…)` + result = await manager.async_configure(result["flow_id"], {"title": "Hello"}) + assert result["type"] == data_entry_flow.RESULT_TYPE_SHOW_PROGRESS_DONE + + await hass.async_block_till_done() + assert len(events) == 2 + assert events[1].data == { + "handler": "test", + "flow_id": result["flow_id"], + "refresh": True, + } + + # Frontend refreshes the flow + result = await manager.async_configure(result["flow_id"]) + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["title"] == "Hello" + + async def test_abort_flow_exception(manager): """Test that the AbortFlow exception works.""" diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index 71358cdd973..fde1cb6ca2e 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -19,7 +19,7 @@ RETYPE = type(re.compile("")) def mock_stream(data): """Mock a stream with data.""" protocol = mock.Mock(_reading_paused=False) - stream = StreamReader(protocol) + stream = StreamReader(protocol, limit=2 ** 16) stream.feed_data(data) stream.feed_eof() return stream diff --git a/tests/testing_config/blueprints/automation/in_folder/in_folder_blueprint.yaml b/tests/testing_config/blueprints/automation/in_folder/in_folder_blueprint.yaml new file mode 100644 index 00000000000..c869e30c41e --- /dev/null +++ b/tests/testing_config/blueprints/automation/in_folder/in_folder_blueprint.yaml @@ -0,0 +1,8 @@ +blueprint: + name: "In Folder Blueprint" + domain: automation + input: + trigger: + action: +trigger: !placeholder trigger +action: !placeholder action diff --git a/tests/testing_config/blueprints/automation/test_event_service.yaml b/tests/testing_config/blueprints/automation/test_event_service.yaml new file mode 100644 index 00000000000..0e9479cd8c3 --- /dev/null +++ b/tests/testing_config/blueprints/automation/test_event_service.yaml @@ -0,0 +1,11 @@ +blueprint: + name: "Call service based on event" + domain: automation + input: + trigger_event: + service_to_call: +trigger: + platform: event + event_type: !placeholder trigger_event +action: + service: !placeholder service_to_call diff --git a/tests/util/test_async.py b/tests/util/test_async.py index 460490eb783..047697168b4 100644 --- a/tests/util/test_async.py +++ b/tests/util/test_async.py @@ -1,4 +1,7 @@ """Tests for async util methods from Python source.""" +import asyncio +import time + import pytest from homeassistant.util import async_ as hasync @@ -144,3 +147,25 @@ def test_protect_loop_sync(): hasync.protect_loop(calls.append)(1) assert len(mock_loop.mock_calls) == 1 assert calls == [1] + + +async def test_gather_with_concurrency(): + """Test gather_with_concurrency limits the number of running tasks.""" + + runs = 0 + now_time = time.time() + + async def _increment_runs_if_in_time(): + if time.time() - now_time > 0.1: + return -1 + + nonlocal runs + runs += 1 + await asyncio.sleep(0.1) + return runs + + results = await hasync.gather_with_concurrency( + 2, *[_increment_runs_if_in_time() for i in range(4)] + ) + + assert results == [2, 2, -1, -1] diff --git a/tests/util/test_distance.py b/tests/util/test_distance.py index ee6b79c0861..e1cf7ae0f6a 100644 --- a/tests/util/test_distance.py +++ b/tests/util/test_distance.py @@ -3,10 +3,14 @@ import pytest from homeassistant.const import ( + LENGTH_CENTIMETERS, LENGTH_FEET, + LENGTH_INCHES, LENGTH_KILOMETERS, LENGTH_METERS, LENGTH_MILES, + LENGTH_MILLIMETERS, + LENGTH_YARD, ) import homeassistant.util.distance as distance_util @@ -18,8 +22,12 @@ def test_convert_same_unit(): """Test conversion from any unit to same unit.""" assert distance_util.convert(5, LENGTH_KILOMETERS, LENGTH_KILOMETERS) == 5 assert distance_util.convert(2, LENGTH_METERS, LENGTH_METERS) == 2 + assert distance_util.convert(6, LENGTH_CENTIMETERS, LENGTH_CENTIMETERS) == 6 + assert distance_util.convert(3, LENGTH_MILLIMETERS, LENGTH_MILLIMETERS) == 3 assert distance_util.convert(10, LENGTH_MILES, LENGTH_MILES) == 10 - assert distance_util.convert(9, LENGTH_FEET, LENGTH_FEET) == 9 + assert distance_util.convert(9, LENGTH_YARD, LENGTH_YARD) == 9 + assert distance_util.convert(8, LENGTH_FEET, LENGTH_FEET) == 8 + assert distance_util.convert(7, LENGTH_INCHES, LENGTH_INCHES) == 7 def test_convert_invalid_unit(): @@ -42,7 +50,26 @@ def test_convert_from_miles(): miles = 5 assert distance_util.convert(miles, LENGTH_MILES, LENGTH_KILOMETERS) == 8.04672 assert distance_util.convert(miles, LENGTH_MILES, LENGTH_METERS) == 8046.72 + assert distance_util.convert(miles, LENGTH_MILES, LENGTH_CENTIMETERS) == 804672.0 + assert distance_util.convert(miles, LENGTH_MILES, LENGTH_MILLIMETERS) == 8046720.0 + assert distance_util.convert(miles, LENGTH_MILES, LENGTH_YARD) == 8799.9734592 assert distance_util.convert(miles, LENGTH_MILES, LENGTH_FEET) == 26400.0008448 + assert distance_util.convert(miles, LENGTH_MILES, LENGTH_INCHES) == 316800.171072 + + +def test_convert_from_yards(): + """Test conversion from yards to other units.""" + yards = 5 + assert ( + distance_util.convert(yards, LENGTH_YARD, LENGTH_KILOMETERS) + == 0.0045720000000000005 + ) + assert distance_util.convert(yards, LENGTH_YARD, LENGTH_METERS) == 4.572 + assert distance_util.convert(yards, LENGTH_YARD, LENGTH_CENTIMETERS) == 457.2 + assert distance_util.convert(yards, LENGTH_YARD, LENGTH_MILLIMETERS) == 4572.0 + assert distance_util.convert(yards, LENGTH_YARD, LENGTH_MILES) == 0.002840908212 + assert distance_util.convert(yards, LENGTH_YARD, LENGTH_FEET) == 15.00000048 + assert distance_util.convert(yards, LENGTH_YARD, LENGTH_INCHES) == 180.0000972 def test_convert_from_feet(): @@ -50,20 +77,70 @@ def test_convert_from_feet(): feet = 5000 assert distance_util.convert(feet, LENGTH_FEET, LENGTH_KILOMETERS) == 1.524 assert distance_util.convert(feet, LENGTH_FEET, LENGTH_METERS) == 1524 + assert distance_util.convert(feet, LENGTH_FEET, LENGTH_CENTIMETERS) == 152400.0 + assert distance_util.convert(feet, LENGTH_FEET, LENGTH_MILLIMETERS) == 1524000.0 assert distance_util.convert(feet, LENGTH_FEET, LENGTH_MILES) == 0.9469694040000001 + assert distance_util.convert(feet, LENGTH_FEET, LENGTH_YARD) == 1666.66164 + assert distance_util.convert(feet, LENGTH_FEET, LENGTH_INCHES) == 60000.032400000004 + + +def test_convert_from_inches(): + """Test conversion from inches to other units.""" + inches = 5000 + assert distance_util.convert(inches, LENGTH_INCHES, LENGTH_KILOMETERS) == 0.127 + assert distance_util.convert(inches, LENGTH_INCHES, LENGTH_METERS) == 127.0 + assert distance_util.convert(inches, LENGTH_INCHES, LENGTH_CENTIMETERS) == 12700.0 + assert distance_util.convert(inches, LENGTH_INCHES, LENGTH_MILLIMETERS) == 127000.0 + assert distance_util.convert(inches, LENGTH_INCHES, LENGTH_MILES) == 0.078914117 + assert ( + distance_util.convert(inches, LENGTH_INCHES, LENGTH_YARD) == 138.88846999999998 + ) + assert distance_util.convert(inches, LENGTH_INCHES, LENGTH_FEET) == 416.66668 def test_convert_from_kilometers(): """Test conversion from kilometers to other units.""" km = 5 - assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_FEET) == 16404.2 assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_METERS) == 5000 + assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_CENTIMETERS) == 500000 + assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_MILLIMETERS) == 5000000 assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_MILES) == 3.106855 + assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_YARD) == 5468.05 + assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_FEET) == 16404.2 + assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_INCHES) == 196850.5 def test_convert_from_meters(): """Test conversion from meters to other units.""" m = 5000 - assert distance_util.convert(m, LENGTH_METERS, LENGTH_FEET) == 16404.2 assert distance_util.convert(m, LENGTH_METERS, LENGTH_KILOMETERS) == 5 + assert distance_util.convert(m, LENGTH_METERS, LENGTH_CENTIMETERS) == 500000 + assert distance_util.convert(m, LENGTH_METERS, LENGTH_MILLIMETERS) == 5000000 assert distance_util.convert(m, LENGTH_METERS, LENGTH_MILES) == 3.106855 + assert distance_util.convert(m, LENGTH_METERS, LENGTH_YARD) == 5468.05 + assert distance_util.convert(m, LENGTH_METERS, LENGTH_FEET) == 16404.2 + assert distance_util.convert(m, LENGTH_METERS, LENGTH_INCHES) == 196850.5 + + +def test_convert_from_centimeters(): + """Test conversion from centimeters to other units.""" + cm = 500000 + assert distance_util.convert(cm, LENGTH_CENTIMETERS, LENGTH_KILOMETERS) == 5 + assert distance_util.convert(cm, LENGTH_CENTIMETERS, LENGTH_METERS) == 5000 + assert distance_util.convert(cm, LENGTH_CENTIMETERS, LENGTH_MILLIMETERS) == 5000000 + assert distance_util.convert(cm, LENGTH_CENTIMETERS, LENGTH_MILES) == 3.106855 + assert distance_util.convert(cm, LENGTH_CENTIMETERS, LENGTH_YARD) == 5468.05 + assert distance_util.convert(cm, LENGTH_CENTIMETERS, LENGTH_FEET) == 16404.2 + assert distance_util.convert(cm, LENGTH_CENTIMETERS, LENGTH_INCHES) == 196850.5 + + +def test_convert_from_millimeters(): + """Test conversion from millimeters to other units.""" + mm = 5000000 + assert distance_util.convert(mm, LENGTH_MILLIMETERS, LENGTH_KILOMETERS) == 5 + assert distance_util.convert(mm, LENGTH_MILLIMETERS, LENGTH_METERS) == 5000 + assert distance_util.convert(mm, LENGTH_MILLIMETERS, LENGTH_CENTIMETERS) == 500000 + assert distance_util.convert(mm, LENGTH_MILLIMETERS, LENGTH_MILES) == 3.106855 + assert distance_util.convert(mm, LENGTH_MILLIMETERS, LENGTH_YARD) == 5468.05 + assert distance_util.convert(mm, LENGTH_MILLIMETERS, LENGTH_FEET) == 16404.2 + assert distance_util.convert(mm, LENGTH_MILLIMETERS, LENGTH_INCHES) == 196850.5 diff --git a/tests/util/test_yaml.py b/tests/util/test_yaml.py index 96b6a86a27d..2e9d1b471ac 100644 --- a/tests/util/test_yaml.py +++ b/tests/util/test_yaml.py @@ -461,3 +461,20 @@ def test_duplicate_key(caplog): with patch_yaml_files(files): load_yaml_config_file(YAML_CONFIG_FILE) assert "contains duplicate key" in caplog.text + + +def test_placeholder_class(): + """Test placeholder class.""" + placeholder = yaml_loader.Placeholder("hello") + placeholder2 = yaml_loader.Placeholder("hello") + + assert placeholder.name == "hello" + assert placeholder == placeholder2 + + assert len({placeholder, placeholder2}) == 1 + + +def test_placeholder(): + """Test loading placeholders.""" + data = {"hello": yaml.Placeholder("test_name")} + assert yaml.parse_yaml(yaml.dump(data)) == data