Merge pull request #36626 from home-assistant/rc

pull/34053/head 0.111.0
Franck Nijhof 2020-06-10 16:07:38 +02:00 committed by GitHub
commit 818b45384d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2169 changed files with 30978 additions and 11564 deletions

View File

@ -10,6 +10,14 @@ omit =
# omit pieces of code that rely on external devices being present
homeassistant/components/acer_projector/switch.py
homeassistant/components/actiontec/device_tracker.py
homeassistant/components/acmeda/__init__.py
homeassistant/components/acmeda/base.py
homeassistant/components/acmeda/const.py
homeassistant/components/acmeda/cover.py
homeassistant/components/acmeda/errors.py
homeassistant/components/acmeda/helpers.py
homeassistant/components/acmeda/hub.py
homeassistant/components/acmeda/sensor.py
homeassistant/components/adguard/__init__.py
homeassistant/components/adguard/const.py
homeassistant/components/adguard/sensor.py
@ -55,14 +63,9 @@ omit =
homeassistant/components/arwn/sensor.py
homeassistant/components/asterisk_cdr/mailbox.py
homeassistant/components/asterisk_mbox/*
homeassistant/components/atag/__init__.py
homeassistant/components/atag/climate.py
homeassistant/components/atag/sensor.py
homeassistant/components/atag/water_heater.py
homeassistant/components/aten_pe/*
homeassistant/components/atome/*
homeassistant/components/aurora_abb_powerone/sensor.py
homeassistant/components/automatic/*
homeassistant/components/avea/light.py
homeassistant/components/avion/light.py
homeassistant/components/avri/sensor.py
@ -115,6 +118,7 @@ omit =
homeassistant/components/cast/*
homeassistant/components/cert_expiry/helper.py
homeassistant/components/channels/*
homeassistant/components/circuit/*
homeassistant/components/cisco_ios/device_tracker.py
homeassistant/components/cisco_mobility_express/device_tracker.py
homeassistant/components/cisco_webex_teams/notify.py
@ -172,6 +176,8 @@ omit =
homeassistant/components/dsmr_reader/*
homeassistant/components/dte_energy_bridge/sensor.py
homeassistant/components/dublin_bus_transport/sensor.py
homeassistant/components/dunehd/__init__.py
homeassistant/components/dunehd/const.py
homeassistant/components/dunehd/media_player.py
homeassistant/components/dwd_weather_warnings/sensor.py
homeassistant/components/dweet/*
@ -271,7 +277,6 @@ omit =
homeassistant/components/garmin_connect/sensor.py
homeassistant/components/gc100/*
homeassistant/components/geniushub/*
homeassistant/components/gearbest/sensor.py
homeassistant/components/geizhals/sensor.py
homeassistant/components/gios/__init__.py
homeassistant/components/gios/air_quality.py
@ -282,7 +287,6 @@ omit =
homeassistant/components/glances/sensor.py
homeassistant/components/gntp/notify.py
homeassistant/components/goalfeed/*
homeassistant/components/gogogate2/cover.py
homeassistant/components/google/*
homeassistant/components/google_cloud/tts.py
homeassistant/components/google_maps/device_tracker.py
@ -296,6 +300,10 @@ omit =
homeassistant/components/growatt_server/sensor.py
homeassistant/components/gstreamer/media_player.py
homeassistant/components/gtfs/sensor.py
homeassistant/components/guardian/__init__.py
homeassistant/components/guardian/binary_sensor.py
homeassistant/components/guardian/sensor.py
homeassistant/components/guardian/switch.py
homeassistant/components/habitica/*
homeassistant/components/hangouts/*
homeassistant/components/hangouts/__init__.py
@ -557,7 +565,9 @@ omit =
homeassistant/components/openevse/sensor.py
homeassistant/components/openexchangerates/sensor.py
homeassistant/components/opengarage/cover.py
homeassistant/components/openhome/__init__.py
homeassistant/components/openhome/media_player.py
homeassistant/components/openhome/const.py
homeassistant/components/opensensemap/air_quality.py
homeassistant/components/opensky/sensor.py
homeassistant/components/opentherm_gw/__init__.py
@ -595,7 +605,11 @@ omit =
homeassistant/components/plaato/*
homeassistant/components/plex/media_player.py
homeassistant/components/plex/sensor.py
homeassistant/components/plugwise/*
homeassistant/components/plugwise/__init__.py
homeassistant/components/plugwise/binary_sensor.py
homeassistant/components/plugwise/climate.py
homeassistant/components/plugwise/sensor.py
homeassistant/components/plugwise/switch.py
homeassistant/components/plum_lightpad/*
homeassistant/components/pocketcasts/sensor.py
homeassistant/components/point/*
@ -718,7 +732,6 @@ omit =
homeassistant/components/soma/__init__.py
homeassistant/components/somfy/*
homeassistant/components/somfy_mylink/*
homeassistant/components/sonarr/sensor.py
homeassistant/components/sonos/*
homeassistant/components/sony_projector/switch.py
homeassistant/components/spc/*
@ -748,6 +761,7 @@ omit =
homeassistant/components/synology/camera.py
homeassistant/components/synology_chat/notify.py
homeassistant/components/synology_dsm/__init__.py
homeassistant/components/synology_dsm/binary_sensor.py
homeassistant/components/synology_dsm/sensor.py
homeassistant/components/synology_srm/device_tracker.py
homeassistant/components/syslog/notify.py
@ -872,9 +886,6 @@ omit =
homeassistant/components/wirelesstag/*
homeassistant/components/worldtidesinfo/sensor.py
homeassistant/components/worxlandroid/sensor.py
homeassistant/components/wunderlist/*
homeassistant/components/wwlln/__init__.py
homeassistant/components/wwlln/geo_location.py
homeassistant/components/x10/light.py
homeassistant/components/xbox_live/sensor.py
homeassistant/components/xeoma/camera.py
@ -922,7 +933,7 @@ omit =
homeassistant/components/zha/light.py
homeassistant/components/zha/sensor.py
homeassistant/components/zhong_hong/climate.py
homeassistant/components/zigbee/*
homeassistant/components/xbee/*
homeassistant/components/ziggo_mediabox_xl/media_player.py
homeassistant/components/zoneminder/*
homeassistant/components/supla/*

1
.gitignore vendored
View File

@ -106,6 +106,7 @@ virtualization/vagrant/config
!.vscode/cSpell.json
!.vscode/extensions.json
!.vscode/tasks.json
.env
# Built docs
docs/build

View File

@ -22,7 +22,7 @@ repos:
- --quiet-level=2
exclude_types: [csv, json]
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.9
rev: 3.8.1
hooks:
- id: flake8
additional_dependencies:
@ -80,8 +80,8 @@ repos:
entry: script/run-in-env.sh python3 -m script.gen_requirements_all
pass_filenames: false
language: script
types: [json]
files: ^homeassistant/.+/manifest\.json$
types: [text]
files: ^(homeassistant/.+/manifest\.json|\.pre-commit-config\.yaml)$
- id: hassfest
name: hassfest
entry: script/run-in-env.sh python3 -m script.hassfest

View File

@ -14,6 +14,7 @@ homeassistant/scripts/check_config.py @kellerza
# Integrations
homeassistant/components/abode/* @shred86
homeassistant/components/acmeda/* @atmurray
homeassistant/components/adguard/* @frenck
homeassistant/components/agent_dvr/* @ispysoftware
homeassistant/components/airly/* @bieniu
@ -42,7 +43,6 @@ homeassistant/components/atome/* @baqs
homeassistant/components/august/* @bdraco
homeassistant/components/aurora_abb_powerone/* @davet2001
homeassistant/components/auth/* @home-assistant/core
homeassistant/components/automatic/* @armills
homeassistant/components/automation/* @home-assistant/core
homeassistant/components/avea/* @pattyland
homeassistant/components/avri/* @timvancann
@ -68,6 +68,7 @@ homeassistant/components/bt_smarthub/* @jxwolstenholme
homeassistant/components/buienradar/* @mjj4791 @ties
homeassistant/components/cast/* @emontnemery
homeassistant/components/cert_expiry/* @Cereal2nd @jjlawren
homeassistant/components/circuit/* @braam
homeassistant/components/cisco_ios/* @fbradyirl
homeassistant/components/cisco_mobility_express/* @fbradyirl
homeassistant/components/cisco_webex_teams/* @fbradyirl
@ -86,7 +87,7 @@ homeassistant/components/cups/* @fabaff
homeassistant/components/daikin/* @fredrike
homeassistant/components/darksky/* @fabaff
homeassistant/components/deconz/* @Kane610
homeassistant/components/delijn/* @bollewolle
homeassistant/components/delijn/* @bollewolle @Emilv2
homeassistant/components/demo/* @home-assistant/core
homeassistant/components/denonavr/* @scarface-4711 @starkillerOG
homeassistant/components/derivative/* @afaucogney
@ -97,6 +98,7 @@ homeassistant/components/directv/* @ctalkington
homeassistant/components/discogs/* @thibmaek
homeassistant/components/doorbird/* @oblogic7 @bdraco
homeassistant/components/dsmr_reader/* @depl0y
homeassistant/components/dunehd/* @bieniu
homeassistant/components/dweet/* @fabaff
homeassistant/components/dynalite/* @ziv1234
homeassistant/components/dyson/* @etheralm
@ -140,7 +142,6 @@ homeassistant/components/fronius/* @nielstron
homeassistant/components/frontend/* @home-assistant/frontend
homeassistant/components/garmin_connect/* @cyberjunky
homeassistant/components/gdacs/* @exxamalte
homeassistant/components/gearbest/* @HerrHofrat
homeassistant/components/geniushub/* @zxdavb
homeassistant/components/geo_rss_events/* @exxamalte
homeassistant/components/geonetnz_quakes/* @exxamalte
@ -149,6 +150,7 @@ homeassistant/components/gios/* @bieniu
homeassistant/components/gitter/* @fabaff
homeassistant/components/glances/* @fabaff @engrbm87
homeassistant/components/gntp/* @robbiet480
homeassistant/components/gogogate2/* @vangorra
homeassistant/components/google_assistant/* @home-assistant/cloud
homeassistant/components/google_cloud/* @lufton
homeassistant/components/google_translate/* @awarecan
@ -159,6 +161,7 @@ homeassistant/components/griddy/* @bdraco
homeassistant/components/group/* @home-assistant/core
homeassistant/components/growatt_server/* @indykoning
homeassistant/components/gtfs/* @robbiet480
homeassistant/components/guardian/* @bachya
homeassistant/components/harmony/* @ehendrix23 @bramkragten @bdraco
homeassistant/components/hassio/* @home-assistant/hass-io
homeassistant/components/heatmiser/* @andylockran
@ -178,7 +181,7 @@ homeassistant/components/homematicip_cloud/* @SukramJ
homeassistant/components/honeywell/* @zxdavb
homeassistant/components/html5/* @robbiet480
homeassistant/components/http/* @home-assistant/core
homeassistant/components/huawei_lte/* @scop
homeassistant/components/huawei_lte/* @scop @fphammerle
homeassistant/components/huawei_router/* @abmantis
homeassistant/components/hue/* @balloob
homeassistant/components/hunterdouglas_powerview/* @bdraco
@ -193,6 +196,7 @@ homeassistant/components/input_datetime/* @home-assistant/core
homeassistant/components/input_number/* @home-assistant/core
homeassistant/components/input_select/* @home-assistant/core
homeassistant/components/input_text/* @home-assistant/core
homeassistant/components/insteon/* @teharris1
homeassistant/components/integration/* @dgomes
homeassistant/components/intent/* @home-assistant/core
homeassistant/components/intesishome/* @jnimmo
@ -306,11 +310,11 @@ homeassistant/components/pilight/* @trekky12
homeassistant/components/plaato/* @JohNan
homeassistant/components/plant/* @ChristianKuehnel
homeassistant/components/plex/* @jjlawren
homeassistant/components/plugwise/* @laetificat @CoMPaTech @bouwew
homeassistant/components/plugwise/* @CoMPaTech @bouwew
homeassistant/components/plum_lightpad/* @ColinHarrington
homeassistant/components/point/* @fredrike
homeassistant/components/powerwall/* @bdraco @jrester
homeassistant/components/proxmoxve/* @k4ds3
homeassistant/components/proxmoxve/* @k4ds3 @jhollowe
homeassistant/components/ps4/* @ktnrg45
homeassistant/components/ptvsd/* @swamp-ig
homeassistant/components/push/* @dgomes
@ -370,7 +374,6 @@ homeassistant/components/soma/* @ratsept
homeassistant/components/somfy/* @tetienne
homeassistant/components/sonarr/* @ctalkington
homeassistant/components/songpal/* @rytilahti @shenxn
homeassistant/components/sonos/* @amelchio
homeassistant/components/spaceapi/* @fabaff
homeassistant/components/speedtestdotnet/* @rohankapoorcom
homeassistant/components/spider/* @peternijssen
@ -456,7 +459,6 @@ homeassistant/components/withings/* @vangorra
homeassistant/components/wled/* @frenck
homeassistant/components/workday/* @fabaff
homeassistant/components/worldclock/* @fabaff
homeassistant/components/wwlln/* @bachya
homeassistant/components/xbox_live/* @MartinHjelmare
homeassistant/components/xfinity/* @cisasteelersfan
homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi

View File

@ -2,79 +2,139 @@
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
Examples of behavior that contributes to a positive environment for our
community include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior by participants include:
Examples of unacceptable behavior include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
## Enforcement Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [safety@home-assistant.io][email]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
reported to the community leaders responsible for enforcement at
[safety@home-assistant.io][email] or by using the report/flag feature of
the medium used. All complaints will be reviewed and investigated promptly and
fairly.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available [here][version].
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available [here][version].
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder][mozilla].
## Adoption
This Code of Conduct was first adopted January 21st, 2017 and announced in [this][coc-blog] blog post.
This Code of Conduct was first adopted January 21st, 2017 and announced in
[this][coc-blog] blog post and has been updated on May 25th, 2020 to version
2.0 of the [Contributor Covenant][homepage] as announced in [this][coc2-blog]
blog post.
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
For answers to common questions about this code of conduct, see the FAQ at
<https://www.contributor-covenant.org/faq>. Translations are available at
<https://www.contributor-covenant.org/translations>.
[coc-blog]: /blog/2017/01/21/home-assistant-governance/
[coc2-blog]: /blog/2020/05/25/code-of-conduct-updated/
[email]: mailto:safety@home-assistant.io
[coc-blog]: https://home-assistant.io/blog/2017/01/21/home-assistant-governance/
[homepage]: http://contributor-covenant.org
[mozilla]: https://github.com/mozilla/diversity
[version]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html

View File

@ -1,4 +1,4 @@
FROM python:3.8
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.8
RUN \
apt-get update && apt-get install -y --no-install-recommends \

View File

@ -158,7 +158,7 @@ stages:
steps:
- template: templates/azp-step-cache.yaml@azure
parameters:
keyfile: "requirements_test_all.txt | homeassistant/package_constraints.txt"
keyfile: "requirements_test_all.txt | requirements_test.txt | homeassistant/package_constraints.txt"
build: |
set -e
python -m venv venv

View File

@ -14,15 +14,14 @@ import voluptuous as vol
from homeassistant import config as conf_util, config_entries, core, loader
from homeassistant.components import http
from homeassistant.const import (
EVENT_HOMEASSISTANT_CLOSE,
EVENT_HOMEASSISTANT_STOP,
REQUIRED_NEXT_PYTHON_DATE,
REQUIRED_NEXT_PYTHON_VER,
)
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import DATA_SETUP, async_setup_component
from homeassistant.util.logging import AsyncHandler
from homeassistant.setup import DATA_SETUP, DATA_SETUP_STARTED, async_setup_component
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
@ -33,6 +32,8 @@ ERROR_LOG_FILENAME = "home-assistant.log"
# hass.data key for logging information.
DATA_LOGGING = "logging"
LOG_SLOW_STARTUP_INTERVAL = 60
DEBUGGER_INTEGRATIONS = {"ptvsd"}
CORE_INTEGRATIONS = ("homeassistant", "persistent_notification")
LOGGING_INTEGRATIONS = {"logger", "system_log", "sentry"}
@ -43,6 +44,13 @@ STAGE_1_INTEGRATIONS = {
"mqtt_eventstream",
# To provide account link implementations
"cloud",
# Ensure supervisor is available
"hassio",
# Get the frontend up and running as soon
# as possible so problem integrations can
# be removed
"frontend",
"config",
}
@ -278,24 +286,17 @@ def async_enable_logging(
err_handler.setLevel(logging.INFO if verbose else logging.WARNING)
err_handler.setFormatter(logging.Formatter(fmt, datefmt=datefmt))
async_handler = AsyncHandler(hass.loop, err_handler)
async def async_stop_async_handler(_: Any) -> None:
"""Cleanup async handler."""
logging.getLogger("").removeHandler(async_handler) # type: ignore
await async_handler.async_close(blocking=True)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_CLOSE, async_stop_async_handler)
logger = logging.getLogger("")
logger.addHandler(async_handler) # type: ignore
logger.setLevel(logging.INFO)
logger.addHandler(err_handler)
logger.setLevel(logging.INFO if verbose else logging.WARNING)
# Save the log file location for access by other components.
hass.data[DATA_LOGGING] = err_log_path
else:
_LOGGER.error("Unable to set up error log %s (access denied)", err_log_path)
async_activate_log_queue_handler(hass)
async def async_mount_local_lib_path(config_dir: str) -> str:
"""Add local library to Python Path.
@ -331,13 +332,30 @@ async def _async_set_up_integrations(
) -> None:
"""Set up all the integrations."""
setup_started = hass.data[DATA_SETUP_STARTED] = {}
async def async_setup_multi_components(domains: Set[str]) -> None:
"""Set up multiple domains. Log on failure."""
async def _async_log_pending_setups() -> None:
"""Periodic log of setups that are pending for longer than LOG_SLOW_STARTUP_INTERVAL."""
while True:
await asyncio.sleep(LOG_SLOW_STARTUP_INTERVAL)
remaining = [domain for domain in domains if domain in setup_started]
if remaining:
_LOGGER.info(
"Waiting on integrations to complete setup: %s",
", ".join(remaining),
)
futures = {
domain: hass.async_create_task(async_setup_component(hass, domain, config))
for domain in domains
}
log_task = asyncio.create_task(_async_log_pending_setups())
await asyncio.wait(futures.values())
log_task.cancel()
errors = [domain for domain in domains if futures[domain].exception()]
for domain in errors:
exception = futures[domain].exception()
@ -388,6 +406,8 @@ async def _async_set_up_integrations(
)
if stage_1_domains:
_LOGGER.info("Setting up %s", stage_1_domains)
await async_setup_multi_components(stage_1_domains)
# Load all integrations
@ -430,4 +450,5 @@ async def _async_set_up_integrations(
await async_setup_multi_components(stage_2_domains)
# Wrap up startup
_LOGGER.debug("Waiting for startup to wrap up")
await hass.async_block_till_done()

View File

@ -12,7 +12,7 @@
"user": {
"data": {
"password": "Jelsz\u00f3",
"username": "Email c\u00edm"
"username": "E-mail"
},
"title": "T\u00f6ltse ki az Abode bejelentkez\u00e9si adatait"
}

View File

@ -12,7 +12,7 @@
"user": {
"data": {
"password": "Password",
"username": "Indirizzo email"
"username": "E-mail"
},
"title": "Inserisci le tue informazioni di accesso Abode"
}

View File

@ -11,8 +11,8 @@
"step": {
"user": {
"data": {
"password": "[%key_id:common::config_flow::data::password%]",
"username": "[%key_id:common::config_flow::data::email%]"
"password": "Has\u0142o",
"username": "Adres e-mail"
},
"title": "Wprowad\u017a informacje logowania Abode"
}

View File

@ -0,0 +1,59 @@
"""The Rollease Acmeda Automate integration."""
import asyncio
from homeassistant import config_entries, core
from .const import DOMAIN
from .hub import PulseHub
CONF_HUBS = "hubs"
PLATFORMS = ["cover", "sensor"]
async def async_setup(hass: core.HomeAssistant, config: dict):
"""Set up the Rollease Acmeda Automate component."""
return True
async def async_setup_entry(
hass: core.HomeAssistant, config_entry: config_entries.ConfigEntry
):
"""Set up Rollease Acmeda Automate hub from a config entry."""
hub = PulseHub(hass, config_entry)
if not await hub.async_setup():
return False
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][config_entry.entry_id] = hub
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: core.HomeAssistant, config_entry: config_entries.ConfigEntry
):
"""Unload a config entry."""
hub = hass.data[DOMAIN][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 not await hub.async_reset():
return False
if unload_ok:
hass.data[DOMAIN].pop(config_entry.entry_id)
return unload_ok

View File

@ -0,0 +1,89 @@
"""Base class for Acmeda Roller Blinds."""
import aiopulse
from homeassistant.core import callback
from homeassistant.helpers import entity
from homeassistant.helpers.device_registry import async_get_registry as get_dev_reg
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_registry import async_get_registry as get_ent_reg
from .const import ACMEDA_ENTITY_REMOVE, DOMAIN, LOGGER
class AcmedaBase(entity.Entity):
"""Base representation of an Acmeda roller."""
def __init__(self, roller: aiopulse.Roller):
"""Initialize the roller."""
self.roller = roller
async def async_remove_and_unregister(self):
"""Unregister from entity and device registry and call entity remove function."""
LOGGER.error("Removing %s %s", self.__class__.__name__, self.unique_id)
ent_registry = await get_ent_reg(self.hass)
if self.entity_id in ent_registry.entities:
ent_registry.async_remove(self.entity_id)
dev_registry = await get_dev_reg(self.hass)
device = dev_registry.async_get_device(
identifiers={(DOMAIN, self.unique_id)}, connections=set()
)
if device is not None:
dev_registry.async_update_device(
device.id, remove_config_entry_id=self.registry_entry.config_entry_id
)
await self.async_remove()
async def async_added_to_hass(self):
"""Entity has been added to hass."""
self.roller.callback_subscribe(self.notify_update)
self.async_on_remove(
async_dispatcher_connect(
self.hass,
ACMEDA_ENTITY_REMOVE.format(self.roller.id),
self.async_remove_and_unregister,
)
)
async def async_will_remove_from_hass(self):
"""Entity being removed from hass."""
self.roller.callback_unsubscribe(self.notify_update)
@callback
def notify_update(self):
"""Write updated device state information."""
LOGGER.debug("Device update notification received: %s", self.name)
self.async_write_ha_state()
@property
def should_poll(self):
"""Report that Acmeda entities do not need polling."""
return False
@property
def unique_id(self):
"""Return the unique ID of this roller."""
return self.roller.id
@property
def device_id(self):
"""Return the ID of this roller."""
return self.roller.id
@property
def name(self):
"""Return the name of roller."""
return self.roller.name
@property
def device_info(self):
"""Return the device info."""
return {
"identifiers": {(DOMAIN, self.unique_id)},
"name": self.roller.name,
"manufacturer": "Rollease Acmeda",
"via_device": (DOMAIN, self.roller.hub.id),
}

View File

@ -0,0 +1,71 @@
"""Config flow for Rollease Acmeda Automate Pulse Hub."""
import asyncio
from typing import Dict, Optional
import aiopulse
import async_timeout
import voluptuous as vol
from homeassistant import config_entries
from .const import DOMAIN # pylint: disable=unused-import
class AcmedaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a Acmeda config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
def __init__(self):
"""Initialize the config flow."""
self.discovered_hubs: Optional[Dict[str, aiopulse.Hub]] = None
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
if (
user_input is not None
and self.discovered_hubs is not None
# pylint: disable=unsupported-membership-test
and user_input["id"] in self.discovered_hubs
):
# pylint: disable=unsubscriptable-object
return await self.async_create(self.discovered_hubs[user_input["id"]])
# Already configured hosts
already_configured = {
entry.unique_id for entry in self._async_current_entries()
}
hubs = []
try:
with async_timeout.timeout(5):
async for hub in aiopulse.Hub.discover():
if hub.id not in already_configured:
hubs.append(hub)
except asyncio.TimeoutError:
pass
if len(hubs) == 0:
return self.async_abort(reason="all_configured")
if len(hubs) == 1:
return await self.async_create(hubs[0])
self.discovered_hubs = {hub.id: hub for hub in hubs}
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required("id"): vol.In(
{hub.id: f"{hub.id} {hub.host}" for hub in hubs}
)
}
),
)
async def async_create(self, hub):
"""Create the Acmeda Hub entry."""
await self.async_set_unique_id(hub.id, raise_on_progress=False)
return self.async_create_entry(title=hub.id, data={"host": hub.host})

View File

@ -0,0 +1,8 @@
"""Constants for the Rollease Acmeda Automate integration."""
import logging
LOGGER = logging.getLogger(__package__)
DOMAIN = "acmeda"
ACMEDA_HUB_UPDATE = "acmeda_hub_update_{}"
ACMEDA_ENTITY_REMOVE = "acmeda_entity_remove_{}"

View File

@ -0,0 +1,122 @@
"""Support for Acmeda Roller Blinds."""
from homeassistant.components.cover import (
ATTR_POSITION,
SUPPORT_CLOSE,
SUPPORT_CLOSE_TILT,
SUPPORT_OPEN,
SUPPORT_OPEN_TILT,
SUPPORT_SET_POSITION,
SUPPORT_SET_TILT_POSITION,
SUPPORT_STOP,
SUPPORT_STOP_TILT,
CoverEntity,
)
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .base import AcmedaBase
from .const import ACMEDA_HUB_UPDATE, DOMAIN
from .helpers import async_add_acmeda_entities
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Acmeda Rollers from a config entry."""
hub = hass.data[DOMAIN][config_entry.entry_id]
current = set()
@callback
def async_add_acmeda_covers():
async_add_acmeda_entities(
hass, AcmedaCover, config_entry, current, async_add_entities
)
hub.cleanup_callbacks.append(
async_dispatcher_connect(
hass,
ACMEDA_HUB_UPDATE.format(config_entry.entry_id),
async_add_acmeda_covers,
)
)
class AcmedaCover(AcmedaBase, CoverEntity):
"""Representation of a Acmeda cover device."""
@property
def current_cover_position(self):
"""Return the current position of the roller blind.
None is unknown, 0 is closed, 100 is fully open.
"""
position = None
if self.roller.type != 7:
position = 100 - self.roller.closed_percent
return position
@property
def current_cover_tilt_position(self):
"""Return the current tilt of the roller blind.
None is unknown, 0 is closed, 100 is fully open.
"""
position = None
if self.roller.type == 7 or self.roller.type == 10:
position = 100 - self.roller.closed_percent
return position
@property
def supported_features(self):
"""Flag supported features."""
supported_features = 0
if self.current_cover_position is not None:
supported_features |= (
SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP | SUPPORT_SET_POSITION
)
if self.current_cover_tilt_position is not None:
supported_features |= (
SUPPORT_OPEN_TILT
| SUPPORT_CLOSE_TILT
| SUPPORT_STOP_TILT
| SUPPORT_SET_TILT_POSITION
)
return supported_features
@property
def is_closed(self):
"""Return if the cover is closed."""
is_closed = self.roller.closed_percent == 100
return is_closed
async def close_cover(self, **kwargs):
"""Close the roller."""
await self.roller.move_down()
async def open_cover(self, **kwargs):
"""Open the roller."""
await self.roller.move_up()
async def stop_cover(self, **kwargs):
"""Stop the roller."""
await self.roller.move_stop()
async def set_cover_position(self, **kwargs):
"""Move the roller shutter to a specific position."""
await self.roller.move_to(100 - kwargs[ATTR_POSITION])
async def close_cover_tilt(self, **kwargs):
"""Close the roller."""
await self.roller.move_down()
async def open_cover_tilt(self, **kwargs):
"""Open the roller."""
await self.roller.move_up()
async def stop_cover_tilt(self, **kwargs):
"""Stop the roller."""
await self.roller.move_stop()
async def set_cover_tilt(self, **kwargs):
"""Tilt the roller shutter to a specific position."""
await self.roller.move_to(100 - kwargs[ATTR_POSITION])

View File

@ -0,0 +1,10 @@
"""Errors for the Acmeda Pulse component."""
from homeassistant.exceptions import HomeAssistantError
class PulseException(HomeAssistantError):
"""Base class for Acmeda Pulse exceptions."""
class CannotConnect(PulseException):
"""Unable to connect to the bridge."""

View File

@ -0,0 +1,41 @@
"""Helper functions for Acmeda Pulse."""
from homeassistant.core import callback
from homeassistant.helpers.device_registry import async_get_registry as get_dev_reg
from .const import DOMAIN, LOGGER
@callback
def async_add_acmeda_entities(
hass, entity_class, config_entry, current, async_add_entities
):
"""Add any new entities."""
hub = hass.data[DOMAIN][config_entry.entry_id]
LOGGER.debug("Looking for new %s on: %s", entity_class.__name__, hub.host)
api = hub.api.rollers
new_items = []
for unique_id, roller in api.items():
if unique_id not in current:
LOGGER.debug("New %s %s", entity_class.__name__, unique_id)
new_item = entity_class(roller)
current.add(unique_id)
new_items.append(new_item)
async_add_entities(new_items)
async def update_devices(hass, config_entry, api):
"""Tell hass that device info has been updated."""
dev_registry = await get_dev_reg(hass)
for api_item in api.values():
# Update Device name
device = dev_registry.async_get_device(
identifiers={(DOMAIN, api_item.id)}, connections=set()
)
if device is not None:
dev_registry.async_update_device(
device.id, name=api_item.name,
)

View File

@ -0,0 +1,88 @@
"""Code to handle a Pulse Hub."""
import asyncio
from typing import Optional
import aiopulse
from homeassistant.helpers.dispatcher import async_dispatcher_send
from .const import ACMEDA_ENTITY_REMOVE, ACMEDA_HUB_UPDATE, LOGGER
from .helpers import update_devices
class PulseHub:
"""Manages a single Pulse Hub."""
def __init__(self, hass, config_entry):
"""Initialize the system."""
self.config_entry = config_entry
self.hass = hass
self.api: Optional[aiopulse.Hub] = None
self.tasks = []
self.current_rollers = {}
self.cleanup_callbacks = []
@property
def title(self):
"""Return the title of the hub shown in the integrations list."""
return f"{self.api.id} ({self.api.host})"
@property
def host(self):
"""Return the host of this hub."""
return self.config_entry.data["host"]
async def async_setup(self, tries=0):
"""Set up a hub based on host parameter."""
host = self.host
hub = aiopulse.Hub(host)
self.api = hub
hub.callback_subscribe(self.async_notify_update)
self.tasks.append(asyncio.create_task(hub.run()))
LOGGER.debug("Hub setup complete")
return True
async def async_reset(self):
"""Reset this hub to default state."""
for cleanup_callback in self.cleanup_callbacks:
cleanup_callback()
# If not setup
if self.api is None:
return False
self.api.callback_unsubscribe(self.async_notify_update)
await self.api.stop()
del self.api
self.api = None
# Wait for any running tasks to complete
await asyncio.wait(self.tasks)
return True
async def async_notify_update(self, update_type):
"""Evaluate entities when hub reports that update has occurred."""
LOGGER.debug("Hub {update_type.name} updated")
if update_type == aiopulse.UpdateType.rollers:
await update_devices(self.hass, self.config_entry, self.api.rollers)
self.hass.config_entries.async_update_entry(
self.config_entry, title=self.title
)
async_dispatcher_send(
self.hass, ACMEDA_HUB_UPDATE.format(self.config_entry.entry_id)
)
for unique_id in list(self.current_rollers):
if unique_id not in self.api.rollers:
LOGGER.debug("Notifying remove of %s", unique_id)
self.current_rollers.pop(unique_id)
async_dispatcher_send(
self.hass, ACMEDA_ENTITY_REMOVE.format(unique_id)
)

View File

@ -0,0 +1,10 @@
{
"domain": "acmeda",
"name": "Rollease Acmeda Automate",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/acmeda",
"requirements": ["aiopulse==0.4.0"],
"codeowners": [
"@atmurray"
]
}

View File

@ -0,0 +1,46 @@
"""Support for Acmeda Roller Blind Batteries."""
from homeassistant.const import DEVICE_CLASS_BATTERY, UNIT_PERCENTAGE
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .base import AcmedaBase
from .const import ACMEDA_HUB_UPDATE, DOMAIN
from .helpers import async_add_acmeda_entities
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Acmeda Rollers from a config entry."""
hub = hass.data[DOMAIN][config_entry.entry_id]
current = set()
@callback
def async_add_acmeda_sensors():
async_add_acmeda_entities(
hass, AcmedaBattery, config_entry, current, async_add_entities
)
hub.cleanup_callbacks.append(
async_dispatcher_connect(
hass,
ACMEDA_HUB_UPDATE.format(config_entry.entry_id),
async_add_acmeda_sensors,
)
)
class AcmedaBattery(AcmedaBase):
"""Representation of a Acmeda cover device."""
device_class = DEVICE_CLASS_BATTERY
unit_of_measurement = UNIT_PERCENTAGE
@property
def name(self):
"""Return the name of roller."""
return f"{super().name} Battery"
@property
def state(self):
"""Return the state of the device."""
return self.roller.battery

View File

@ -0,0 +1,16 @@
{
"title": "Rollease Acmeda Automate",
"config": {
"step": {
"user": {
"title": "Pick a hub to add",
"data": {
"id": "Host ID"
}
}
},
"abort": {
"all_configured": "No new Pulse hubs discovered."
}
}
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "No s'han descobert nous hubs de Pulse."
},
"step": {
"user": {
"data": {
"id": "ID d'amfitri\u00f3"
},
"title": "Selecci\u00f3 del Hub a afegir"
}
}
},
"title": "Rollease Acmeda Automate"
}

View File

@ -3,8 +3,7 @@
"step": {
"user": {
"data": {
"latitude": "Latitude",
"longitude": "Longitude"
"id": "Host-ID"
}
}
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "No new Pulse hubs discovered."
},
"step": {
"user": {
"data": {
"id": "Host ID"
},
"title": "Pick a hub to add"
}
}
},
"title": "Rollease Acmeda Automate"
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "No se han descubierto nuevos hubs Pulse."
},
"step": {
"user": {
"data": {
"id": "ID de host"
},
"title": "Elige un hub para a\u00f1adir"
}
}
},
"title": "Rollease Acmeda Automate"
}

View File

@ -0,0 +1,12 @@
{
"config": {
"step": {
"user": {
"data": {
"id": "ID de l'h\u00f4te"
},
"title": "Choisissez un hub \u00e0 ajouter"
}
}
}
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "Non sono stati scoperti nuovi hub Pulse."
},
"step": {
"user": {
"data": {
"id": "ID host"
},
"title": "Scegliere un hub da aggiungere"
}
}
},
"title": "Rollease Acmeda Automate"
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "\ubc1c\uacac\ub41c \uc0c8\ub85c\uc6b4 Pulse \ud5c8\ube0c\uac00 \uc5c6\uc2b5\ub2c8\ub2e4."
},
"step": {
"user": {
"data": {
"id": "\ud638\uc2a4\ud2b8 ID"
},
"title": "\ucd94\uac00\ud560 \ud5c8\ube0c \uc120\ud0dd\ud558\uae30"
}
}
},
"title": "Rollease Acmeda Automate"
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "Keng nei Pulse Hubs entdeckt."
},
"step": {
"user": {
"data": {
"id": "Host ID"
},
"title": "Wiel den Hub aus dee soll dob\u00e4igesat ginn."
}
}
},
"title": "Rollease ACmeda Automate"
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "Geen nieuwe Pulse hubs ontdekt."
},
"step": {
"user": {
"data": {
"id": "Host ID"
},
"title": "Kies een hub om toe te voegen"
}
}
},
"title": "Rollease Acmeda Automate"
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "Ingen nye Pulse-hub oppdaget."
},
"step": {
"user": {
"data": {
"id": "Verts-ID"
},
"title": "Velg en hub du vil legge til"
}
}
},
"title": ""
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "Nie wykryto hub\u00f3w Pulse."
},
"step": {
"user": {
"data": {
"id": "ID hosta"
},
"title": "Wybierz hub, kt\u00f3ry chcesz doda\u0107"
}
}
},
"title": "Rollease Acmeda Automate"
}

View File

@ -0,0 +1,16 @@
{
"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."
},
"step": {
"user": {
"data": {
"id": "ID \u0445\u043e\u0441\u0442\u0430"
},
"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"
}

View File

@ -0,0 +1,16 @@
{
"config": {
"abort": {
"all_configured": "\u672a\u641c\u5c0b\u5230 Pulse hub"
},
"step": {
"user": {
"data": {
"id": "\u4e3b\u6a5f ID"
},
"title": "\u9078\u64c7\u6240\u8981\u65b0\u589e\u7684 Hub"
}
}
},
"title": "Rollease Acmeda Automate"
}

View File

@ -21,8 +21,7 @@
"username": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435",
"verify_ssl": "AdGuard Home \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 \u043d\u0430\u0434\u0435\u0436\u0434\u0435\u043d \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442"
},
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0412\u0430\u0448\u0438\u044f AdGuard Home, \u0437\u0430 \u0434\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u0435 \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b.",
"title": "\u0421\u0432\u044a\u0440\u0436\u0435\u0442\u0435 \u0412\u0430\u0448\u0438\u044f AdGuard Home."
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0412\u0430\u0448\u0438\u044f AdGuard Home, \u0437\u0430 \u0434\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u0435 \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "[%key::common::config_flow::data::username%]",
"verify_ssl": "AdGuard Home utilitza un certificat adequat"
},
"description": "Configuraci\u00f3 de la inst\u00e0ncia d'AdGuard Home, permet el control i la monitoritzaci\u00f3.",
"title": "Enlla\u00e7ar AdGuard Home."
"description": "Configuraci\u00f3 de la inst\u00e0ncia d'AdGuard Home, permet el control i la monitoritzaci\u00f3."
}
}
}

View File

@ -21,8 +21,7 @@
"username": "Brugernavn",
"verify_ssl": "AdGuard Home bruger et korrekt certifikat"
},
"description": "Konfigurer din AdGuard Home-instans for at tillade overv\u00e5gning og kontrol.",
"title": "Forbind din AdGuard Home."
"description": "Konfigurer din AdGuard Home-instans for at tillade overv\u00e5gning og kontrol."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "Benutzername",
"verify_ssl": "AdGuard Home verwendet ein richtiges Zertifikat"
},
"description": "Richte deine AdGuard Home-Instanz ein um sie zu \u00dcberwachen und zu Steuern.",
"title": "Verkn\u00fcpfe AdGuard Home."
"description": "Richte deine AdGuard Home-Instanz ein um sie zu \u00dcberwachen und zu Steuern."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "Username",
"verify_ssl": "AdGuard Home uses a proper certificate"
},
"description": "Set up your AdGuard Home instance to allow monitoring and control.",
"title": "Link your AdGuard Home."
"description": "Set up your AdGuard Home instance to allow monitoring and control."
}
}
}

View File

@ -16,13 +16,14 @@
},
"user": {
"data": {
"host": "Host",
"password": "Contrase\u00f1a",
"port": "Puerto",
"ssl": "AdGuard Home utiliza un certificado SSL",
"username": "Nombre de usuario",
"verify_ssl": "AdGuard Home utiliza un certificado adecuado"
},
"description": "Configure su instancia de AdGuard Home para permitir la supervisi\u00f3n y el control.",
"title": "Enlace su AdGuard Home."
"description": "Configure su instancia de AdGuard Home para permitir la supervisi\u00f3n y el control."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "Usuario",
"verify_ssl": "AdGuard Home utiliza un certificado apropiado"
},
"description": "Configure su instancia de AdGuard Home para permitir la supervisi\u00f3n y el control.",
"title": "Enlace su AdGuard Home."
"description": "Configure su instancia de AdGuard Home para permitir la supervisi\u00f3n y el control."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "Nom d'utilisateur",
"verify_ssl": "AdGuard Home utilise un certificat appropri\u00e9"
},
"description": "Configurez votre instance AdGuard Home pour permettre la surveillance et le contr\u00f4le.",
"title": "Liez votre AdGuard Home."
"description": "Configurez votre instance AdGuard Home pour permettre la surveillance et le contr\u00f4le."
}
}
}

View File

@ -3,6 +3,7 @@
"step": {
"user": {
"data": {
"host": "Hoszt",
"password": "Jelsz\u00f3",
"port": "Port",
"username": "Felhaszn\u00e1l\u00f3n\u00e9v"

View File

@ -23,8 +23,7 @@
"username": "Nome utente",
"verify_ssl": "AdGuard Home utilizza un certificato appropriato"
},
"description": "Configura l'istanza di AdGuard Home per consentire il monitoraggio e il controllo.",
"title": "Collega la tua AdGuard Home."
"description": "Configura l'istanza di AdGuard Home per consentire il monitoraggio e il controllo."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "\uc0ac\uc6a9\uc790 \uc774\ub984",
"verify_ssl": "AdGuard Home \uc740 \uc62c\ubc14\ub978 \uc778\uc99d\uc11c\ub97c \uc0ac\uc6a9\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4"
},
"description": "\ubaa8\ub2c8\ud130\ub9c1 \ubc0f \uc81c\uc5b4\uac00 \uac00\ub2a5\ud558\ub3c4\ub85d AdGuard Home \uc778\uc2a4\ud134\uc2a4\ub97c \uc124\uc815\ud574\uc8fc\uc138\uc694.",
"title": "AdGuard Home \uc5f0\uacb0\ud558\uae30"
"description": "\ubaa8\ub2c8\ud130\ub9c1 \ubc0f \uc81c\uc5b4\uac00 \uac00\ub2a5\ud558\ub3c4\ub85d AdGuard Home \uc778\uc2a4\ud134\uc2a4\ub97c \uc124\uc815\ud574\uc8fc\uc138\uc694."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "Benotzernumm",
"verify_ssl": "AdGuard Home benotzt een eegenen Zertifikat"
},
"description": "Konfigur\u00e9iert \u00e4r AdGuard Home Instanz fir d'Iwwerwaachung an d'Kontroll z'erlaben.",
"title": "Verbannt \u00e4ren AdGuard Home"
"description": "Konfigur\u00e9iert \u00e4r AdGuard Home Instanz fir d'Iwwerwaachung an d'Kontroll z'erlaben."
}
}
}

View File

@ -21,8 +21,7 @@
"username": "Gebruikersnaam",
"verify_ssl": "AdGuard Home maakt gebruik van een goed certificaat"
},
"description": "Stel uw AdGuard Home-instantie in om toezicht en controle mogelijk te maken.",
"title": "Link uw AdGuard Home."
"description": "Stel uw AdGuard Home-instantie in om toezicht en controle mogelijk te maken."
}
}
}

View File

@ -21,8 +21,7 @@
"ssl": "AdGuard Hjem bruker et SSL-sertifikat",
"verify_ssl": "AdGuard Home bruker et riktig sertifikat"
},
"description": "Sett opp din AdGuard Hjem instans for \u00e5 tillate overv\u00e5king og kontroll.",
"title": "Koble til ditt AdGuard Hjem."
"description": "Sett opp din AdGuard Hjem instans for \u00e5 tillate overv\u00e5king og kontroll."
}
}
}

View File

@ -7,7 +7,7 @@
"single_instance_allowed": "Dozwolona jest tylko jedna konfiguracja AdGuard Home."
},
"error": {
"connection_error": "[%key_id:common::config_flow::error::cannot_connect%]"
"connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia."
},
"step": {
"hassio_confirm": {
@ -16,15 +16,14 @@
},
"user": {
"data": {
"host": "[%key_id:common::config_flow::data::host%]",
"password": "[%key_id:common::config_flow::data::password%]",
"port": "[%key_id:common::config_flow::data::port%]",
"host": "Nazwa hosta lub adres IP",
"password": "Has\u0142o",
"port": "Port",
"ssl": "AdGuard Home u\u017cywa certyfikatu SSL",
"username": "[%key_id:common::config_flow::data::username%]",
"username": "Nazwa u\u017cytkownika",
"verify_ssl": "AdGuard Home u\u017cywa odpowiedniego certyfikatu."
},
"description": "Skonfiguruj instancj\u0119 AdGuard Home, aby umo\u017cliwi\u0107 monitorowanie i kontrol\u0119.",
"title": "Po\u0142\u0105cz AdGuard Home"
"description": "Skonfiguruj instancj\u0119 AdGuard Home, aby umo\u017cliwi\u0107 monitorowanie i kontrol\u0119."
}
}
}

View File

@ -19,8 +19,7 @@
"username": "Nome de usu\u00e1rio",
"verify_ssl": "O AdGuard Home usa um certificado apropriado"
},
"description": "Configure sua inst\u00e2ncia do AdGuard Home para permitir o monitoramento e o controle.",
"title": "Vincule o seu AdGuard Home."
"description": "Configure sua inst\u00e2ncia do AdGuard Home para permitir o monitoramento e o controle."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "\u041b\u043e\u0433\u0438\u043d",
"verify_ssl": "AdGuard Home \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442"
},
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 Home Assistant \u0434\u043b\u044f \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f AdGuard Home.",
"title": "AdGuard Home"
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 Home Assistant \u0434\u043b\u044f \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f AdGuard Home."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "Uporabni\u0161ko ime",
"verify_ssl": "AdGuard Home uporablja ustrezen certifikat"
},
"description": "Nastavite primerek AdGuard Home, da omogo\u010dite spremljanje in nadzor.",
"title": "Pove\u017eite svoj AdGuard Home."
"description": "Nastavite primerek AdGuard Home, da omogo\u010dite spremljanje in nadzor."
}
}
}

View File

@ -21,8 +21,7 @@
"username": "Anv\u00e4ndarnamn",
"verify_ssl": "AdGuard Home anv\u00e4nder ett korrekt certifikat"
},
"description": "St\u00e4ll in din AdGuard Home-instans f\u00f6r att till\u00e5ta \u00f6vervakning och kontroll.",
"title": "L\u00e4nka din AdGuard Home."
"description": "St\u00e4ll in din AdGuard Home-instans f\u00f6r att till\u00e5ta \u00f6vervakning och kontroll."
}
}
}

View File

@ -23,8 +23,7 @@
"username": "\u4f7f\u7528\u8005\u540d\u7a31",
"verify_ssl": "AdGuard Home \u4f7f\u7528\u5c0d\u61c9\u8a8d\u8b49"
},
"description": "\u8a2d\u5b9a AdGuard Home \u4ee5\u9032\u884c\u76e3\u63a7\u3002",
"title": "\u9023\u7d50 AdGuard Home\u3002"
"description": "\u8a2d\u5b9a AdGuard Home \u4ee5\u9032\u884c\u76e3\u63a7\u3002"
}
}
}

View File

@ -0,0 +1,21 @@
{
"config": {
"abort": {
"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"
},
"step": {
"user": {
"data": {
"host": "Host",
"port": "Puerto"
},
"title": "Configurar Agent DVR"
}
}
},
"title": "Agent DVR"
}

View File

@ -12,7 +12,8 @@
"data": {
"host": "H\u00f4te",
"port": "Port"
}
},
"title": "Configurer l'agent DVR"
}
}
},

View File

@ -3,8 +3,8 @@
"step": {
"user": {
"data": {
"latitude": "Leveysaste",
"longitude": "Pituusaste"
"host": "Hoszt",
"port": "Port"
}
}
}

View File

@ -1,7 +1,7 @@
{
"config": {
"abort": {
"already_configured": "[%key_id:common::config_flow::abort::already_configured_device%]"
"already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane."
},
"error": {
"already_in_progress": "Konfiguracja urz\u0105dzenia jest ju\u017c w toku.",
@ -10,8 +10,8 @@
"step": {
"user": {
"data": {
"host": "[%key_id:common::config_flow::data::host%]",
"port": "[%key_id:common::config_flow::data::port%]"
"host": "Nazwa hosta lub adres IP",
"port": "Port"
},
"title": "Konfiguracja Agent DVR"
}

View File

@ -0,0 +1,7 @@
{
"config": {
"error": {
"device_unavailable": "O dispositivo n\u00e3o est\u00e1 dispon\u00edvel"
}
}
}

View File

@ -10,7 +10,7 @@
"step": {
"user": {
"data": {
"api_key": "Clau API d'Airly",
"api_key": "Clau API",
"latitude": "Latitud",
"longitude": "Longitud",
"name": "Nom de la integraci\u00f3"

View File

@ -10,7 +10,7 @@
"step": {
"user": {
"data": {
"api_key": "Airly API kulcs",
"api_key": "API kulcs",
"latitude": "Sz\u00e9less\u00e9g",
"longitude": "Hossz\u00fas\u00e1g",
"name": "Az integr\u00e1ci\u00f3 neve"

View File

@ -10,7 +10,7 @@
"step": {
"user": {
"data": {
"api_key": "Chiave API Airly",
"api_key": "Chiave API",
"latitude": "Latitudine",
"longitude": "Logitudine",
"name": "Nome dell'integrazione"

View File

@ -10,7 +10,7 @@
"step": {
"user": {
"data": {
"api_key": "[%key_id:common::config_flow::data::api_key%] Airly",
"api_key": "Klucz API",
"latitude": "Szeroko\u015b\u0107 geograficzna",
"longitude": "D\u0142ugo\u015b\u0107 geograficzna",
"name": "Nazwa integracji"

View File

@ -1,7 +1,7 @@
{
"config": {
"abort": {
"already_configured": "Aquesta clau API ja est\u00e0 sent utilitzada."
"already_configured": "Aquestes coordenades o Node/Pro ID ja estan registrades."
},
"error": {
"general_error": "S'ha produ\u00eft un error desconegut.",
@ -21,21 +21,18 @@
"node_pro": {
"data": {
"ip_address": "Adre\u00e7a IP o amfitri\u00f3 de la unitat",
"password": "Contrasenya de la unitat"
"password": "Contrasenya"
},
"description": "Monitoritza una unitat personal d'AirVisual. Pots obtenir la contrasenya des de la interf\u00edcie d'usuari (UI) de la unitat.",
"title": "Configuraci\u00f3 d'AirVisual Node/Pro"
},
"user": {
"data": {
"api_key": "Clau API",
"cloud_api": "Ubicaci\u00f3 geogr\u00e0fica",
"latitude": "Latitud",
"longitude": "Longitud",
"node_pro": "AirVisual Node Pro",
"type": "Tipus d'integraci\u00f3"
},
"description": "Monitoritzaci\u00f3 de la qualitat de l'aire per ubicaci\u00f3 geogr\u00e0fica.",
"description": "Tria quin tipus de dades d'AirVisual vols monitoritzar.",
"title": "Configura AirVisual"
}
}
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Mostra al mapa l'\u00e0rea geogr\u00e0fica monitoritzada"
},
"description": "Estableix les diferents opcions de la integraci\u00f3 AirVisual.",
"title": "Configuraci\u00f3 d'AirVisual"
}
}

View File

@ -27,10 +27,7 @@
},
"user": {
"data": {
"api_key": "API-Schl\u00fcssel",
"cloud_api": "Geografische Position",
"latitude": "Breitengrad",
"longitude": "L\u00e4ngengrad",
"node_pro": "AirVisual Node Pro",
"type": "Integrationstyp"
},
@ -45,7 +42,6 @@
"data": {
"show_on_map": "Zeigen Sie die \u00fcberwachte Geografie auf der Karte an"
},
"description": "Legen Sie verschiedene Optionen f\u00fcr die AirVisual-Integration fest.",
"title": "Konfigurieren Sie AirVisual"
}
}

View File

@ -28,10 +28,7 @@
},
"user": {
"data": {
"api_key": "API Key",
"cloud_api": "Geographical Location",
"latitude": "Latitude",
"longitude": "Longitude",
"node_pro": "AirVisual Node Pro",
"type": "Integration Type"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Show monitored geography on the map"
},
"description": "Set various options for the AirVisual integration.",
"title": "Configure AirVisual"
}
}

View File

@ -5,11 +5,13 @@
},
"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."
},
"step": {
"geography": {
"data": {
"api_key": "Clave API",
"latitude": "Latitud",
"longitude": "Longitud"
},
@ -26,10 +28,7 @@
},
"user": {
"data": {
"api_key": "Clave API",
"cloud_api": "Localizaci\u00f3n geogr\u00e1fica",
"latitude": "Latitud",
"longitude": "Longitud",
"node_pro": "AirVisual Node Pro",
"type": "Tipo de integraci\u00f3n"
},
@ -44,7 +43,6 @@
"data": {
"show_on_map": "Mostrar geograf\u00eda monitoreada en el mapa"
},
"description": "Establezca varias opciones para la integraci\u00f3n de AirVisual.",
"title": "Configurar AirVisual"
}
}

View File

@ -21,21 +21,18 @@
"node_pro": {
"data": {
"ip_address": "Direcci\u00f3n IP/Nombre de host de la Unidad",
"password": "Contrase\u00f1a de la Unidad"
"password": "Contrase\u00f1a"
},
"description": "Monitorizar una unidad personal AirVisual. La contrase\u00f1a puede ser recuperada desde la interfaz de la unidad.",
"title": "Configurar un AirVisual Node/Pro"
},
"user": {
"data": {
"api_key": "Clave API",
"cloud_api": "Ubicaci\u00f3n Geogr\u00e1fica",
"latitude": "Latitud",
"longitude": "Longitud",
"node_pro": "AirVisual Node Pro",
"type": "Tipo de Integraci\u00f3n"
},
"description": "Elige qu\u00e9 tipo de datos de AirVisual quieres monitorear.",
"description": "Elige qu\u00e9 tipo de datos de AirVisual quieres monitorizar.",
"title": "Configurar AirVisual"
}
}
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Mostrar geograf\u00eda monitorizada en el mapa"
},
"description": "Ajustar varias opciones para la integraci\u00f3n de AirVisual.",
"title": "Configurar AirVisual"
}
}

View File

@ -28,10 +28,7 @@
},
"user": {
"data": {
"api_key": "Cl\u00e9 API",
"cloud_api": "Localisation g\u00e9ographique",
"latitude": "Latitude",
"longitude": "Longitude",
"node_pro": "AirVisual Node Pro",
"type": "Type d'int\u00e9gration"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Afficher la g\u00e9ographie surveill\u00e9e sur la carte"
},
"description": "D\u00e9finissez diverses options pour l'int\u00e9gration d'AirVisual.",
"title": "Configurer AirVisual"
}
}

View File

@ -6,10 +6,15 @@
"step": {
"geography": {
"data": {
"api_key": "API Kulcs",
"api_key": "API kulcs",
"latitude": "Sz\u00e9less\u00e9g",
"longitude": "Hossz\u00fas\u00e1g"
}
},
"node_pro": {
"data": {
"password": "Jelsz\u00f3"
}
}
}
}

View File

@ -21,17 +21,14 @@
"node_pro": {
"data": {
"ip_address": "Indirizzo IP/Nome host dell'unit\u00e0",
"password": "Password dell'unit\u00e0"
"password": "Password"
},
"description": "Monitorare un'unit\u00e0 AirVisual personale. La password pu\u00f2 essere recuperata dall'interfaccia utente dell'unit\u00e0.",
"title": "Configurare un AirVisual Node/Pro"
},
"user": {
"data": {
"api_key": "Chiave API",
"cloud_api": "Posizione geografica",
"latitude": "Latitudine",
"longitude": "Logitudine",
"node_pro": "AirVisual Node Pro",
"type": "Tipo di integrazione"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Mostra l'area geografica monitorata sulla mappa"
},
"description": "Impostare varie opzioni per l'integrazione AirVisual.",
"title": "Configurare AirVisual"
}
}

View File

@ -28,10 +28,7 @@
},
"user": {
"data": {
"api_key": "API \ud0a4",
"cloud_api": "\uc9c0\ub9ac\uc801 \uc704\uce58",
"latitude": "\uc704\ub3c4",
"longitude": "\uacbd\ub3c4",
"node_pro": "AirVisual Node Pro",
"type": "\uc5f0\ub3d9 \uc720\ud615"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "\uc9c0\ub3c4\uc5d0 \ubaa8\ub2c8\ud130\ub9c1\ub41c \uc9c0\ub9ac \uc815\ubcf4 \ud45c\uc2dc"
},
"description": "AirVisual \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\uc5d0 \ub300\ud55c \ub2e4\uc591\ud55c \uc635\uc158\uc744 \uc124\uc815\ud574\uc8fc\uc138\uc694.",
"title": "AirVisual \uad6c\uc131\ud558\uae30"
}
}

View File

@ -28,10 +28,7 @@
},
"user": {
"data": {
"api_key": "API Schl\u00ebssel",
"cloud_api": "Geografesche Standuert",
"latitude": "Breedegrad",
"longitude": "L\u00e4ngegrad",
"node_pro": "Airvisual Node Pro",
"type": "Typ vun der Integratioun"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Iwwerwaachte Geografie op der Kaart uweisen"
},
"description": "Verschidden Optioune fir d'AirVisual Integratioun d\u00e9fin\u00e9ieren.",
"title": "Airvisual ariichten"
}
}

View File

@ -26,10 +26,7 @@
},
"user": {
"data": {
"api_key": "API-sleutel",
"cloud_api": "Geografische ligging",
"latitude": "Breedtegraad",
"longitude": "Lengtegraad",
"node_pro": "AirVisual Node Pro",
"type": "Integratietype"
},
@ -44,7 +41,6 @@
"data": {
"show_on_map": "Toon gecontroleerde geografie op de kaart"
},
"description": "Stel verschillende opties in voor de AirVisual-integratie.",
"title": "Configureer AirVisual"
}
}

View File

@ -28,10 +28,7 @@
},
"user": {
"data": {
"api_key": "API-n\u00f8kkel",
"cloud_api": "Geografisk plassering",
"latitude": "Breddegrad",
"longitude": "Lengdegrad",
"node_pro": "",
"type": "Integrasjonstype"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Vis overv\u00e5ket geografi p\u00e5 kartet"
},
"description": "Angi forskjellige alternativer for AirVisual-integrasjonen.",
"title": "Konfigurer AirVisual"
}
}

View File

@ -4,14 +4,14 @@
"already_configured": "Ten klucz API jest ju\u017c w u\u017cyciu."
},
"error": {
"general_error": "[%key_id:common::config_flow::error::unknown%]",
"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."
},
"step": {
"geography": {
"data": {
"api_key": "[%key_id:common::config_flow::data::api_key%]",
"api_key": "Klucz API",
"latitude": "Szeroko\u015b\u0107 geograficzna",
"longitude": "D\u0142ugo\u015b\u0107 geograficzna"
},
@ -20,18 +20,15 @@
},
"node_pro": {
"data": {
"ip_address": "[%key_id:common::config_flow::data::host%]",
"password": "[%key_id:common::config_flow::data::password%] jednostki"
"ip_address": "Nazwa hosta lub adres IP",
"password": "Has\u0142o"
},
"description": "Monitoruj jednostk\u0119 AirVisual. Has\u0142o mo\u017cna odzyska\u0107 z interfejsu u\u017cytkownika urz\u0105dzenia.",
"title": "Konfiguracja AirVisual Node/Pro"
},
"user": {
"data": {
"api_key": "[%key_id:common::config_flow::data::api_key%]",
"cloud_api": "Lokalizacja geograficzna",
"latitude": "Szeroko\u015b\u0107 geograficzna",
"longitude": "D\u0142ugo\u015b\u0107 geograficzna",
"node_pro": "AirVisual Node Pro",
"type": "Typ integracji"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Wy\u015bwietlaj encje na mapie"
},
"description": "Konfiguracja opcji integracji AirVisual.",
"title": "Konfiguracja AirVisual"
}
}

View File

@ -0,0 +1,21 @@
{
"config": {
"error": {
"general_error": "Ocorreu um erro desconhecido.",
"invalid_api_key": "Chave de API fornecida \u00e9 inv\u00e1lida."
},
"step": {
"geography": {
"data": {
"latitude": "Latitude",
"longitude": "Longitude"
}
},
"user": {
"data": {
"type": "Tipo de Integra\u00e7\u00e3o"
}
}
}
}
}

View File

@ -28,10 +28,7 @@
},
"user": {
"data": {
"api_key": "\u041a\u043b\u044e\u0447 API",
"cloud_api": "\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435",
"latitude": "\u0428\u0438\u0440\u043e\u0442\u0430",
"longitude": "\u0414\u043e\u043b\u0433\u043e\u0442\u0430",
"node_pro": "AirVisual Node Pro",
"type": "\u0422\u0438\u043f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c\u0443\u044e \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u043d\u0430 \u043a\u0430\u0440\u0442\u0435"
},
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 AirVisual.",
"title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 AirVisual"
}
}

View File

@ -28,10 +28,7 @@
},
"user": {
"data": {
"api_key": "API Klju\u010d",
"cloud_api": "Geografska lokacija",
"latitude": "Zemljepisna \u0161irina",
"longitude": "Zemljepisna dol\u017eina",
"node_pro": "AirVisual Node Pro",
"type": "Vrsta integracije"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "Prika\u017ei nadzorovano obmo\u010dje na zemljevidu"
},
"description": "Nastavite razli\u010dne mo\u017enosti za integracijo AirVisual.",
"title": "Nastavite AirVisual"
}
}

View File

@ -18,10 +18,7 @@
},
"user": {
"data": {
"api_key": "API-nyckel",
"cloud_api": "Geografisk Plats",
"latitude": "Latitud",
"longitude": "Longitud",
"type": "Integrationstyp"
}
}

View File

@ -5,7 +5,7 @@
},
"error": {
"general_error": "\u767c\u751f\u672a\u77e5\u932f\u8aa4\u3002",
"invalid_api_key": "API \u5bc6\u78bc\u7121\u6548\u3002",
"invalid_api_key": "API \u5bc6\u9470\u7121\u6548\u3002",
"unable_to_connect": "\u7121\u6cd5\u9023\u7dda\u81f3 Node/Pro \u8a2d\u5099\u3002"
},
"step": {
@ -28,10 +28,7 @@
},
"user": {
"data": {
"api_key": "API \u5bc6\u9470",
"cloud_api": "\u5730\u7406\u5ea7\u6a19",
"latitude": "\u7def\u5ea6",
"longitude": "\u7d93\u5ea6",
"node_pro": "AirVisual Node Pro",
"type": "\u6574\u5408\u985e\u578b"
},
@ -46,7 +43,6 @@
"data": {
"show_on_map": "\u65bc\u5730\u5716\u4e0a\u986f\u793a\u76e3\u63a7\u4f4d\u7f6e\u3002"
},
"description": "\u8a2d\u5b9a AirVisual \u6574\u5408\u9078\u9805\u3002",
"title": "\u8a2d\u5b9a AirVisual"
}
}

View File

@ -24,13 +24,13 @@
},
"state": {
"_": {
"armed": "Armado",
"armed": "Armada",
"armed_away": "Armada ausente",
"armed_custom_bypass": "Armada personalizada",
"armed_home": "Armada en casa",
"armed_night": "Armada noche",
"arming": "Armando",
"disarmed": "Desarmado",
"disarmed": "Desarmada",
"disarming": "Desarmando",
"pending": "Pendiente",
"triggered": "Disparada"

View File

@ -7,6 +7,13 @@
"disarm": "Desarmar {entity_name}",
"trigger": "Disparar {entidade_nome}"
},
"condition_type": {
"is_armed_away": "{entity_name} est\u00e1 armado modo longe",
"is_armed_home": "{entity_name} est\u00e1 armadado modo casa",
"is_armed_night": "{entity_name} est\u00e1 armadado modo noite",
"is_disarmed": "{entity_name} est\u00e1 desarmado",
"is_triggered": "{entity_name} est\u00e1 acionado"
},
"trigger_type": {
"armed_away": "{entity_name} armado modo longe",
"armed_home": "{entity_name} armadado modo casa",

View File

@ -3,15 +3,13 @@ import logging
import voluptuous as vol
from homeassistant.const import CONF_NAME
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_NAME
from homeassistant.core import callback
from homeassistant.helpers import config_validation as cv, entityfilter
from . import flash_briefings, intent, smart_home_http
from .const import (
CONF_AUDIO,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
CONF_DESCRIPTION,
CONF_DISPLAY_CATEGORIES,
CONF_DISPLAY_URL,

View File

@ -7,7 +7,7 @@ import logging
import aiohttp
import async_timeout
from homeassistant.const import HTTP_OK
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, HTTP_OK
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client
from homeassistant.util import dt
@ -48,8 +48,8 @@ class Auth:
lwa_params = {
"grant_type": "authorization_code",
"code": accept_grant_code,
"client_id": self.client_id,
"client_secret": self.client_secret,
CONF_CLIENT_ID: self.client_id,
CONF_CLIENT_SECRET: self.client_secret,
}
_LOGGER.debug(
"Calling LWA to get the access token (first time), with: %s",
@ -80,8 +80,8 @@ class Auth:
lwa_params = {
"grant_type": "refresh_token",
"refresh_token": self._prefs[STORAGE_REFRESH_TOKEN],
"client_id": self.client_id,
"client_secret": self.client_secret,
CONF_CLIENT_ID: self.client_id,
CONF_CLIENT_SECRET: self.client_secret,
}
_LOGGER.debug("Calling LWA to refresh the access token.")

View File

@ -1661,7 +1661,21 @@ class AlexaDoorbellEventSource(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-doorbelleventsource.html
"""
supported_locales = {"en-US"}
supported_locales = {
"en-US",
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"es-MX",
"fr-CA",
"fr-FR",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
@ -1789,6 +1803,13 @@ class AlexaEqualizerController(AlexaCapability):
"""
supported_locales = {"en-US"}
VALID_SOUND_MODES = {
"MOVIE",
"MUSIC",
"NIGHT",
"SPORT",
"TV",
}
def name(self):
"""Return the Alexa API name of this interface."""
@ -1807,35 +1828,34 @@ class AlexaEqualizerController(AlexaCapability):
raise UnsupportedProperty(name)
sound_mode = self.entity.attributes.get(media_player.ATTR_SOUND_MODE)
if sound_mode and sound_mode.upper() in (
"MOVIE",
"MUSIC",
"NIGHT",
"SPORT",
"TV",
):
if sound_mode and sound_mode.upper() in self.VALID_SOUND_MODES:
return sound_mode.upper()
return None
def configurations(self):
"""Return the sound modes supported in the configurations object.
Valid Values for modes are: MOVIE, MUSIC, NIGHT, SPORT, TV.
"""
"""Return the sound modes supported in the configurations object."""
configurations = None
sound_mode_list = self.entity.attributes.get(media_player.ATTR_SOUND_MODE_LIST)
if sound_mode_list:
supported_sound_modes = [
{"name": sound_mode.upper()}
for sound_mode in sound_mode_list
if sound_mode.upper() in ("MOVIE", "MUSIC", "NIGHT", "SPORT", "TV")
]
supported_sound_modes = self.get_valid_inputs(
self.entity.attributes.get(media_player.ATTR_SOUND_MODE_LIST, [])
)
if supported_sound_modes:
configurations = {"modes": {"supported": supported_sound_modes}}
return configurations
@classmethod
def get_valid_inputs(cls, sound_mode_list):
"""Return list of supported inputs."""
input_list = []
for sound_mode in sound_mode_list:
sound_mode = sound_mode.upper()
if sound_mode in cls.VALID_SOUND_MODES:
input_list.append({"name": sound_mode})
return input_list
class AlexaTimeHoldController(AlexaCapability):
"""Implements Alexa.TimeHoldController.

View File

@ -18,8 +18,6 @@ CONF_DISPLAY_URL = "display_url"
CONF_FILTER = "filter"
CONF_ENTITY_CONFIG = "entity_config"
CONF_ENDPOINT = "endpoint"
CONF_CLIENT_ID = "client_id"
CONF_CLIENT_SECRET = "client_secret"
CONF_LOCALE = "locale"
ATTR_UID = "uid"
@ -126,6 +124,8 @@ class Inputs:
"""
VALID_SOURCE_NAME_MAP = {
"antenna": "TUNER",
"antennatv": "TUNER",
"aux": "AUX 1",
"aux1": "AUX 1",
"aux2": "AUX 2",
@ -135,6 +135,7 @@ class Inputs:
"aux6": "AUX 6",
"aux7": "AUX 7",
"bluray": "BLURAY",
"blurayplayer": "BLURAY",
"cable": "CABLE",
"cd": "CD",
"coax": "COAX 1",
@ -186,6 +187,7 @@ class Inputs:
"playstation": "PLAYSTATION",
"playstation3": "PLAYSTATION 3",
"playstation4": "PLAYSTATION 4",
"rokumediaplayer": "MEDIA PLAYER",
"satellite": "SATELLITE",
"satellitetv": "SATELLITE",
"smartcast": "SMARTCAST",

View File

@ -547,7 +547,11 @@ class MediaPlayerCapabilities(AlexaEntity):
yield AlexaChannelController(self.entity)
if supported & media_player.const.SUPPORT_SELECT_SOUND_MODE:
yield AlexaEqualizerController(self.entity)
inputs = AlexaInputController.get_valid_inputs(
self.entity.attributes.get(media_player.const.ATTR_SOUND_MODE_LIST, [])
)
if len(inputs) > 0:
yield AlexaEqualizerController(self.entity)
yield AlexaEndpointHealth(self.hass, self.entity)
yield Alexa(self.hass)

View File

@ -40,6 +40,16 @@ def async_setup(hass):
hass.http.register_view(AlexaIntentsView)
async def async_setup_intents(hass):
"""
Do intents setup.
Right now this module does not expose any, but the intent component breaks
without it.
"""
pass # pylint: disable=unnecessary-pass
class UnknownRequest(HomeAssistantError):
"""When an unknown Alexa request is passed in."""

View File

@ -3,17 +3,11 @@ import logging
from homeassistant import core
from homeassistant.components.http.view import HomeAssistantView
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
from .auth import Auth
from .config import AbstractConfig
from .const import (
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
CONF_ENDPOINT,
CONF_ENTITY_CONFIG,
CONF_FILTER,
CONF_LOCALE,
)
from .const import CONF_ENDPOINT, CONF_ENTITY_CONFIG, CONF_FILTER, CONF_LOCALE
from .smart_home import async_handle_message
from .state_report import async_enable_proactive_mode

View File

@ -13,7 +13,13 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.auth.const import GROUP_ID_ADMIN
from homeassistant.components import conversation
from homeassistant.const import CONF_HOST, CONF_TYPE, EVENT_HOMEASSISTANT_START
from homeassistant.const import (
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
CONF_HOST,
CONF_TYPE,
EVENT_HOMEASSISTANT_START,
)
from homeassistant.core import Context, CoreState, HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import (
@ -29,9 +35,6 @@ from homeassistant.helpers import (
from . import config_flow
from .const import DOMAIN, TYPE_LOCAL, TYPE_OAUTH2
CONF_CLIENT_ID = "client_id"
CONF_CLIENT_SECRET = "client_secret"
STORAGE_VERSION = 1
STORAGE_KEY = DOMAIN

View File

@ -7,11 +7,11 @@
},
"step": {
"hassio_confirm": {
"description": "Czy chcesz skonfigurowa\u0107 Home Assistant'a, aby \u0142\u0105czy\u0142 si\u0119 z Almond dostarczonym przez dodatek Hass.io: {addon}?",
"description": "Czy chcesz skonfigurowa\u0107 Home Assistanta, aby \u0142\u0105czy\u0142 si\u0119 z Almond dostarczonym przez dodatek Hass.io: {addon}?",
"title": "Almond poprzez dodatek Hass.io"
},
"pick_implementation": {
"title": "[%key_id:common::config_flow::title::oauth2_pick_implementation%]"
"title": "Wybierz metod\u0119 uwierzytelniania"
}
}
}

View File

@ -3,10 +3,11 @@ import logging
import voluptuous as vol
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
from homeassistant.helpers import config_validation as cv
from . import config_flow
from .const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, DOMAIN
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)

View File

@ -11,14 +11,18 @@ from homeassistant.components.climate.const import (
HVAC_MODE_OFF,
SUPPORT_TARGET_TEMPERATURE,
)
from homeassistant.const import ATTR_NAME, ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.const import (
ATTR_NAME,
ATTR_TEMPERATURE,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
TEMP_CELSIUS,
)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import (
ATTR_VALUE,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
DOMAIN,
SERVICE_COMFORT_FEEDBACK,
SERVICE_COMFORT_MODE,

View File

@ -5,6 +5,7 @@ import ambiclimate
from homeassistant import config_entries
from homeassistant.components.http import HomeAssistantView
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.network import get_url
@ -12,8 +13,6 @@ from homeassistant.helpers.network import get_url
from .const import (
AUTH_CALLBACK_NAME,
AUTH_CALLBACK_PATH,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
DOMAIN,
STORAGE_KEY,
STORAGE_VERSION,

View File

@ -1,12 +1,13 @@
"""Constants used by the Ambiclimate component."""
ATTR_VALUE = "value"
CONF_CLIENT_ID = "client_id"
CONF_CLIENT_SECRET = "client_secret"
DOMAIN = "ambiclimate"
ATTR_VALUE = "value"
SERVICE_COMFORT_FEEDBACK = "send_comfort_feedback"
SERVICE_COMFORT_MODE = "set_comfort_mode"
SERVICE_TEMPERATURE_MODE = "set_temperature_mode"
STORAGE_KEY = "ambiclimate_auth"
STORAGE_VERSION = 1

View File

@ -14,7 +14,7 @@
},
"step": {
"auth": {
"description": "\u041c\u043e\u043b\u044f, \u043f\u043e\u0441\u043b\u0435\u0434\u0432\u0430\u0439\u0442\u0435 \u0442\u043e\u0437\u0438 [link]({authorization_url}) \u0438 <b>\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u0442\u0435</b> \u0434\u043e\u0441\u0442\u044a\u043f\u0430 \u0434\u043e \u043f\u0440\u043e\u0444\u0438\u043b\u0430 \u0441\u0438 \u0432 Ambiclimate, \u0441\u043b\u0435\u0434 \u0442\u043e\u0432\u0430 \u0441\u0435 \u0432\u044a\u0440\u043d\u0435\u0442\u0435 \u0438 \u043d\u0430\u0442\u0438\u0441\u043d\u0435\u0442\u0435 <b>\u0418\u0437\u043f\u0440\u0430\u0449\u0430\u043d\u0435</b> \u043f\u043e-\u0434\u043e\u043b\u0443. \n (\u0423\u0432\u0435\u0440\u0435\u0442\u0435 \u0441\u0435, \u0447\u0435 \u043f\u043e\u0441\u043e\u0447\u0435\u043d\u0438\u044f\u0442 url \u0437\u0430 \u043e\u0431\u0440\u0430\u0442\u043d\u0430 \u043f\u043e\u0432\u0438\u043a\u0432\u0430\u043d\u0435 \u0435 {cb_url})",
"description": "\u041c\u043e\u043b\u044f, \u043f\u043e\u0441\u043b\u0435\u0434\u0432\u0430\u0439\u0442\u0435 \u0442\u043e\u0437\u0438 [link]({authorization_url}) \u0438 **\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u0442\u0435** \u0434\u043e\u0441\u0442\u044a\u043f\u0430 \u0434\u043e \u043f\u0440\u043e\u0444\u0438\u043b\u0430 \u0441\u0438 \u0432 Ambiclimate, \u0441\u043b\u0435\u0434 \u0442\u043e\u0432\u0430 \u0441\u0435 \u0432\u044a\u0440\u043d\u0435\u0442\u0435 \u0438 \u043d\u0430\u0442\u0438\u0441\u043d\u0435\u0442\u0435 **\u0418\u0437\u043f\u0440\u0430\u0449\u0430\u043d\u0435** \u043f\u043e-\u0434\u043e\u043b\u0443. \n (\u0423\u0432\u0435\u0440\u0435\u0442\u0435 \u0441\u0435, \u0447\u0435 \u043f\u043e\u0441\u043e\u0447\u0435\u043d\u0438\u044f\u0442 url \u0437\u0430 \u043e\u0431\u0440\u0430\u0442\u043d\u0430 \u043f\u043e\u0432\u0438\u043a\u0432\u0430\u043d\u0435 \u0435 {cb_url})",
"title": "\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u043a\u0438\u0440\u0430\u043d\u0435 \u0441 Ambiclimate"
}
}

View File

@ -14,7 +14,7 @@
},
"step": {
"auth": {
"description": "V\u00e9s a l'[enlla\u00e7]({authorization_url}) i <b>Permet</b> l'acc\u00e9s al teu compte de Ambiclimate, despr\u00e9s torna i prem <b>Envia</b> (a sota).\n(Assegura't que l'enlla\u00e7 de retorn \u00e9s el seg\u00fcent {cb_url})",
"description": "V\u00e9s a l'[enlla\u00e7]({authorization_url}) i **Permet** l'acc\u00e9s al teu compte de Ambiclimate, despr\u00e9s torna i prem **Envia** (a sota).\n(Assegura't que l'enlla\u00e7 de retorn \u00e9s el seg\u00fcent {cb_url})",
"title": "Autenticaci\u00f3 amb Ambi Climate"
}
}

View File

@ -6,7 +6,7 @@
},
"step": {
"auth": {
"description": "N\u00e1sledujte tento [odkaz]({authorization_url}) a <b> Povolit </b> p\u0159\u00edstup k va\u0161emu \u00fa\u010dtu Ambiclimate, pot\u00e9 se vra\u0165te a stiskn\u011bte <b> Odeslat </b> n\u00ed\u017ee. \n (Ujist\u011bte se, \u017ee zadan\u00e1 adresa URL zp\u011btn\u00e9ho vol\u00e1n\u00ed je {cb_url} )",
"description": "N\u00e1sledujte tento [odkaz]({authorization_url}) a **Povolit** p\u0159\u00edstup k va\u0161emu \u00fa\u010dtu Ambiclimate, pot\u00e9 se vra\u0165te a stiskn\u011bte **Odeslat** n\u00ed\u017ee. \n (Ujist\u011bte se, \u017ee zadan\u00e1 adresa URL zp\u011btn\u00e9ho vol\u00e1n\u00ed je {cb_url} )",
"title": "Ov\u011b\u0159it Ambiclimate"
}
}

Some files were not shown because too many files have changed in this diff Show More