mirror of
https://github.com/home-assistant/core.git
synced 2025-07-31 09:17:10 +00:00
2022.12.0 (#83482)
This commit is contained in:
commit
7b462e1b8e
@ -38,6 +38,7 @@ base_platforms: &base_platforms
|
||||
- homeassistant/components/siren/**
|
||||
- homeassistant/components/stt/**
|
||||
- homeassistant/components/switch/**
|
||||
- homeassistant/components/text/**
|
||||
- homeassistant/components/tts/**
|
||||
- homeassistant/components/update/**
|
||||
- homeassistant/components/vacuum/**
|
||||
|
29
.coveragerc
29
.coveragerc
@ -35,6 +35,8 @@ omit =
|
||||
homeassistant/components/agent_dvr/helpers.py
|
||||
homeassistant/components/airnow/__init__.py
|
||||
homeassistant/components/airnow/sensor.py
|
||||
homeassistant/components/airq/__init__.py
|
||||
homeassistant/components/airq/sensor.py
|
||||
homeassistant/components/airthings/__init__.py
|
||||
homeassistant/components/airthings/sensor.py
|
||||
homeassistant/components/airthings_ble/__init__.py
|
||||
@ -232,8 +234,6 @@ omit =
|
||||
homeassistant/components/dlib_face_detect/image_processing.py
|
||||
homeassistant/components/dlib_face_identify/image_processing.py
|
||||
homeassistant/components/dlink/switch.py
|
||||
homeassistant/components/dnsip/__init__.py
|
||||
homeassistant/components/dnsip/sensor.py
|
||||
homeassistant/components/dominos/*
|
||||
homeassistant/components/doods/*
|
||||
homeassistant/components/doorbird/__init__.py
|
||||
@ -455,7 +455,7 @@ omit =
|
||||
homeassistant/components/github/sensor.py
|
||||
homeassistant/components/gitlab_ci/sensor.py
|
||||
homeassistant/components/gitter/sensor.py
|
||||
homeassistant/components/glances/__init__.py
|
||||
homeassistant/components/glances/const.py
|
||||
homeassistant/components/glances/sensor.py
|
||||
homeassistant/components/goalfeed/*
|
||||
homeassistant/components/goodwe/__init__.py
|
||||
@ -483,11 +483,6 @@ omit =
|
||||
homeassistant/components/habitica/__init__.py
|
||||
homeassistant/components/habitica/const.py
|
||||
homeassistant/components/habitica/sensor.py
|
||||
homeassistant/components/hangouts/__init__.py
|
||||
homeassistant/components/hangouts/hangouts_bot.py
|
||||
homeassistant/components/hangouts/hangups_utils.py
|
||||
homeassistant/components/hangouts/intents.py
|
||||
homeassistant/components/hangouts/notify.py
|
||||
homeassistant/components/harman_kardon_avr/media_player.py
|
||||
homeassistant/components/harmony/const.py
|
||||
homeassistant/components/harmony/data.py
|
||||
@ -676,8 +671,8 @@ omit =
|
||||
homeassistant/components/lcn/services.py
|
||||
homeassistant/components/led_ble/__init__.py
|
||||
homeassistant/components/led_ble/light.py
|
||||
homeassistant/components/led_ble/util.py
|
||||
homeassistant/components/lg_netcast/media_player.py
|
||||
homeassistant/components/lg_soundbar/__init__.py
|
||||
homeassistant/components/lg_soundbar/media_player.py
|
||||
homeassistant/components/lidarr/__init__.py
|
||||
homeassistant/components/lidarr/coordinator.py
|
||||
@ -729,6 +724,9 @@ omit =
|
||||
homeassistant/components/map/*
|
||||
homeassistant/components/mastodon/notify.py
|
||||
homeassistant/components/matrix/*
|
||||
homeassistant/components/matter/__init__.py
|
||||
homeassistant/components/matter/adapter.py
|
||||
homeassistant/components/matter/entity.py
|
||||
homeassistant/components/meater/__init__.py
|
||||
homeassistant/components/meater/const.py
|
||||
homeassistant/components/meater/sensor.py
|
||||
@ -951,6 +949,8 @@ omit =
|
||||
homeassistant/components/overkiz/sensor.py
|
||||
homeassistant/components/overkiz/siren.py
|
||||
homeassistant/components/overkiz/switch.py
|
||||
homeassistant/components/overkiz/water_heater.py
|
||||
homeassistant/components/overkiz/water_heater_entities/*
|
||||
homeassistant/components/ovo_energy/__init__.py
|
||||
homeassistant/components/ovo_energy/const.py
|
||||
homeassistant/components/ovo_energy/sensor.py
|
||||
@ -960,6 +960,7 @@ omit =
|
||||
homeassistant/components/pencom/switch.py
|
||||
homeassistant/components/philips_js/__init__.py
|
||||
homeassistant/components/philips_js/diagnostics.py
|
||||
homeassistant/components/philips_js/helpers.py
|
||||
homeassistant/components/philips_js/light.py
|
||||
homeassistant/components/philips_js/media_player.py
|
||||
homeassistant/components/philips_js/remote.py
|
||||
@ -999,6 +1000,7 @@ omit =
|
||||
homeassistant/components/proxmoxve/*
|
||||
homeassistant/components/proxy/camera.py
|
||||
homeassistant/components/pulseaudio_loopback/switch.py
|
||||
homeassistant/components/pushbullet/api.py
|
||||
homeassistant/components/pushbullet/notify.py
|
||||
homeassistant/components/pushbullet/sensor.py
|
||||
homeassistant/components/pushover/notify.py
|
||||
@ -1107,13 +1109,6 @@ omit =
|
||||
homeassistant/components/sesame/lock.py
|
||||
homeassistant/components/seven_segments/image_processing.py
|
||||
homeassistant/components/seventeentrack/sensor.py
|
||||
homeassistant/components/shelly/binary_sensor.py
|
||||
homeassistant/components/shelly/climate.py
|
||||
homeassistant/components/shelly/coordinator.py
|
||||
homeassistant/components/shelly/entity.py
|
||||
homeassistant/components/shelly/number.py
|
||||
homeassistant/components/shelly/sensor.py
|
||||
homeassistant/components/shelly/utils.py
|
||||
homeassistant/components/shiftr/*
|
||||
homeassistant/components/shodan/sensor.py
|
||||
homeassistant/components/sia/__init__.py
|
||||
@ -1147,6 +1142,7 @@ omit =
|
||||
homeassistant/components/skybell/switch.py
|
||||
homeassistant/components/slack/__init__.py
|
||||
homeassistant/components/slack/notify.py
|
||||
homeassistant/components/slack/sensor.py
|
||||
homeassistant/components/slide/*
|
||||
homeassistant/components/slimproto/__init__.py
|
||||
homeassistant/components/slimproto/media_player.py
|
||||
@ -1574,6 +1570,7 @@ omit =
|
||||
homeassistant/components/yolink/coordinator.py
|
||||
homeassistant/components/yolink/cover.py
|
||||
homeassistant/components/yolink/entity.py
|
||||
homeassistant/components/yolink/light.py
|
||||
homeassistant/components/yolink/lock.py
|
||||
homeassistant/components/yolink/sensor.py
|
||||
homeassistant/components/yolink/siren.py
|
||||
|
@ -9,7 +9,6 @@ docs
|
||||
.vscode
|
||||
|
||||
# Test related files
|
||||
.tox
|
||||
tests
|
||||
|
||||
# Other virtualization methods
|
||||
|
13
.github/move.yml
vendored
13
.github/move.yml
vendored
@ -1,13 +0,0 @@
|
||||
# Configuration for move-issues - https://github.com/dessant/move-issues
|
||||
|
||||
# Delete the command comment. Ignored when the comment also contains other content
|
||||
deleteCommand: true
|
||||
# Close the source issue after moving
|
||||
closeSourceIssue: true
|
||||
# Lock the source issue after moving
|
||||
lockSourceIssue: false
|
||||
# Set custom aliases for targets
|
||||
# aliases:
|
||||
# r: repo
|
||||
# or: owner/repo
|
||||
|
4
.github/workflows/builder.yml
vendored
4
.github/workflows/builder.yml
vendored
@ -159,7 +159,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build base image
|
||||
uses: home-assistant/builder@2022.09.0
|
||||
uses: home-assistant/builder@2022.11.0
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
@ -225,7 +225,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build base image
|
||||
uses: home-assistant/builder@2022.09.0
|
||||
uses: home-assistant/builder@2022.11.0
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
|
10
.github/workflows/ci.yaml
vendored
10
.github/workflows/ci.yaml
vendored
@ -22,7 +22,7 @@ on:
|
||||
env:
|
||||
CACHE_VERSION: 3
|
||||
PIP_CACHE_VERSION: 3
|
||||
HA_SHORT_VERSION: 2022.11
|
||||
HA_SHORT_VERSION: 2022.12
|
||||
DEFAULT_PYTHON: 3.9
|
||||
ALL_PYTHON_VERSIONS: "['3.9', '3.10']"
|
||||
PRE_COMMIT_CACHE: ~/.cache/pre-commit
|
||||
@ -842,7 +842,6 @@ jobs:
|
||||
python3 -X dev -m pytest \
|
||||
-qq \
|
||||
--timeout=9 \
|
||||
--durations=10 \
|
||||
-n auto \
|
||||
--cov="homeassistant.components.${{ matrix.group }}" \
|
||||
--cov-report=xml \
|
||||
@ -936,7 +935,7 @@ jobs:
|
||||
. venv/bin/activate
|
||||
pip install mysqlclient sqlalchemy_utils
|
||||
- name: Run pytest (partially)
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 15
|
||||
shell: bash
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
@ -944,14 +943,13 @@ jobs:
|
||||
|
||||
python3 -X dev -m pytest \
|
||||
-qq \
|
||||
--timeout=9 \
|
||||
--timeout=20 \
|
||||
-n 1 \
|
||||
--cov="homeassistant.components.recorder" \
|
||||
--cov-report=xml \
|
||||
--cov-report=term-missing \
|
||||
-o console_output_style=count \
|
||||
--durations=0 \
|
||||
--durations-min=10 \
|
||||
--durations=10 \
|
||||
-p no:sugar \
|
||||
--dburl=mysql://root:password@127.0.0.1/homeassistant-test \
|
||||
tests/components/recorder
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -58,7 +58,6 @@ pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
coverage.xml
|
||||
nosetests.xml
|
||||
htmlcov/
|
||||
|
@ -1,9 +1,16 @@
|
||||
repos:
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.1.0
|
||||
rev: v3.2.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py39-plus]
|
||||
- repo: https://github.com/PyCQA/autoflake
|
||||
rev: v2.0.0
|
||||
hooks:
|
||||
- id: autoflake
|
||||
args:
|
||||
- --in-place
|
||||
- --remove-all-unused-imports
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.10.0
|
||||
hooks:
|
||||
@ -13,27 +20,27 @@ repos:
|
||||
- --quiet
|
||||
files: ^((homeassistant|pylint|script|tests)/.+)?[^/]+\.py$
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.1.0
|
||||
rev: v2.2.2
|
||||
hooks:
|
||||
- id: codespell
|
||||
args:
|
||||
- --ignore-words-list=hass,alot,datas,dof,dur,ether,farenheit,hist,iff,iif,ines,ist,lightsensor,mut,nd,pres,referer,rime,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing,iam,incomfort,ba,haa,pullrequests
|
||||
- --ignore-words-list=additionals,alot,ba,bre,bund,datas,dof,dur,ether,farenheit,falsy,fo,haa,hass,hist,iam,iff,iif,incomfort,ines,ist,lightsensor,mut,nam,nd,pres,pullrequests,referer,resset,rime,ser,serie,sur,te,technik,ue,uint,unsecure,visability,wan,wanna,withing,zar
|
||||
- --skip="./.*,*.csv,*.json"
|
||||
- --quiet-level=2
|
||||
exclude_types: [csv, json]
|
||||
exclude: ^tests/fixtures/|homeassistant/generated/
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 4.0.1
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
- pycodestyle==2.8.0
|
||||
- pyflakes==2.4.0
|
||||
- pycodestyle==2.10.0
|
||||
- pyflakes==3.0.1
|
||||
- flake8-docstrings==1.6.0
|
||||
- pydocstyle==6.1.1
|
||||
- flake8-comprehensions==3.10.0
|
||||
- flake8-noqa==1.2.8
|
||||
- mccabe==0.6.1
|
||||
- flake8-comprehensions==3.10.1
|
||||
- flake8-noqa==1.3.0
|
||||
- mccabe==0.7.0
|
||||
files: ^(homeassistant|script|tests)/.+\.py$
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: 1.7.4
|
||||
@ -65,7 +72,7 @@ repos:
|
||||
hooks:
|
||||
- id: yamllint
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v2.6.1
|
||||
rev: v2.7.1
|
||||
hooks:
|
||||
- id: prettier
|
||||
- repo: https://github.com/cdce8p/python-typing-update
|
||||
|
@ -5,14 +5,10 @@
|
||||
# Strict typing is enabled by default for core files.
|
||||
# Add it here to add 'disallow_any_generics'.
|
||||
# --- Only for core file! ---
|
||||
homeassistant.exceptions
|
||||
homeassistant.core
|
||||
homeassistant.loader
|
||||
homeassistant.requirements
|
||||
homeassistant.runner
|
||||
homeassistant.setup
|
||||
homeassistant.auth.auth_store
|
||||
homeassistant.auth.providers.*
|
||||
homeassistant.core
|
||||
homeassistant.exceptions
|
||||
homeassistant.helpers.area_registry
|
||||
homeassistant.helpers.condition
|
||||
homeassistant.helpers.debounce
|
||||
@ -29,6 +25,10 @@ homeassistant.helpers.script_variables
|
||||
homeassistant.helpers.singleton
|
||||
homeassistant.helpers.sun
|
||||
homeassistant.helpers.translation
|
||||
homeassistant.loader
|
||||
homeassistant.requirements
|
||||
homeassistant.runner
|
||||
homeassistant.setup
|
||||
homeassistant.util.async_
|
||||
homeassistant.util.color
|
||||
homeassistant.util.decorator
|
||||
@ -79,13 +79,14 @@ homeassistant.components.button.*
|
||||
homeassistant.components.calendar.*
|
||||
homeassistant.components.camera.*
|
||||
homeassistant.components.canary.*
|
||||
homeassistant.components.cover.*
|
||||
homeassistant.components.clickatell.*
|
||||
homeassistant.components.clicksend.*
|
||||
homeassistant.components.cover.*
|
||||
homeassistant.components.cpuspeed.*
|
||||
homeassistant.components.crownstone.*
|
||||
homeassistant.components.deconz.*
|
||||
homeassistant.components.demo.*
|
||||
homeassistant.components.derivative.*
|
||||
homeassistant.components.device_automation.*
|
||||
homeassistant.components.device_tracker.*
|
||||
homeassistant.components.devolo_home_control.*
|
||||
@ -151,6 +152,7 @@ homeassistant.components.http.*
|
||||
homeassistant.components.huawei_lte.*
|
||||
homeassistant.components.hyperion.*
|
||||
homeassistant.components.ibeacon.*
|
||||
homeassistant.components.image.*
|
||||
homeassistant.components.image_processing.*
|
||||
homeassistant.components.input_button.*
|
||||
homeassistant.components.input_select.*
|
||||
@ -173,17 +175,21 @@ homeassistant.components.litterrobot.*
|
||||
homeassistant.components.local_ip.*
|
||||
homeassistant.components.lock.*
|
||||
homeassistant.components.logbook.*
|
||||
homeassistant.components.logger.*
|
||||
homeassistant.components.lookin.*
|
||||
homeassistant.components.luftdaten.*
|
||||
homeassistant.components.mailbox.*
|
||||
homeassistant.components.matter.*
|
||||
homeassistant.components.media_player.*
|
||||
homeassistant.components.media_source.*
|
||||
homeassistant.components.metoffice.*
|
||||
homeassistant.components.mikrotik.*
|
||||
homeassistant.components.min_max.*
|
||||
homeassistant.components.mjpeg.*
|
||||
homeassistant.components.modbus.*
|
||||
homeassistant.components.modem_callerid.*
|
||||
homeassistant.components.moon.*
|
||||
homeassistant.components.mqtt.*
|
||||
homeassistant.components.mysensors.*
|
||||
homeassistant.components.nam.*
|
||||
homeassistant.components.nanoleaf.*
|
||||
@ -191,6 +197,7 @@ homeassistant.components.neato.*
|
||||
homeassistant.components.nest.*
|
||||
homeassistant.components.netatmo.*
|
||||
homeassistant.components.network.*
|
||||
homeassistant.components.nextdns.*
|
||||
homeassistant.components.nfandroidtv.*
|
||||
homeassistant.components.nissan_leaf.*
|
||||
homeassistant.components.no_ip.*
|
||||
@ -213,9 +220,9 @@ homeassistant.components.prusalink.*
|
||||
homeassistant.components.pure_energie.*
|
||||
homeassistant.components.pvoutput.*
|
||||
homeassistant.components.qnap_qsw.*
|
||||
homeassistant.components.radarr.*
|
||||
homeassistant.components.rainmachine.*
|
||||
homeassistant.components.rdw.*
|
||||
homeassistant.components.radarr.*
|
||||
homeassistant.components.recollect_waste.*
|
||||
homeassistant.components.recorder.*
|
||||
homeassistant.components.remote.*
|
||||
@ -228,12 +235,14 @@ homeassistant.components.rituals_perfume_genie.*
|
||||
homeassistant.components.roku.*
|
||||
homeassistant.components.rpi_power.*
|
||||
homeassistant.components.rtsp_to_webrtc.*
|
||||
homeassistant.components.ruuvitag_ble.*
|
||||
homeassistant.components.samsungtv.*
|
||||
homeassistant.components.scene.*
|
||||
homeassistant.components.schedule.*
|
||||
homeassistant.components.select.*
|
||||
homeassistant.components.senseme.*
|
||||
homeassistant.components.sensibo.*
|
||||
homeassistant.components.sensirion_ble.*
|
||||
homeassistant.components.sensor.*
|
||||
homeassistant.components.senz.*
|
||||
homeassistant.components.shelly.*
|
||||
@ -283,6 +292,7 @@ homeassistant.components.vacuum.*
|
||||
homeassistant.components.vallox.*
|
||||
homeassistant.components.velbus.*
|
||||
homeassistant.components.vlc_telnet.*
|
||||
homeassistant.components.wake_on_lan.*
|
||||
homeassistant.components.wallbox.*
|
||||
homeassistant.components.water_heater.*
|
||||
homeassistant.components.watttime.*
|
||||
|
44
CODEOWNERS
44
CODEOWNERS
@ -45,6 +45,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/airly/ @bieniu
|
||||
/homeassistant/components/airnow/ @asymworks
|
||||
/tests/components/airnow/ @asymworks
|
||||
/homeassistant/components/airq/ @Sibgatulin @dl2080
|
||||
/tests/components/airq/ @Sibgatulin @dl2080
|
||||
/homeassistant/components/airthings/ @danielhiversen
|
||||
/tests/components/airthings/ @danielhiversen
|
||||
/homeassistant/components/airthings_ble/ @vincegio
|
||||
@ -61,8 +63,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/alarm_control_panel/ @home-assistant/core
|
||||
/homeassistant/components/alert/ @home-assistant/core @frenck
|
||||
/tests/components/alert/ @home-assistant/core @frenck
|
||||
/homeassistant/components/alexa/ @home-assistant/cloud @ochlocracy
|
||||
/tests/components/alexa/ @home-assistant/cloud @ochlocracy
|
||||
/homeassistant/components/alexa/ @home-assistant/cloud @ochlocracy @jbouwh
|
||||
/tests/components/alexa/ @home-assistant/cloud @ochlocracy @jbouwh
|
||||
/homeassistant/components/almond/ @gcampax @balloob
|
||||
/tests/components/almond/ @gcampax @balloob
|
||||
/homeassistant/components/amberelectric/ @madpilot
|
||||
@ -94,6 +96,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/apprise/ @caronc
|
||||
/homeassistant/components/aprs/ @PhilRW
|
||||
/tests/components/aprs/ @PhilRW
|
||||
/homeassistant/components/aranet/ @aschmitz
|
||||
/tests/components/aranet/ @aschmitz
|
||||
/homeassistant/components/arcam_fmj/ @elupus
|
||||
/tests/components/arcam_fmj/ @elupus
|
||||
/homeassistant/components/arris_tg2492lg/ @vanbalken
|
||||
@ -477,6 +481,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/homeassistant/ @home-assistant/core
|
||||
/homeassistant/components/homeassistant_alerts/ @home-assistant/core
|
||||
/tests/components/homeassistant_alerts/ @home-assistant/core
|
||||
/homeassistant/components/homeassistant_hardware/ @home-assistant/core
|
||||
/tests/components/homeassistant_hardware/ @home-assistant/core
|
||||
/homeassistant/components/homeassistant_sky_connect/ @home-assistant/core
|
||||
/tests/components/homeassistant_sky_connect/ @home-assistant/core
|
||||
/homeassistant/components/homeassistant_yellow/ @home-assistant/core
|
||||
@ -631,6 +637,10 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/litejet/ @joncar
|
||||
/homeassistant/components/litterrobot/ @natekspencer @tkdrob
|
||||
/tests/components/litterrobot/ @natekspencer @tkdrob
|
||||
/homeassistant/components/livisi/ @StefanIacobLivisi
|
||||
/tests/components/livisi/ @StefanIacobLivisi
|
||||
/homeassistant/components/local_calendar/ @allenporter
|
||||
/tests/components/local_calendar/ @allenporter
|
||||
/homeassistant/components/local_ip/ @issacg
|
||||
/tests/components/local_ip/ @issacg
|
||||
/homeassistant/components/lock/ @home-assistant/core
|
||||
@ -649,13 +659,15 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/luftdaten/ @fabaff @frenck
|
||||
/tests/components/luftdaten/ @fabaff @frenck
|
||||
/homeassistant/components/lupusec/ @majuss
|
||||
/homeassistant/components/lutron/ @JonGilmore
|
||||
/homeassistant/components/lutron/ @cdheiser
|
||||
/homeassistant/components/lutron_caseta/ @swails @bdraco @danaues
|
||||
/tests/components/lutron_caseta/ @swails @bdraco @danaues
|
||||
/homeassistant/components/lyric/ @timmo001
|
||||
/tests/components/lyric/ @timmo001
|
||||
/homeassistant/components/mastodon/ @fabaff
|
||||
/homeassistant/components/matrix/ @tinloaf
|
||||
/homeassistant/components/matter/ @MartinHjelmare @marcelveldt
|
||||
/tests/components/matter/ @MartinHjelmare @marcelveldt
|
||||
/homeassistant/components/mazda/ @bdr99
|
||||
/tests/components/mazda/ @bdr99
|
||||
/homeassistant/components/meater/ @Sotolotl @emontnemery
|
||||
@ -687,8 +699,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/mikrotik/ @engrbm87
|
||||
/homeassistant/components/mill/ @danielhiversen
|
||||
/tests/components/mill/ @danielhiversen
|
||||
/homeassistant/components/min_max/ @fabaff
|
||||
/tests/components/min_max/ @fabaff
|
||||
/homeassistant/components/min_max/ @gjohansson-ST
|
||||
/tests/components/min_max/ @gjohansson-ST
|
||||
/homeassistant/components/minecraft_server/ @elmurato
|
||||
/tests/components/minecraft_server/ @elmurato
|
||||
/homeassistant/components/minio/ @tkislan
|
||||
@ -713,8 +725,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/motion_blinds/ @starkillerOG
|
||||
/homeassistant/components/motioneye/ @dermotduffy
|
||||
/tests/components/motioneye/ @dermotduffy
|
||||
/homeassistant/components/mqtt/ @emontnemery
|
||||
/tests/components/mqtt/ @emontnemery
|
||||
/homeassistant/components/mqtt/ @emontnemery @jbouwh
|
||||
/tests/components/mqtt/ @emontnemery @jbouwh
|
||||
/homeassistant/components/msteams/ @peroyvind
|
||||
/homeassistant/components/mullvad/ @meichthys
|
||||
/tests/components/mullvad/ @meichthys
|
||||
@ -776,6 +788,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/nsw_fuel_station/ @nickw444
|
||||
/homeassistant/components/nsw_rural_fire_service_feed/ @exxamalte
|
||||
/tests/components/nsw_rural_fire_service_feed/ @exxamalte
|
||||
/homeassistant/components/nuheat/ @tstabrawa
|
||||
/tests/components/nuheat/ @tstabrawa
|
||||
/homeassistant/components/nuki/ @pschmitt @pvizeli @pree
|
||||
/tests/components/nuki/ @pschmitt @pvizeli @pree
|
||||
/homeassistant/components/numato/ @clssn
|
||||
@ -878,6 +892,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/pure_energie/ @klaasnicolaas
|
||||
/homeassistant/components/push/ @dgomes
|
||||
/tests/components/push/ @dgomes
|
||||
/homeassistant/components/pushbullet/ @engrbm87
|
||||
/tests/components/pushbullet/ @engrbm87
|
||||
/homeassistant/components/pushover/ @engrbm87
|
||||
/tests/components/pushover/ @engrbm87
|
||||
/homeassistant/components/pvoutput/ @frenck
|
||||
@ -955,6 +971,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/rtsp_to_webrtc/ @allenporter
|
||||
/homeassistant/components/ruckus_unleashed/ @gabe565
|
||||
/tests/components/ruckus_unleashed/ @gabe565
|
||||
/homeassistant/components/ruuvitag_ble/ @akx
|
||||
/tests/components/ruuvitag_ble/ @akx
|
||||
/homeassistant/components/sabnzbd/ @shaiu
|
||||
/tests/components/sabnzbd/ @shaiu
|
||||
/homeassistant/components/safe_mode/ @home-assistant/core
|
||||
@ -985,6 +1003,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/senseme/ @mikelawrence @bdraco
|
||||
/homeassistant/components/sensibo/ @andrey-git @gjohansson-ST
|
||||
/tests/components/sensibo/ @andrey-git @gjohansson-ST
|
||||
/homeassistant/components/sensirion_ble/ @akx
|
||||
/tests/components/sensirion_ble/ @akx
|
||||
/homeassistant/components/sensor/ @home-assistant/core
|
||||
/tests/components/sensor/ @home-assistant/core
|
||||
/homeassistant/components/sensorpro/ @bdraco
|
||||
@ -1001,8 +1021,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/sharkiq/ @JeffResc @funkybunch @AritroSaha10
|
||||
/homeassistant/components/shell_command/ @home-assistant/core
|
||||
/tests/components/shell_command/ @home-assistant/core
|
||||
/homeassistant/components/shelly/ @balloob @bieniu @thecode @chemelli74
|
||||
/tests/components/shelly/ @balloob @bieniu @thecode @chemelli74
|
||||
/homeassistant/components/shelly/ @balloob @bieniu @thecode @chemelli74 @bdraco
|
||||
/tests/components/shelly/ @balloob @bieniu @thecode @chemelli74 @bdraco
|
||||
/homeassistant/components/shodan/ @fabaff
|
||||
/homeassistant/components/sia/ @eavanvalkenburg
|
||||
/tests/components/sia/ @eavanvalkenburg
|
||||
@ -1121,8 +1141,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/synology_srm/ @aerialls
|
||||
/homeassistant/components/system_bridge/ @timmo001
|
||||
/tests/components/system_bridge/ @timmo001
|
||||
/homeassistant/components/tado/ @michaelarnauts @north3221
|
||||
/tests/components/tado/ @michaelarnauts @north3221
|
||||
/homeassistant/components/tado/ @michaelarnauts
|
||||
/tests/components/tado/ @michaelarnauts
|
||||
/homeassistant/components/tag/ @balloob @dmulcahey
|
||||
/tests/components/tag/ @balloob @dmulcahey
|
||||
/homeassistant/components/tailscale/ @frenck
|
||||
@ -1140,6 +1160,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/template/ @PhracturedBlue @tetienne @home-assistant/core
|
||||
/homeassistant/components/tesla_wall_connector/ @einarhauks
|
||||
/tests/components/tesla_wall_connector/ @einarhauks
|
||||
/homeassistant/components/text/ @home-assistant/core
|
||||
/tests/components/text/ @home-assistant/core
|
||||
/homeassistant/components/tfiac/ @fredrike @mellado
|
||||
/homeassistant/components/thermobeacon/ @bdraco
|
||||
/tests/components/thermobeacon/ @bdraco
|
||||
|
10
build.yaml
10
build.yaml
@ -1,11 +1,11 @@
|
||||
image: homeassistant/{arch}-homeassistant
|
||||
shadow_repository: ghcr.io/home-assistant
|
||||
build_from:
|
||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2022.10.0
|
||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2022.10.0
|
||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2022.10.0
|
||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2022.10.0
|
||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2022.10.0
|
||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2022.11.0
|
||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2022.11.0
|
||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2022.11.0
|
||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2022.11.0
|
||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2022.11.0
|
||||
codenotary:
|
||||
signer: notary@home-assistant.io
|
||||
base_image: notary@home-assistant.io
|
||||
|
@ -89,11 +89,21 @@ def get_arguments() -> argparse.Namespace:
|
||||
parser.add_argument(
|
||||
"--open-ui", action="store_true", help="Open the webinterface in a browser"
|
||||
)
|
||||
parser.add_argument(
|
||||
|
||||
skip_pip_group = parser.add_mutually_exclusive_group()
|
||||
skip_pip_group.add_argument(
|
||||
"--skip-pip",
|
||||
action="store_true",
|
||||
help="Skips pip install of required packages on startup",
|
||||
)
|
||||
skip_pip_group.add_argument(
|
||||
"--skip-pip-packages",
|
||||
metavar="package_names",
|
||||
type=lambda arg: arg.split(","),
|
||||
default=[],
|
||||
help="Skip pip install of specific packages on startup",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", action="store_true", help="Enable verbose logging to file."
|
||||
)
|
||||
@ -180,6 +190,7 @@ def main() -> int:
|
||||
log_file=args.log_file,
|
||||
log_no_color=args.log_no_color,
|
||||
skip_pip=args.skip_pip,
|
||||
skip_pip_packages=args.skip_pip_packages,
|
||||
safe_mode=args.safe_mode,
|
||||
debug=args.debug,
|
||||
open_ui=args.open_ui,
|
||||
|
@ -356,8 +356,7 @@ class AuthManager:
|
||||
provider = self._async_get_auth_provider(credentials)
|
||||
|
||||
if provider is not None and hasattr(provider, "async_will_remove_credentials"):
|
||||
# https://github.com/python/mypy/issues/1424
|
||||
await provider.async_will_remove_credentials(credentials) # type: ignore[attr-defined]
|
||||
await provider.async_will_remove_credentials(credentials)
|
||||
|
||||
await self._store.async_remove_credentials(credentials)
|
||||
|
||||
|
@ -166,7 +166,6 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) -> types.Modul
|
||||
|
||||
processed = hass.data[DATA_REQS] = set()
|
||||
|
||||
# https://github.com/python/mypy/issues/1424
|
||||
await requirements.async_process_requirements(
|
||||
hass, module_path, module.REQUIREMENTS
|
||||
)
|
||||
|
@ -47,7 +47,7 @@ def _lookup_domain(
|
||||
perm_lookup: PermissionLookup, domains_dict: SubCategoryDict, entity_id: str
|
||||
) -> ValueType | None:
|
||||
"""Look up entity permissions by domain."""
|
||||
return domains_dict.get(entity_id.split(".", 1)[0])
|
||||
return domains_dict.get(entity_id.partition(".")[0])
|
||||
|
||||
|
||||
def _lookup_area(
|
||||
|
@ -250,9 +250,7 @@ class LoginFlow(data_entry_flow.FlowHandler):
|
||||
auth_module, "async_initialize_login_mfa_step"
|
||||
):
|
||||
try:
|
||||
await auth_module.async_initialize_login_mfa_step( # type: ignore[attr-defined]
|
||||
self.user.id
|
||||
)
|
||||
await auth_module.async_initialize_login_mfa_step(self.user.id)
|
||||
except HomeAssistantError:
|
||||
_LOGGER.exception("Error initializing MFA step")
|
||||
return self.async_abort(reason="unknown_error")
|
||||
|
@ -88,12 +88,12 @@ class CommandLineAuthProvider(AuthProvider):
|
||||
for _line in stdout.splitlines():
|
||||
try:
|
||||
line = _line.decode().lstrip()
|
||||
if line.startswith("#"):
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
except ValueError:
|
||||
# malformed line
|
||||
continue
|
||||
if line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, _, value = line.partition("=")
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
if key in self.ALLOWED_META_KEYS:
|
||||
|
@ -17,7 +17,7 @@ import voluptuous as vol
|
||||
import yarl
|
||||
|
||||
from . import config as conf_util, config_entries, core, loader
|
||||
from .components import http, persistent_notification
|
||||
from .components import http
|
||||
from .const import (
|
||||
REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
||||
REQUIRED_NEXT_PYTHON_VER,
|
||||
@ -53,6 +53,7 @@ ERROR_LOG_FILENAME = "home-assistant.log"
|
||||
|
||||
# hass.data key for logging information.
|
||||
DATA_LOGGING = "logging"
|
||||
DATA_REGISTRIES_LOADED = "bootstrap_registries_loaded"
|
||||
|
||||
LOG_SLOW_STARTUP_INTERVAL = 60
|
||||
SLOW_STARTUP_CHECK_INTERVAL = 1
|
||||
@ -117,7 +118,8 @@ async def async_setup_hass(
|
||||
)
|
||||
|
||||
hass.config.skip_pip = runtime_config.skip_pip
|
||||
if runtime_config.skip_pip:
|
||||
hass.config.skip_pip_packages = runtime_config.skip_pip_packages
|
||||
if runtime_config.skip_pip or runtime_config.skip_pip_packages:
|
||||
_LOGGER.warning(
|
||||
"Skipping pip installation of required modules. This may cause issues"
|
||||
)
|
||||
@ -175,6 +177,7 @@ async def async_setup_hass(
|
||||
if old_logging:
|
||||
hass.data[DATA_LOGGING] = old_logging
|
||||
hass.config.skip_pip = old_config.skip_pip
|
||||
hass.config.skip_pip_packages = old_config.skip_pip_packages
|
||||
hass.config.internal_url = old_config.internal_url
|
||||
hass.config.external_url = old_config.external_url
|
||||
hass.config.config_dir = old_config.config_dir
|
||||
@ -216,6 +219,32 @@ def open_hass_ui(hass: core.HomeAssistant) -> None:
|
||||
)
|
||||
|
||||
|
||||
async def load_registries(hass: core.HomeAssistant) -> None:
|
||||
"""Load the registries and cache the result of platform.uname().processor."""
|
||||
if DATA_REGISTRIES_LOADED in hass.data:
|
||||
return
|
||||
hass.data[DATA_REGISTRIES_LOADED] = None
|
||||
|
||||
def _cache_uname_processor() -> None:
|
||||
"""Cache the result of platform.uname().processor in the executor.
|
||||
|
||||
Multiple modules call this function at startup which
|
||||
executes a blocking subprocess call. This is a problem for the
|
||||
asyncio event loop. By primeing the cache of uname we can
|
||||
avoid the blocking call in the event loop.
|
||||
"""
|
||||
platform.uname().processor # pylint: disable=expression-not-assigned
|
||||
|
||||
# Load the registries and cache the result of platform.uname().processor
|
||||
await asyncio.gather(
|
||||
area_registry.async_load(hass),
|
||||
device_registry.async_load(hass),
|
||||
entity_registry.async_load(hass),
|
||||
issue_registry.async_load(hass),
|
||||
hass.async_add_executor_job(_cache_uname_processor),
|
||||
)
|
||||
|
||||
|
||||
async def async_from_config_dict(
|
||||
config: ConfigType, hass: core.HomeAssistant
|
||||
) -> core.HomeAssistant | None:
|
||||
@ -228,6 +257,7 @@ async def async_from_config_dict(
|
||||
|
||||
hass.config_entries = config_entries.ConfigEntries(hass, config)
|
||||
await hass.config_entries.async_initialize()
|
||||
await load_registries(hass)
|
||||
|
||||
# Set up core.
|
||||
_LOGGER.debug("Setting up %s", CORE_INTEGRATIONS)
|
||||
@ -268,16 +298,31 @@ async def async_from_config_dict(
|
||||
REQUIRED_NEXT_PYTHON_HA_RELEASE
|
||||
and sys.version_info[:3] < REQUIRED_NEXT_PYTHON_VER
|
||||
):
|
||||
msg = (
|
||||
"Support for the running Python version "
|
||||
f"{'.'.join(str(x) for x in sys.version_info[:3])} is deprecated and will "
|
||||
f"be removed in Home Assistant {REQUIRED_NEXT_PYTHON_HA_RELEASE}. "
|
||||
"Please upgrade Python to "
|
||||
f"{'.'.join(str(x) for x in REQUIRED_NEXT_PYTHON_VER[:2])}."
|
||||
current_python_version = ".".join(str(x) for x in sys.version_info[:3])
|
||||
required_python_version = ".".join(str(x) for x in REQUIRED_NEXT_PYTHON_VER[:2])
|
||||
_LOGGER.warning(
|
||||
(
|
||||
"Support for the running Python version %s is deprecated and "
|
||||
"will be removed in Home Assistant %s; "
|
||||
"Please upgrade Python to %s"
|
||||
),
|
||||
current_python_version,
|
||||
REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
||||
required_python_version,
|
||||
)
|
||||
_LOGGER.warning(msg)
|
||||
persistent_notification.async_create(
|
||||
hass, msg, "Python version", "python_version"
|
||||
issue_registry.async_create_issue(
|
||||
hass,
|
||||
core.DOMAIN,
|
||||
"python_version",
|
||||
is_fixable=False,
|
||||
severity=issue_registry.IssueSeverity.WARNING,
|
||||
breaks_in_ha_version=REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
||||
translation_key="python_version",
|
||||
translation_placeholders={
|
||||
"current_python_version": current_python_version,
|
||||
"required_python_version": required_python_version,
|
||||
"breaks_in_ha_version": REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
||||
},
|
||||
)
|
||||
|
||||
return hass
|
||||
@ -404,7 +449,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 if key != core.DOMAIN}
|
||||
domains = {key.partition(" ")[0] for key in config if key != core.DOMAIN}
|
||||
|
||||
# Add config entry domains
|
||||
if not hass.config.safe_mode:
|
||||
@ -515,25 +560,6 @@ async def _async_set_up_integrations(
|
||||
|
||||
_LOGGER.info("Domains to be set up: %s", domains_to_setup)
|
||||
|
||||
def _cache_uname_processor() -> None:
|
||||
"""Cache the result of platform.uname().processor in the executor.
|
||||
|
||||
Multiple modules call this function at startup which
|
||||
executes a blocking subprocess call. This is a problem for the
|
||||
asyncio event loop. By primeing the cache of uname we can
|
||||
avoid the blocking call in the event loop.
|
||||
"""
|
||||
platform.uname().processor # pylint: disable=expression-not-assigned
|
||||
|
||||
# Load the registries and cache the result of platform.uname().processor
|
||||
await asyncio.gather(
|
||||
area_registry.async_load(hass),
|
||||
device_registry.async_load(hass),
|
||||
entity_registry.async_load(hass),
|
||||
issue_registry.async_load(hass),
|
||||
hass.async_add_executor_job(_cache_uname_processor),
|
||||
)
|
||||
|
||||
# Initialize recorder
|
||||
if "recorder" in domains_to_setup:
|
||||
recorder.async_initialize_recorder(hass)
|
||||
|
@ -14,7 +14,6 @@
|
||||
"google",
|
||||
"nest",
|
||||
"cast",
|
||||
"hangouts",
|
||||
"dialogflow"
|
||||
]
|
||||
}
|
||||
|
5
homeassistant/brands/yamaha.json
Normal file
5
homeassistant/brands/yamaha.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"domain": "yamaha",
|
||||
"name": "Yamaha",
|
||||
"integrations": ["yamaha", "yamaha_musiccast"]
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
"""Support for Abode Security System binary sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import suppress
|
||||
from typing import cast
|
||||
|
||||
from abodepy.devices.binary_sensor import AbodeBinarySensor as ABBinarySensor
|
||||
@ -47,8 +50,10 @@ class AbodeBinarySensor(AbodeDevice, BinarySensorEntity):
|
||||
return cast(bool, self._device.is_on)
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
def device_class(self) -> BinarySensorDeviceClass | None:
|
||||
"""Return the class of the binary sensor."""
|
||||
if self._device.get_value("is_window") == "1":
|
||||
return BinarySensorDeviceClass.WINDOW
|
||||
return cast(str, self._device.generic_type)
|
||||
with suppress(ValueError):
|
||||
return BinarySensorDeviceClass(cast(str, self._device.generic_type))
|
||||
return None
|
||||
|
@ -116,8 +116,3 @@ class AbodeLight(AbodeDevice, LightEntity):
|
||||
if self._device.is_dimmable:
|
||||
return {ColorMode.BRIGHTNESS}
|
||||
return {ColorMode.ONOFF}
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
"""Flag supported features."""
|
||||
return 0
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"reauth_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0442\u043e \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044f\u0432\u0430\u043d\u0435 \u0431\u0435\u0448\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e",
|
||||
"reauth_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u0442\u0430 \u0430\u0432\u0442\u0435\u043d\u0442\u0438\u043a\u0430\u0446\u0438\u044f \u0431\u0435\u0448\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u0430",
|
||||
"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": {
|
||||
|
@ -1,21 +1,34 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"reauth_successful": "Op\u00e4tovn\u00e9 overenie bolo \u00faspe\u0161n\u00e9"
|
||||
"reauth_successful": "Op\u00e4tovn\u00e9 overenie bolo \u00faspe\u0161n\u00e9",
|
||||
"single_instance_allowed": "U\u017e je nakonfigurovan\u00fd. Mo\u017en\u00e1 len jedna konfigur\u00e1cia."
|
||||
},
|
||||
"error": {
|
||||
"invalid_auth": "Neplatn\u00e9 overenie"
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165",
|
||||
"invalid_auth": "Neplatn\u00e9 overenie",
|
||||
"invalid_mfa_code": "Neplatn\u00fd k\u00f3d MFA"
|
||||
},
|
||||
"step": {
|
||||
"mfa": {
|
||||
"data": {
|
||||
"mfa_code": "K\u00f3d MFA (6-miestny)"
|
||||
},
|
||||
"title": "Zadajte svoj k\u00f3d MFA pre Abode"
|
||||
},
|
||||
"reauth_confirm": {
|
||||
"data": {
|
||||
"password": "Heslo",
|
||||
"username": "Email"
|
||||
}
|
||||
},
|
||||
"title": "Vypl\u0148te svoje prihlasovacie \u00fadaje do slu\u017eby Abode"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"password": "Heslo",
|
||||
"username": "Email"
|
||||
}
|
||||
},
|
||||
"title": "Vypl\u0148te svoje prihlasovacie \u00fadaje Abode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,22 @@ from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.schema_config_entry_flow import (
|
||||
SchemaFlowFormStep,
|
||||
SchemaOptionsFlowHandler,
|
||||
)
|
||||
|
||||
from .const import CONF_FORECAST, DOMAIN
|
||||
|
||||
OPTIONS_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_FORECAST, default=False): bool,
|
||||
}
|
||||
)
|
||||
OPTIONS_FLOW = {
|
||||
"init": SchemaFlowFormStep(OPTIONS_SCHEMA),
|
||||
}
|
||||
|
||||
|
||||
class AccuWeatherFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Config flow for AccuWeather."""
|
||||
@ -84,41 +97,6 @@ class AccuWeatherFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(
|
||||
config_entry: ConfigEntry,
|
||||
) -> AccuWeatherOptionsFlowHandler:
|
||||
def async_get_options_flow(config_entry: ConfigEntry) -> SchemaOptionsFlowHandler:
|
||||
"""Options callback for AccuWeather."""
|
||||
return AccuWeatherOptionsFlowHandler(config_entry)
|
||||
|
||||
|
||||
class AccuWeatherOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Config flow options for AccuWeather."""
|
||||
|
||||
def __init__(self, entry: ConfigEntry) -> None:
|
||||
"""Initialize AccuWeather options flow."""
|
||||
self.config_entry = entry
|
||||
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Manage the options."""
|
||||
return await self.async_step_user()
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle a flow initialized by the user."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_FORECAST,
|
||||
default=self.config_entry.options.get(CONF_FORECAST, False),
|
||||
): bool
|
||||
}
|
||||
),
|
||||
)
|
||||
return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW)
|
||||
|
@ -253,7 +253,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||
name="Cloud ceiling",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
unit_fn=lambda metric: LENGTH_METERS if metric else LENGTH_FEET,
|
||||
value_fn=lambda data, unit: round(data[unit][ATTR_VALUE]),
|
||||
value_fn=lambda data, unit: round(cast(float, data[unit][ATTR_VALUE])),
|
||||
),
|
||||
AccuWeatherSensorDescription(
|
||||
key="CloudCover",
|
||||
|
@ -24,7 +24,7 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"user": {
|
||||
"init": {
|
||||
"description": "Due to the limitations of the free version of the AccuWeather API key, when you enable weather forecast, data updates will be performed every 80 minutes instead of every 40 minutes.",
|
||||
"data": {
|
||||
"forecast": "Weather forecast"
|
||||
|
@ -20,6 +20,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "\u041f\u0440\u043e\u0433\u043d\u043e\u0437\u0430 \u0437\u0430 \u0432\u0440\u0435\u043c\u0435\u0442\u043e"
|
||||
},
|
||||
"description": "\u041f\u043e\u0440\u0430\u0434\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u0442\u0430 \u043d\u0430 \u0431\u0435\u0437\u043f\u043b\u0430\u0442\u043d\u0430\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f \u043d\u0430 API \u043a\u043b\u044e\u0447\u0430 \u043d\u0430 AccuWeather, \u043a\u043e\u0433\u0430\u0442\u043e \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0430\u0442\u0435 \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430\u0442\u0430 \u0437\u0430 \u0432\u0440\u0435\u043c\u0435\u0442\u043e, \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\u0442\u0435 \u043d\u0430 \u0434\u0430\u043d\u043d\u0438 \u0449\u0435 \u0441\u0435 \u0438\u0437\u0432\u044a\u0440\u0448\u0432\u0430\u0442 \u043d\u0430 \u0432\u0441\u0435\u043a\u0438 80 \u043c\u0438\u043d\u0443\u0442\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0430 \u0432\u0441\u0435\u043a\u0438 40 \u043c\u0438\u043d\u0443\u0442\u0438."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "\u041f\u0440\u043e\u0433\u043d\u043e\u0437\u0430 \u0437\u0430 \u0432\u0440\u0435\u043c\u0435\u0442\u043e"
|
||||
|
@ -24,6 +24,11 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Previsi\u00f3 meteorol\u00f2gica"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Previsi\u00f3 meteorol\u00f2gica"
|
||||
|
@ -21,6 +21,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "P\u0159edpov\u011b\u010f po\u010das\u00ed"
|
||||
},
|
||||
"description": "Vzhledem k omezen\u00edm bezplatn\u00e9 verze kl\u00ed\u010de AccuWeather API, kdy\u017e povol\u00edte p\u0159edpov\u011b\u010f po\u010das\u00ed, aktualizace dat se budou prov\u00e1d\u011bt ka\u017ed\u00fdch 80 minut m\u00edsto ka\u017ed\u00fdch 40 minut."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "P\u0159edpov\u011b\u010f po\u010das\u00ed"
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Wettervorhersage"
|
||||
},
|
||||
"description": "Aufgrund der Einschr\u00e4nkungen der kostenlosen Version des AccuWeather API-Schl\u00fcssels werden bei aktivierter Wettervorhersage Datenaktualisierungen alle 80 Minuten statt alle 40 Minuten durchgef\u00fchrt."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Wettervorhersage"
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "\u03a0\u03c1\u03cc\u03b3\u03bd\u03c9\u03c3\u03b7 \u03ba\u03b1\u03b9\u03c1\u03bf\u03cd"
|
||||
},
|
||||
"description": "\u039b\u03cc\u03b3\u03c9 \u03c4\u03c9\u03bd \u03c0\u03b5\u03c1\u03b9\u03bf\u03c1\u03b9\u03c3\u03bc\u03ce\u03bd \u03c4\u03b7\u03c2 \u03b4\u03c9\u03c1\u03b5\u03ac\u03bd \u03ad\u03ba\u03b4\u03bf\u03c3\u03b7\u03c2 \u03c4\u03bf\u03c5 \u03ba\u03bb\u03b5\u03b9\u03b4\u03b9\u03bf\u03cd AccuWeather API, \u03cc\u03c4\u03b1\u03bd \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b5\u03af\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c0\u03c1\u03cc\u03b3\u03bd\u03c9\u03c3\u03b7 \u03ba\u03b1\u03b9\u03c1\u03bf\u03cd, \u03bf\u03b9 \u03b5\u03bd\u03b7\u03bc\u03b5\u03c1\u03ce\u03c3\u03b5\u03b9\u03c2 \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03b8\u03b1 \u03b5\u03ba\u03c4\u03b5\u03bb\u03bf\u03cd\u03bd\u03c4\u03b1\u03b9 \u03ba\u03ac\u03b8\u03b5 80 \u03bb\u03b5\u03c0\u03c4\u03ac \u03b1\u03bd\u03c4\u03af \u03b3\u03b9\u03b1 \u03ba\u03ac\u03b8\u03b5 40 \u03bb\u03b5\u03c0\u03c4\u03ac."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "\u03a0\u03c1\u03cc\u03b3\u03bd\u03c9\u03c3\u03b7 \u03ba\u03b1\u03b9\u03c1\u03bf\u03cd"
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Weather forecast"
|
||||
},
|
||||
"description": "Due to the limitations of the free version of the AccuWeather API key, when you enable weather forecast, data updates will be performed every 80 minutes instead of every 40 minutes."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Weather forecast"
|
||||
|
@ -4,7 +4,7 @@
|
||||
"single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n."
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "Algunos sensores no est\u00e1n habilitados de forma predeterminada. Puedes habilitarlos en el registro de la entidad despu\u00e9s de la configuraci\u00f3n de la integraci\u00f3n.\nEl pron\u00f3stico del tiempo no est\u00e1 habilitado de forma predeterminada. Puedes habilitarlo en las opciones de integraci\u00f3n."
|
||||
"default": "Algunos sensores no est\u00e1n habilitados de forma predeterminada. Puedes habilitarlos en el registro de la entidad despu\u00e9s de la configuraci\u00f3n de la integraci\u00f3n.\nLa previsi\u00f3n meteorol\u00f3gica no est\u00e1 habilitada de forma predeterminada. Puedes habilitarla en las opciones de integraci\u00f3n."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
@ -24,11 +24,17 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Previsi\u00f3n meteorol\u00f3gica"
|
||||
},
|
||||
"description": "Debido a las limitaciones de la versi\u00f3n gratuita de la clave API de AccuWeather, cuando habilitas la previsi\u00f3n meteorol\u00f3gica, las actualizaciones de datos se realizar\u00e1n cada 80 minutos en lugar de cada 40 minutos."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Pron\u00f3stico del tiempo"
|
||||
"forecast": "Previsi\u00f3n meteorol\u00f3gica"
|
||||
},
|
||||
"description": "Debido a las limitaciones de la versi\u00f3n gratuita de la clave API de AccuWeather, cuando habilitas el pron\u00f3stico del tiempo, las actualizaciones de datos se realizar\u00e1n cada 80 minutos en lugar de cada 40 minutos."
|
||||
"description": "Debido a las limitaciones de la versi\u00f3n gratuita de la clave API de AccuWeather, cuando habilitas la previsi\u00f3n meteorol\u00f3gica, las actualizaciones de datos se realizar\u00e1n cada 80 minutos en lugar de cada 40 minutos."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Ilmateade"
|
||||
},
|
||||
"description": "AccuWeather API tasuta versioonis toimub ilmaennustuse lubamisel andmete v\u00e4rskendamine iga 80 minuti j\u00e4rel (muidu 40 minutit)."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Ilmateade"
|
||||
|
@ -24,6 +24,11 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Pr\u00e9visions m\u00e9t\u00e9orologiques"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Pr\u00e9visions m\u00e9t\u00e9orologiques"
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Prakiraan cuaca"
|
||||
},
|
||||
"description": "Karena keterbatasan versi gratis kunci API AccuWeather, ketika Anda mengaktifkan prakiraan cuaca, pembaruan data akan dilakukan setiap 80 menit, bukan setiap 40 menit."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Prakiraan cuaca"
|
||||
|
@ -28,7 +28,7 @@
|
||||
"data": {
|
||||
"forecast": "\u5929\u6c17\u4e88\u5831"
|
||||
},
|
||||
"description": "\u5236\u9650\u306b\u3088\u308a\u7121\u6599\u30d0\u30fc\u30b8\u30e7\u30f3\u306eAccuWeather API\u30ad\u30fc\u3067\u306f\u3001\u5929\u6c17\u4e88\u5831\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u30c7\u30fc\u30bf\u306e\u66f4\u65b0\u306f40\u5206\u3067\u306f\u306a\u304f80\u5206\u3054\u3068\u3067\u3059\u3002"
|
||||
"description": "\u7121\u6599\u7248\u306eAccuWeather API\u30ad\u30fc\u306e\u5236\u9650\u306b\u3088\u308a\u3001\u5929\u6c17\u4e88\u5831\u3092\u6709\u52b9\u306b\u3057\u305f\u5834\u5408\u3001\u30c7\u30fc\u30bf\u306e\u66f4\u65b0\u306f40\u5206\u6bce\u3067\u306f\u306a\u304f80\u5206\u6bce\u306b\u5b9f\u884c\u3055\u308c\u307e\u3059\u3002"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Weersverwachting"
|
||||
},
|
||||
"description": "Wanneer je de weersverwachting ingeschakeld zullen updates elke 80 minuten plaatsvinden i.p.v. elke 40 minuten, dit komt door de beperkingen van de gratis versie van de AccuWeather API sleutel."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Weervoorspelling"
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "V\u00e6rmelding"
|
||||
},
|
||||
"description": "P\u00e5 grunn av begrensningene til gratisversjonen av AccuWeather API-n\u00f8kkelen, n\u00e5r du aktiverer v\u00e6rmelding, vil dataoppdateringer utf\u00f8res hvert 80. minutt i stedet for hvert 40. minutt."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "V\u00e6rmelding"
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Previs\u00e3o do tempo"
|
||||
},
|
||||
"description": "Devido \u00e0s limita\u00e7\u00f5es da vers\u00e3o gratuita da chave API AccuWeather, quando voc\u00ea ativa a previs\u00e3o do tempo, as atualiza\u00e7\u00f5es de dados s\u00e3o realizadas a cada 80 minutos em vez de 40 minutos."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Previs\u00e3o do Tempo"
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "\u041f\u0440\u043e\u0433\u043d\u043e\u0437 \u043f\u043e\u0433\u043e\u0434\u044b"
|
||||
},
|
||||
"description": "\u0412 \u0441\u0432\u044f\u0437\u0438 \u0441 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043a\u043b\u044e\u0447\u0430 API AccuWeather, \u043f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430 \u043f\u043e\u0433\u043e\u0434\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0435 80 \u043c\u0438\u043d\u0443\u0442, \u0430 \u043d\u0435 \u043a\u0430\u0436\u0434\u044b\u0435 40 \u043c\u0438\u043d\u0443\u0442."
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "\u041f\u0440\u043e\u0433\u043d\u043e\u0437 \u043f\u043e\u0433\u043e\u0434\u044b"
|
||||
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"state": {
|
||||
"accuweather__pressure_tendency": {
|
||||
"falling": "Klesaj\u00faci",
|
||||
"rising": "Padaj\u00faci"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,12 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"single_instance_allowed": "U\u017e je nakonfigurovan\u00fd. Mo\u017en\u00e1 len jedna konfigur\u00e1cia."
|
||||
},
|
||||
"error": {
|
||||
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d"
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165",
|
||||
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d",
|
||||
"requests_exceeded": "Povolen\u00fd po\u010det po\u017eiadaviek na rozhranie Accuweather API bol prekro\u010den\u00fd. Mus\u00edte po\u010dka\u0165 alebo zmeni\u0165 k\u013e\u00fa\u010d API."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
@ -13,5 +18,25 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "Predpove\u010f po\u010dasia"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "Predpove\u010f po\u010dasia"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "Oslovi\u0165 server AccuWeather",
|
||||
"remaining_requests": "Zost\u00e1vaj\u00face povolen\u00e9 \u017eiadosti"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,14 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "\u5929\u6c14\u9884\u62a5"
|
||||
},
|
||||
"description": "\u7531\u4e8e AccuWeather API \u5bc6\u94a5\u514d\u8d39\u7248\u672c\u7684\u9650\u5236\uff0c\u5f53\u60a8\u542f\u7528\u5929\u6c14\u9884\u62a5\u65f6\uff0c\u6570\u636e\u66f4\u65b0\u5c06\u6bcf 80 \u5206\u949f\u6267\u884c\u4e00\u6b21\uff0c\u800c\u4e0d\u662f\u6bcf 40 \u5206\u949f\u4e00\u6b21\u3002"
|
||||
}
|
||||
}
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "\u53ef\u8bbf\u95ee AccuWeather \u670d\u52a1\u5668",
|
||||
|
@ -24,6 +24,12 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"forecast": "\u5929\u6c23\u9810\u5831"
|
||||
},
|
||||
"description": "\u7531\u65bc AccuWeather API \u91d1\u9470\u514d\u8cbb\u7248\u672c\u9650\u5236\uff0c\u7576\u958b\u555f\u5929\u6c23\u9810\u5831\u6642\u3001\u6578\u64da\u6703\u6bcf 80 \u5206\u9418\u66f4\u65b0\u4e00\u6b21\uff0c\u800c\u975e 40 \u5206\u9418\u3002"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"forecast": "\u5929\u6c23\u9810\u5831"
|
||||
|
@ -18,16 +18,11 @@ from homeassistant.components.weather import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
LENGTH_INCHES,
|
||||
LENGTH_KILOMETERS,
|
||||
LENGTH_MILES,
|
||||
LENGTH_MILLIMETERS,
|
||||
PRESSURE_HPA,
|
||||
PRESSURE_INHG,
|
||||
SPEED_KILOMETERS_PER_HOUR,
|
||||
SPEED_MILES_PER_HOUR,
|
||||
TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT,
|
||||
UnitOfLength,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
@ -72,19 +67,19 @@ class AccuWeatherEntity(
|
||||
# converted, hence the weather entity's native units follow the configured unit
|
||||
# system
|
||||
if coordinator.hass.config.units is METRIC_SYSTEM:
|
||||
self._attr_native_precipitation_unit = LENGTH_MILLIMETERS
|
||||
self._attr_native_pressure_unit = PRESSURE_HPA
|
||||
self._attr_native_temperature_unit = TEMP_CELSIUS
|
||||
self._attr_native_visibility_unit = LENGTH_KILOMETERS
|
||||
self._attr_native_wind_speed_unit = SPEED_KILOMETERS_PER_HOUR
|
||||
self._attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS
|
||||
self._attr_native_pressure_unit = UnitOfPressure.HPA
|
||||
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
self._attr_native_visibility_unit = UnitOfLength.KILOMETERS
|
||||
self._attr_native_wind_speed_unit = UnitOfSpeed.KILOMETERS_PER_HOUR
|
||||
self._unit_system = API_METRIC
|
||||
else:
|
||||
self._unit_system = API_IMPERIAL
|
||||
self._attr_native_precipitation_unit = LENGTH_INCHES
|
||||
self._attr_native_pressure_unit = PRESSURE_INHG
|
||||
self._attr_native_temperature_unit = TEMP_FAHRENHEIT
|
||||
self._attr_native_visibility_unit = LENGTH_MILES
|
||||
self._attr_native_wind_speed_unit = SPEED_MILES_PER_HOUR
|
||||
self._attr_native_precipitation_unit = UnitOfPrecipitationDepth.INCHES
|
||||
self._attr_native_pressure_unit = UnitOfPressure.INHG
|
||||
self._attr_native_temperature_unit = UnitOfTemperature.FAHRENHEIT
|
||||
self._attr_native_visibility_unit = UnitOfLength.MILES
|
||||
self._attr_native_wind_speed_unit = UnitOfSpeed.MILES_PER_HOUR
|
||||
self._attr_unique_id = coordinator.location_key
|
||||
self._attr_attribution = ATTRIBUTION
|
||||
self._attr_device_info = coordinator.device_info
|
||||
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from contextlib import suppress
|
||||
from typing import Any
|
||||
|
||||
import aiopulse
|
||||
import async_timeout
|
||||
@ -10,6 +11,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_HOST, CONF_ID
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
@ -19,11 +21,13 @@ class AcmedaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the config flow."""
|
||||
self.discovered_hubs: dict[str, aiopulse.Hub] | None = None
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle a flow initialized by the user."""
|
||||
if (
|
||||
user_input is not None
|
||||
@ -37,7 +41,7 @@ class AcmedaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
entry.unique_id for entry in self._async_current_entries()
|
||||
}
|
||||
|
||||
hubs = []
|
||||
hubs: list[aiopulse.Hub] = []
|
||||
with suppress(asyncio.TimeoutError):
|
||||
async with async_timeout.timeout(5):
|
||||
async for hub in aiopulse.Hub.discover():
|
||||
@ -63,7 +67,7 @@ class AcmedaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
),
|
||||
)
|
||||
|
||||
async def async_create(self, hub):
|
||||
async def async_create(self, hub: aiopulse.Hub) -> FlowResult:
|
||||
"""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={CONF_HOST: hub.host})
|
||||
|
@ -70,9 +70,9 @@ class AcmedaCover(AcmedaBase, CoverEntity):
|
||||
return position
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
def supported_features(self) -> CoverEntityFeature:
|
||||
"""Flag supported features."""
|
||||
supported_features = 0
|
||||
supported_features = CoverEntityFeature(0)
|
||||
if self.current_cover_position is not None:
|
||||
supported_features |= (
|
||||
CoverEntityFeature.OPEN
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"no_devices_found": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05db\u05e9\u05d9\u05e8\u05d9\u05dd \u05d1\u05e8\u05e9\u05ea"
|
||||
"no_devices_found": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05d4\u05ea\u05e7\u05e0\u05d9\u05dd \u05d1\u05e8\u05e9\u05ea"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
|
14
homeassistant/components/acmeda/translations/sk.json
Normal file
14
homeassistant/components/acmeda/translations/sk.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"no_devices_found": "V sieti sa nena\u0161li \u017eiadne zariadenia"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"id": "ID hostite\u013ea"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,33 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Zariadenie u\u017e je nakonfigurovan\u00e9",
|
||||
"heater_not_available": "Ohrieva\u010d nie je k dispoz\u00edcii. Sk\u00faste resetova\u0165 ohrieva\u010d stla\u010den\u00edm + a OK na nieko\u013eko sek\u00fand.",
|
||||
"heater_not_found": "Ohrieva\u010d sa nena\u0161iel. Sk\u00faste presun\u00fa\u0165 ohrieva\u010d bli\u017e\u0161ie k Home Assistant.",
|
||||
"invalid_auth": "Neplatn\u00e9 overenie"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165"
|
||||
},
|
||||
"step": {
|
||||
"cloud": {
|
||||
"data": {
|
||||
"account_id": "ID \u00fa\u010dtu",
|
||||
"password": "Heslo"
|
||||
}
|
||||
},
|
||||
"local": {
|
||||
"data": {
|
||||
"wifi_pswd": "Heslo Wi-Fi",
|
||||
"wifi_ssid": "Wi-Fi SSID"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"connection_type": "Vyberte typ pripojenia"
|
||||
},
|
||||
"description": "Vyberte typ pripojenia. Miestne vy\u017eaduje ohrieva\u010de s bluetooth"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,25 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Slu\u017eba u\u017e je nakonfigurovan\u00e1",
|
||||
"existing_instance_updated": "Aktualizovan\u00e1 existuj\u00faca konfigur\u00e1cia."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165"
|
||||
},
|
||||
"step": {
|
||||
"hassio_confirm": {
|
||||
"description": "Chcete nakonfigurova\u0165 Home Assistant na pripojenie k AdGuard Home poskytovan\u00e9mu doplnkom: {addon}?",
|
||||
"title": "AdGuard Home cez doplnok Home Assistant"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"port": "Port"
|
||||
"host": "Hostite\u013e",
|
||||
"password": "Heslo",
|
||||
"port": "Port",
|
||||
"ssl": "Pou\u017e\u00edva SSL certifik\u00e1t",
|
||||
"username": "Pou\u017e\u00edvate\u013esk\u00e9 meno",
|
||||
"verify_ssl": "Overi\u0165 SSL certifik\u00e1t"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,18 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Zariadenie u\u017e je nakonfigurovan\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP adresa",
|
||||
"port": "Port"
|
||||
}
|
||||
},
|
||||
"title": "Pripoji\u0165"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,22 @@ from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.schema_config_entry_flow import (
|
||||
SchemaFlowFormStep,
|
||||
SchemaOptionsFlowHandler,
|
||||
)
|
||||
|
||||
from .const import CONF_STATION_UPDATES, DEFAULT_NAME, DOMAIN
|
||||
|
||||
OPTIONS_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_STATION_UPDATES): bool,
|
||||
}
|
||||
)
|
||||
OPTIONS_FLOW = {
|
||||
"init": SchemaFlowFormStep(OPTIONS_SCHEMA),
|
||||
}
|
||||
|
||||
|
||||
class AemetConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Config flow for AEMET OpenData."""
|
||||
@ -54,32 +67,9 @@ class AemetConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
@callback
|
||||
def async_get_options_flow(
|
||||
config_entry: config_entries.ConfigEntry,
|
||||
) -> OptionsFlowHandler:
|
||||
) -> SchemaOptionsFlowHandler:
|
||||
"""Get the options flow for this handler."""
|
||||
return OptionsFlowHandler(config_entry)
|
||||
|
||||
|
||||
class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Handle a option flow for AEMET."""
|
||||
|
||||
def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
|
||||
"""Initialize options flow."""
|
||||
self.config_entry = config_entry
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
"""Handle options flow."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
||||
data_schema = vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
CONF_STATION_UPDATES,
|
||||
default=self.config_entry.options.get(CONF_STATION_UPDATES),
|
||||
): bool,
|
||||
}
|
||||
)
|
||||
return self.async_show_form(step_id="init", data_schema=data_schema)
|
||||
return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW)
|
||||
|
||||
|
||||
async def _is_aemet_api_online(hass, api_key):
|
||||
|
@ -1,5 +1,8 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Umiestnenie u\u017e je nakonfigurovan\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d"
|
||||
},
|
||||
@ -8,7 +11,18 @@
|
||||
"data": {
|
||||
"api_key": "API k\u013e\u00fa\u010d",
|
||||
"latitude": "Zemepisn\u00e1 \u0161\u00edrka",
|
||||
"longitude": "Zemepisn\u00e1 d\u013a\u017eka"
|
||||
"longitude": "Zemepisn\u00e1 d\u013a\u017eka",
|
||||
"name": "N\u00e1zov integr\u00e1cie"
|
||||
},
|
||||
"description": "Ak chcete vygenerova\u0165 k\u013e\u00fa\u010d API, prejdite na https://opendata.aemet.es/centrodedescargas/altaUsuario"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"station_updates": "Zhroma\u017edi\u0165 \u00fadaje z meteorologick\u00fdch stan\u00edc AEMET"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ from homeassistant.components.weather import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
LENGTH_MILLIMETERS,
|
||||
PRESSURE_HPA,
|
||||
SPEED_KILOMETERS_PER_HOUR,
|
||||
TEMP_CELSIUS,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
@ -91,10 +91,10 @@ class AemetWeather(CoordinatorEntity[WeatherUpdateCoordinator], WeatherEntity):
|
||||
"""Implementation of an AEMET OpenData sensor."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
_attr_native_precipitation_unit = LENGTH_MILLIMETERS
|
||||
_attr_native_pressure_unit = PRESSURE_HPA
|
||||
_attr_native_temperature_unit = TEMP_CELSIUS
|
||||
_attr_native_wind_speed_unit = SPEED_KILOMETERS_PER_HOUR
|
||||
_attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS
|
||||
_attr_native_pressure_unit = UnitOfPressure.HPA
|
||||
_attr_native_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
_attr_native_wind_speed_unit = UnitOfSpeed.KILOMETERS_PER_HOUR
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -1,11 +1,16 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Zariadenie u\u017e je nakonfigurovan\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"already_in_progress": "Konfigur\u00e1cia u\u017e prebieha"
|
||||
"already_in_progress": "Konfigur\u00e1cia u\u017e prebieha",
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "Hostite\u013e",
|
||||
"port": "Port"
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,8 @@
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "Lze kontaktovat Airly server"
|
||||
"can_reach_server": "Lze kontaktovat Airly server",
|
||||
"requests_per_day": "Povolen\u00e9 po\u017eadavky za den"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Umiestnenie u\u017e je nakonfigurovan\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d"
|
||||
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d",
|
||||
"wrong_location": "V tejto oblasti nie s\u00fa \u017eiadne meracie stanice Airly."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
@ -10,8 +14,16 @@
|
||||
"latitude": "Zemepisn\u00e1 \u0161\u00edrka",
|
||||
"longitude": "Zemepisn\u00e1 d\u013a\u017eka",
|
||||
"name": "N\u00e1zov"
|
||||
}
|
||||
},
|
||||
"description": "Ak chcete vygenerova\u0165 k\u013e\u00fa\u010d API, prejdite na https://developer.airly.eu/register"
|
||||
}
|
||||
}
|
||||
},
|
||||
"system_health": {
|
||||
"info": {
|
||||
"can_reach_server": "Dosta\u0148te sa na server Airly",
|
||||
"requests_per_day": "Povolen\u00e9 po\u017eiadavky za de\u0148",
|
||||
"requests_remaining": "Zost\u00e1vaj\u00face povolen\u00e9 \u017eiadosti"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,23 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Zariadenie u\u017e je nakonfigurovan\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"invalid_auth": "Neplatn\u00e9 overenie"
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165",
|
||||
"invalid_auth": "Neplatn\u00e9 overenie",
|
||||
"invalid_location": "Pre t\u00fato lokalitu sa nena\u0161li \u017eiadne v\u00fdsledky",
|
||||
"unknown": "Neo\u010dak\u00e1van\u00e1 chyba"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"api_key": "API k\u013e\u00fa\u010d",
|
||||
"latitude": "Zemepisn\u00e1 \u0161\u00edrka",
|
||||
"longitude": "Zemepisn\u00e1 d\u013a\u017eka"
|
||||
}
|
||||
"longitude": "Zemepisn\u00e1 d\u013a\u017eka",
|
||||
"radius": "Polomer stanice (m\u00edle; volite\u013en\u00e9)"
|
||||
},
|
||||
"description": "Ak chcete vygenerova\u0165 k\u013e\u00fa\u010d API, prejdite na https://docs.airnowapi.org/account/request/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
78
homeassistant/components/airq/__init__.py
Normal file
78
homeassistant/components/airq/__init__.py
Normal file
@ -0,0 +1,78 @@
|
||||
"""The air-Q integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from aioairq import AirQ
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from .const import DOMAIN, MANUFACTURER, TARGET_ROUTE, UPDATE_INTERVAL
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
||||
|
||||
|
||||
class AirQCoordinator(DataUpdateCoordinator):
|
||||
"""Coordinator is responsible for querying the device at a specified route."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
) -> None:
|
||||
"""Initialise a custom coordinator."""
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=DOMAIN,
|
||||
update_interval=timedelta(seconds=UPDATE_INTERVAL),
|
||||
)
|
||||
session = async_get_clientsession(hass)
|
||||
self.airq = AirQ(
|
||||
entry.data[CONF_IP_ADDRESS], entry.data[CONF_PASSWORD], session
|
||||
)
|
||||
self.device_id = entry.unique_id
|
||||
assert self.device_id is not None
|
||||
self.device_info = DeviceInfo(
|
||||
manufacturer=MANUFACTURER,
|
||||
identifiers={(DOMAIN, self.device_id)},
|
||||
)
|
||||
self.device_info.update(entry.data["device_info"])
|
||||
|
||||
async def _async_update_data(self) -> dict:
|
||||
"""Fetch the data from the device."""
|
||||
data = await self.airq.get(TARGET_ROUTE)
|
||||
return self.airq.drop_uncertainties_from_data(data)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up air-Q from a config entry."""
|
||||
|
||||
coordinator = AirQCoordinator(hass, entry)
|
||||
|
||||
# Query the device for the first time and initialise coordinator.data
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
# Record the coordinator in a global store
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
hass.data[DOMAIN][entry.entry_id] = coordinator
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
|
||||
return unload_ok
|
84
homeassistant/components/airq/config_flow.py
Normal file
84
homeassistant/components/airq/config_flow.py
Normal file
@ -0,0 +1,84 @@
|
||||
"""Config flow for air-Q integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from aioairq import AirQ, InvalidAuth, InvalidInput
|
||||
from aiohttp.client_exceptions import ClientConnectionError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_IP_ADDRESS): str,
|
||||
vol.Required(CONF_PASSWORD): str,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for air-Q."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle the initial (authentication) configuration step."""
|
||||
if user_input is None:
|
||||
return self.async_show_form(
|
||||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA
|
||||
)
|
||||
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
session = async_get_clientsession(self.hass)
|
||||
try:
|
||||
airq = AirQ(user_input[CONF_IP_ADDRESS], user_input[CONF_PASSWORD], session)
|
||||
except InvalidInput:
|
||||
_LOGGER.debug(
|
||||
"%s does not appear to be a valid IP address or mDNS name",
|
||||
user_input[CONF_IP_ADDRESS],
|
||||
)
|
||||
errors["base"] = "invalid_input"
|
||||
else:
|
||||
try:
|
||||
await airq.validate()
|
||||
except ClientConnectionError:
|
||||
_LOGGER.debug(
|
||||
"Failed to connect to device %s. Check the IP address / device ID "
|
||||
"as well as whether the device is connected to power and the WiFi",
|
||||
user_input[CONF_IP_ADDRESS],
|
||||
)
|
||||
errors["base"] = "cannot_connect"
|
||||
except InvalidAuth:
|
||||
_LOGGER.debug(
|
||||
"Incorrect password for device %s", user_input[CONF_IP_ADDRESS]
|
||||
)
|
||||
errors["base"] = "invalid_auth"
|
||||
else:
|
||||
_LOGGER.debug(
|
||||
"Successfully connected to %s", user_input[CONF_IP_ADDRESS]
|
||||
)
|
||||
|
||||
device_info = await airq.fetch_device_info()
|
||||
await self.async_set_unique_id(device_info.pop("id"))
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
return self.async_create_entry(
|
||||
title=device_info["name"],
|
||||
data=user_input | {"device_info": device_info},
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
||||
)
|
9
homeassistant/components/airq/const.py
Normal file
9
homeassistant/components/airq/const.py
Normal file
@ -0,0 +1,9 @@
|
||||
"""Constants for the air-Q integration."""
|
||||
from typing import Final
|
||||
|
||||
DOMAIN: Final = "airq"
|
||||
MANUFACTURER: Final = "CorantGmbH"
|
||||
TARGET_ROUTE: Final = "average"
|
||||
CONCENTRATION_GRAMS_PER_CUBIC_METER: Final = "g/m³"
|
||||
ACTIVITY_BECQUEREL_PER_CUBIC_METER: Final = "Bq/m³"
|
||||
UPDATE_INTERVAL: float = 10.0
|
11
homeassistant/components/airq/manifest.json
Normal file
11
homeassistant/components/airq/manifest.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"domain": "airq",
|
||||
"name": "air-Q",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/airq",
|
||||
"requirements": ["aioairq==0.2.4"],
|
||||
"codeowners": ["@Sibgatulin", "@dl2080"],
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairq"],
|
||||
"integration_type": "hub"
|
||||
}
|
361
homeassistant/components/airq/sensor.py
Normal file
361
homeassistant/components/airq/sensor.py
Normal file
@ -0,0 +1,361 @@
|
||||
"""Definition of air-Q sensor platform."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from typing import Literal
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
PRESSURE_HPA,
|
||||
SOUND_PRESSURE_WEIGHTED_DBA,
|
||||
TEMP_CELSIUS,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import AirQCoordinator
|
||||
from .const import (
|
||||
ACTIVITY_BECQUEREL_PER_CUBIC_METER,
|
||||
CONCENTRATION_GRAMS_PER_CUBIC_METER,
|
||||
DOMAIN,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class AirQEntityDescriptionMixin:
|
||||
"""Class for keys required by AirQ entity."""
|
||||
|
||||
value: Callable[[dict], float | int | None]
|
||||
|
||||
|
||||
@dataclass
|
||||
class AirQEntityDescription(SensorEntityDescription, AirQEntityDescriptionMixin):
|
||||
"""Describes AirQ sensor entity."""
|
||||
|
||||
|
||||
# Keys must match those in the data dictionary
|
||||
SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
AirQEntityDescription(
|
||||
key="nh3_MR100",
|
||||
name="Ammonia",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("nh3_MR100"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="cl2_M20",
|
||||
name="Chlorine",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("cl2_M20"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="co",
|
||||
name="CO",
|
||||
device_class=SensorDeviceClass.CO,
|
||||
native_unit_of_measurement=CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("co"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="co2",
|
||||
name="CO2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("co2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="dewpt",
|
||||
name="Dew point",
|
||||
native_unit_of_measurement=TEMP_CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("dewpt"),
|
||||
icon="mdi:water-thermometer",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="ethanol",
|
||||
name="Ethanol",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ethanol"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="ch2o_M10",
|
||||
name="Formaldehyde",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ch2o_M10"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="h2s",
|
||||
name="H2S",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("h2s"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="health",
|
||||
name="Health Index",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
icon="mdi:heart-pulse",
|
||||
value=lambda data: data.get("health", 0.0) / 10.0,
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="humidity",
|
||||
name="Humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("humidity"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="humidity_abs",
|
||||
name="Absolute humidity",
|
||||
native_unit_of_measurement=CONCENTRATION_GRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("humidity_abs"),
|
||||
icon="mdi:water",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="h2_M1000",
|
||||
name="Hydrogen",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("h2_M1000"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="ch4_MIPEX",
|
||||
name="Methane",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ch4_MIPEX"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="n2o",
|
||||
name="N2O",
|
||||
device_class=SensorDeviceClass.NITROUS_OXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("n2o"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="no_M250",
|
||||
name="NO",
|
||||
device_class=SensorDeviceClass.NITROGEN_MONOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("no_M250"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="no2",
|
||||
name="NO2",
|
||||
device_class=SensorDeviceClass.NITROGEN_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("no2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="o3",
|
||||
name="Ozone",
|
||||
device_class=SensorDeviceClass.OZONE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("o3"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="oxygen",
|
||||
name="Oxygen",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("oxygen"),
|
||||
icon="mdi:leaf",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="performance",
|
||||
name="Performance Index",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
icon="mdi:head-check",
|
||||
value=lambda data: data.get("performance", 0.0) / 10.0,
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="pm1",
|
||||
name="PM1",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("pm1"),
|
||||
icon="mdi:dots-hexagon",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="pm2_5",
|
||||
name="PM2.5",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("pm2_5"),
|
||||
icon="mdi:dots-hexagon",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="pm10",
|
||||
name="PM10",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("pm10"),
|
||||
icon="mdi:dots-hexagon",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="pressure",
|
||||
name="Pressure",
|
||||
device_class=SensorDeviceClass.PRESSURE,
|
||||
native_unit_of_measurement=PRESSURE_HPA,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("pressure"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="pressure_rel",
|
||||
name="Relative pressure",
|
||||
native_unit_of_measurement=PRESSURE_HPA,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("pressure_rel"),
|
||||
icon="mdi:gauge",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="c3h8_MIPEX",
|
||||
name="Propane",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("c3h8_MIPEX"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="so2",
|
||||
name="SO2",
|
||||
device_class=SensorDeviceClass.SULPHUR_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("so2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="sound",
|
||||
name="Noise",
|
||||
native_unit_of_measurement=SOUND_PRESSURE_WEIGHTED_DBA,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("sound"),
|
||||
icon="mdi:ear-hearing",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="sound_max",
|
||||
name="Noise (Maximum)",
|
||||
native_unit_of_measurement=SOUND_PRESSURE_WEIGHTED_DBA,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("sound_max"),
|
||||
icon="mdi:ear-hearing",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="radon",
|
||||
name="Radon",
|
||||
native_unit_of_measurement=ACTIVITY_BECQUEREL_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("radon"),
|
||||
icon="mdi:radioactive",
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="temperature",
|
||||
name="Temperature",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
native_unit_of_measurement=TEMP_CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("temperature"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="tvoc",
|
||||
name="VOC",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("tvoc"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="tvoc_ionsc",
|
||||
name="VOC (Industrial)",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("tvoc_ionsc"),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up sensor entities based on a config entry."""
|
||||
|
||||
coordinator = hass.data[DOMAIN][config.entry_id]
|
||||
|
||||
entities: list[AirQSensor] = []
|
||||
|
||||
device_status: dict[str, str] | Literal["OK"] = coordinator.data["Status"]
|
||||
|
||||
for description in SENSOR_TYPES:
|
||||
if description.key not in coordinator.data:
|
||||
if isinstance(
|
||||
device_status, dict
|
||||
) and "sensor still in warm up phase" in device_status.get(
|
||||
description.key, "OK"
|
||||
):
|
||||
# warming up sensors do not contribute keys to coordinator.data
|
||||
# but still must be added
|
||||
_LOGGER.debug("Following sensor is warming up: %s", description.key)
|
||||
else:
|
||||
continue
|
||||
entities.append(AirQSensor(coordinator, description))
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class AirQSensor(CoordinatorEntity, SensorEntity):
|
||||
"""Representation of a Sensor."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirQCoordinator,
|
||||
description: AirQEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize a single sensor."""
|
||||
super().__init__(coordinator)
|
||||
self.entity_description: AirQEntityDescription = description
|
||||
|
||||
self._attr_device_info = coordinator.device_info
|
||||
self._attr_name = description.name
|
||||
self._attr_unique_id = f"{coordinator.device_id}_{description.key}"
|
||||
self._attr_native_value = description.value(coordinator.data)
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle updated data from the coordinator."""
|
||||
self._attr_native_value = self.entity_description.value(self.coordinator.data)
|
||||
self.async_write_ha_state()
|
22
homeassistant/components/airq/strings.json
Normal file
22
homeassistant/components/airq/strings.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Identify the device",
|
||||
"description": "Provide the IP address or mDNS of the device and its password",
|
||||
"data": {
|
||||
"ip_address": "[%key:common::config_flow::data::ip%]",
|
||||
"password": "[%key:common::config_flow::data::password%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"invalid_input": "[%key:common::config_flow::error::invalid_host%]"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/bg.json
Normal file
22
homeassistant/components/airq/translations/bg.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435",
|
||||
"invalid_auth": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044f\u0432\u0430\u043d\u0435",
|
||||
"invalid_input": "\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e \u0438\u043c\u0435 \u043d\u0430 \u0445\u043e\u0441\u0442 \u0438\u043b\u0438 IP \u0430\u0434\u0440\u0435\u0441"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP \u0430\u0434\u0440\u0435\u0441",
|
||||
"password": "\u041f\u0430\u0440\u043e\u043b\u0430"
|
||||
},
|
||||
"description": "\u041f\u043e\u0441\u043e\u0447\u0435\u0442\u0435 IP \u0430\u0434\u0440\u0435\u0441\u0430 \u0438\u043b\u0438 mDNS \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u0438 \u043d\u0435\u0433\u043e\u0432\u0430\u0442\u0430 \u043f\u0430\u0440\u043e\u043b\u0430",
|
||||
"title": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/ca.json
Normal file
22
homeassistant/components/airq/translations/ca.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "El dispositiu ja est\u00e0 configurat"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Ha fallat la connexi\u00f3",
|
||||
"invalid_auth": "Autenticaci\u00f3 inv\u00e0lida",
|
||||
"invalid_input": "Nom de l'amfitri\u00f3 o adre\u00e7a IP inv\u00e0lids"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "Adre\u00e7a IP",
|
||||
"password": "Contrasenya"
|
||||
},
|
||||
"description": "Proporciona l'adre\u00e7a IP o el mDNS del dispositiu i la seva contrasenya",
|
||||
"title": "Identificaci\u00f3 del dispositiu"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
homeassistant/components/airq/translations/cs.json
Normal file
20
homeassistant/components/airq/translations/cs.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"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",
|
||||
"invalid_input": "Neplatn\u00fd hostitel nebo IP adresa"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP adresa",
|
||||
"password": "Heslo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/de.json
Normal file
22
homeassistant/components/airq/translations/de.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Ger\u00e4t ist bereits konfiguriert"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Verbindung fehlgeschlagen",
|
||||
"invalid_auth": "Ung\u00fcltige Authentifizierung",
|
||||
"invalid_input": "Ung\u00fcltiger Hostname oder IP-Adresse"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP-Adresse",
|
||||
"password": "Passwort"
|
||||
},
|
||||
"description": "Gib die IP-Adresse oder den mDNS des Ger\u00e4ts und sein Passwort an",
|
||||
"title": "Identifizieren des Ger\u00e4ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/el.json
Normal file
22
homeassistant/components/airq/translations/el.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "\u0397 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03ad\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03c9\u03b8\u03b5\u03af"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2",
|
||||
"invalid_auth": "\u039c\u03b7 \u03ad\u03b3\u03ba\u03c5\u03c1\u03bf\u03c2 \u03ad\u03bb\u03b5\u03b3\u03c7\u03bf\u03c2 \u03c4\u03b1\u03c5\u03c4\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2",
|
||||
"invalid_input": "\u039c\u03b7 \u03ad\u03b3\u03ba\u03c5\u03c1\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 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 IP"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "\u0394\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 IP",
|
||||
"password": "\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2"
|
||||
},
|
||||
"description": "\u0394\u03ce\u03c3\u03c4\u03b5 \u03c4\u03b7 \u03b4\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 IP \u03ae \u03c4\u03bf mDNS \u03c4\u03b7\u03c2 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae\u03c2 \u03ba\u03b1\u03b9 \u03c4\u03bf\u03bd \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03ae\u03c2 \u03c4\u03b7\u03c2",
|
||||
"title": "\u03a0\u03c1\u03bf\u03c3\u03b4\u03b9\u03bf\u03c1\u03af\u03c3\u03c4\u03b5 \u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/en.json
Normal file
22
homeassistant/components/airq/translations/en.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Device is already configured"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Failed to connect",
|
||||
"invalid_auth": "Invalid authentication",
|
||||
"invalid_input": "Invalid hostname or IP address"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP Address",
|
||||
"password": "Password"
|
||||
},
|
||||
"description": "Provide the IP address or mDNS of the device and its password",
|
||||
"title": "Identify the device"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/es.json
Normal file
22
homeassistant/components/airq/translations/es.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "El dispositivo ya est\u00e1 configurado"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "No se pudo conectar",
|
||||
"invalid_auth": "Autenticaci\u00f3n no v\u00e1lida",
|
||||
"invalid_input": "Nombre de host o direcci\u00f3n IP no v\u00e1lidos"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "Direcci\u00f3n IP",
|
||||
"password": "Contrase\u00f1a"
|
||||
},
|
||||
"description": "Proporciona la direcci\u00f3n IP o mDNS del dispositivo y su contrase\u00f1a",
|
||||
"title": "Identificar el dispositivo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/et.json
Normal file
22
homeassistant/components/airq/translations/et.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Seade on juba h\u00e4\u00e4lestatud"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "\u00dchendamine nurjus",
|
||||
"invalid_auth": "Tuvastamine nurjus",
|
||||
"invalid_input": "Hostinimi v\u00f5i IP aadress vigane"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP aadress",
|
||||
"password": "Salas\u00f5na"
|
||||
},
|
||||
"description": "Sisesta seadme IP-aadress v\u00f5i mDNS ja parool",
|
||||
"title": "Seadme tuvastamine"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
homeassistant/components/airq/translations/fr.json
Normal file
20
homeassistant/components/airq/translations/fr.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "\u00c9chec de connexion",
|
||||
"invalid_auth": "Authentification non valide",
|
||||
"invalid_input": "Nom d'h\u00f4te ou adresse IP non valide"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "Adresse IP",
|
||||
"password": "Mot de passe"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/hr.json
Normal file
22
homeassistant/components/airq/translations/hr.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Ure\u0111aj je ve\u0107 konfiguriran"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Povezivanje nije uspjelo",
|
||||
"invalid_auth": "Neva\u017ee\u0107a provjera autenti\u010dnosti",
|
||||
"invalid_input": "Neva\u017ee\u0107i naziv hosta ili IP adresa"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP adresa",
|
||||
"password": "Lozinka"
|
||||
},
|
||||
"description": "Navedite IP adresu ili mDNS ure\u0111aja i njegovu lozinku",
|
||||
"title": "Identificirajte ure\u0111aj"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/hu.json
Normal file
22
homeassistant/components/airq/translations/hu.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Sikertelen csatlakoz\u00e1s",
|
||||
"invalid_auth": "\u00c9rv\u00e9nytelen hiteles\u00edt\u00e9s",
|
||||
"invalid_input": "\u00c9rv\u00e9nytelen hosztn\u00e9v vagy IP-c\u00edm"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP c\u00edm",
|
||||
"password": "Jelsz\u00f3"
|
||||
},
|
||||
"description": "Adja meg az eszk\u00f6z IP-c\u00edm\u00e9t vagy mDNS c\u00edm\u00e9t \u00e9s jelszav\u00e1t.",
|
||||
"title": "Az eszk\u00f6z azonos\u00edt\u00e1sa"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/id.json
Normal file
22
homeassistant/components/airq/translations/id.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Perangkat sudah dikonfigurasi"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Gagal terhubung",
|
||||
"invalid_auth": "Autentikasi tidak valid",
|
||||
"invalid_input": "Nama host atau alamat IP tidak valid"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "Alamat IP",
|
||||
"password": "Kata Sandi"
|
||||
},
|
||||
"description": "Berikan alamat IP atau mDNS perangkat dan kata sandinya",
|
||||
"title": "Identifikasi perangkat"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/it.json
Normal file
22
homeassistant/components/airq/translations/it.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Impossibile connettersi",
|
||||
"invalid_auth": "Autenticazione non valida",
|
||||
"invalid_input": "Nome host o indirizzo IP non valido"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "Indirizzo IP",
|
||||
"password": "Password"
|
||||
},
|
||||
"description": "Fornire l'indirizzo IP o mDNS del dispositivo e la relativa password",
|
||||
"title": "Identifica il dispositivo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
homeassistant/components/airq/translations/ja.json
Normal file
20
homeassistant/components/airq/translations/ja.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "\u30c7\u30d0\u30a4\u30b9\u306f\u3059\u3067\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "\u63a5\u7d9a\u306b\u5931\u6557\u3057\u307e\u3057\u305f",
|
||||
"invalid_auth": "\u7121\u52b9\u306a\u8a8d\u8a3c",
|
||||
"invalid_input": "\u7121\u52b9\u306a\u30db\u30b9\u30c8\u540d\u307e\u305f\u306fIP\u30a2\u30c9\u30ec\u30b9"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP\u30a2\u30c9\u30ec\u30b9",
|
||||
"password": "\u30d1\u30b9\u30ef\u30fc\u30c9"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/nl.json
Normal file
22
homeassistant/components/airq/translations/nl.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Apparaat is al geconfigureerd"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Verbinding mislukt",
|
||||
"invalid_auth": "Ongeldige authenticatie poging",
|
||||
"invalid_input": "Ongeldige hostnaam of IP adres"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP adres",
|
||||
"password": "Wachtwoord"
|
||||
},
|
||||
"description": "Geef het IP adress of mDNS van het apparaat en het bijbehorend wachtwoord",
|
||||
"title": "Identificeer het apparaat"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/no.json
Normal file
22
homeassistant/components/airq/translations/no.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Enheten er allerede konfigurert"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Tilkobling mislyktes",
|
||||
"invalid_auth": "Ugyldig godkjenning",
|
||||
"invalid_input": "Ugyldig vertsnavn eller IP-adresse"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP adresse",
|
||||
"password": "Passord"
|
||||
},
|
||||
"description": "Oppgi IP-adressen eller mDNS til enheten og passordet",
|
||||
"title": "Identifiser enheten"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/pl.json
Normal file
22
homeassistant/components/airq/translations/pl.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia",
|
||||
"invalid_auth": "Niepoprawne uwierzytelnienie",
|
||||
"invalid_input": "Nieprawid\u0142owa nazwa hosta lub adres IP"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "Adres IP",
|
||||
"password": "Has\u0142o"
|
||||
},
|
||||
"description": "Podaj adres IP lub mDNS urz\u0105dzenia i jego has\u0142o",
|
||||
"title": "Zidentyfikuj urz\u0105dzenie"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/pt-BR.json
Normal file
22
homeassistant/components/airq/translations/pt-BR.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Dispositivo j\u00e1 est\u00e1 configurado"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Falha ao conectar",
|
||||
"invalid_auth": "Autentica\u00e7\u00e3o inv\u00e1lida",
|
||||
"invalid_input": "Nome de host ou endere\u00e7o IP inv\u00e1lido"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "Endere\u00e7o IP",
|
||||
"password": "Senha"
|
||||
},
|
||||
"description": "Forne\u00e7a o endere\u00e7o IP ou mDNS do dispositivo e sua senha",
|
||||
"title": "Identifique o dispositivo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/ru.json
Normal file
22
homeassistant/components/airq/translations/ru.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"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_auth": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.",
|
||||
"invalid_input": "\u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u043c\u044f \u0445\u043e\u0441\u0442\u0430 \u0438\u043b\u0438 IP-\u0430\u0434\u0440\u0435\u0441."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP-\u0430\u0434\u0440\u0435\u0441",
|
||||
"password": "\u041f\u0430\u0440\u043e\u043b\u044c"
|
||||
},
|
||||
"description": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 IP-\u0430\u0434\u0440\u0435\u0441 \u0438\u043b\u0438 mDNS \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u0435\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044c.",
|
||||
"title": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/sk.json
Normal file
22
homeassistant/components/airq/translations/sk.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Zariadenie u\u017e je nakonfigurovan\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165",
|
||||
"invalid_auth": "Neplatn\u00e9 overenie",
|
||||
"invalid_input": "Neplatn\u00fd n\u00e1zov hostite\u013ea alebo IP adresa"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP adresa",
|
||||
"password": "Heslo"
|
||||
},
|
||||
"description": "Zadajte IP adresu alebo mDNS zariadenia a jeho heslo",
|
||||
"title": "Identifikujte zariadenie"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
homeassistant/components/airq/translations/zh-Hant.json
Normal file
22
homeassistant/components/airq/translations/zh-Hant.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "\u88dd\u7f6e\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "\u9023\u7dda\u5931\u6557",
|
||||
"invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548",
|
||||
"invalid_input": "\u7121\u6548\u4e3b\u6a5f\u540d\u7a31\u6216 IP \u4f4d\u5740"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"ip_address": "IP \u4f4d\u5740",
|
||||
"password": "\u5bc6\u78bc"
|
||||
},
|
||||
"description": "\u63d0\u4f9b\u88dd\u7f6e\u4e4b IP \u4f4d\u5740\u6216 mDNS \u53ca\u5bc6\u78bc",
|
||||
"title": "\u8b58\u5225\u88dd\u7f6e"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,21 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "\u00da\u010det je u\u017e nakonfigurovan\u00fd"
|
||||
},
|
||||
"error": {
|
||||
"invalid_auth": "Neplatn\u00e9 overenie"
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165",
|
||||
"invalid_auth": "Neplatn\u00e9 overenie",
|
||||
"unknown": "Neo\u010dak\u00e1van\u00e1 chyba"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"description": "Ak chcete n\u00e1js\u0165 svoje poverenia, prihl\u00e1ste sa na adrese {url}",
|
||||
"id": "ID",
|
||||
"secret": "Tajn\u00e9"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
"already_configured": "\u05ea\u05e6\u05d5\u05e8\u05ea \u05d4\u05d4\u05ea\u05e7\u05df \u05db\u05d1\u05e8 \u05e0\u05e7\u05d1\u05e2\u05d4",
|
||||
"already_in_progress": "\u05d6\u05e8\u05d9\u05de\u05ea \u05d4\u05ea\u05e6\u05d5\u05e8\u05d4 \u05db\u05d1\u05e8 \u05de\u05ea\u05d1\u05e6\u05e2\u05ea",
|
||||
"cannot_connect": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05e0\u05db\u05e9\u05dc\u05d4",
|
||||
"no_devices_found": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05db\u05e9\u05d9\u05e8\u05d9\u05dd \u05d1\u05e8\u05e9\u05ea",
|
||||
"no_devices_found": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05d4\u05ea\u05e7\u05e0\u05d9\u05dd \u05d1\u05e8\u05e9\u05ea",
|
||||
"unknown": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05d1\u05dc\u05ea\u05d9 \u05e6\u05e4\u05d5\u05d9\u05d4"
|
||||
},
|
||||
"flow_title": "{name}",
|
||||
|
18
homeassistant/components/airthings_ble/translations/hy.json
Normal file
18
homeassistant/components/airthings_ble/translations/hy.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"cannot_connect": "\u0549\u0570\u0561\u057b\u0578\u0572\u057e\u0565\u0581 \u0574\u056b\u0561\u0576\u0561\u056c",
|
||||
"no_devices_found": "\u0551\u0561\u0576\u0581\u0578\u0582\u0574 \u057d\u0561\u0580\u0584\u0565\u0580 \u0579\u0565\u0576 \u0563\u057f\u0576\u057e\u0565\u056c",
|
||||
"unknown": "\u0531\u0576\u057d\u057a\u0561\u057d\u0565\u056c\u056b \u057d\u056d\u0561\u056c"
|
||||
},
|
||||
"flow_title": "{name}",
|
||||
"step": {
|
||||
"bluetooth_confirm": {
|
||||
"description": "\u0551\u0561\u0576\u056f\u0561\u0576\u0578\u0582\u055e\u0574 \u0565\u0584 \u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0565\u056c {name}-\u0568:"
|
||||
},
|
||||
"user": {
|
||||
"description": "\u0538\u0576\u057f\u0580\u0565\u0584 \u057d\u0561\u0580\u0584\u0568 \u056f\u0561\u0580\u0563\u0561\u057e\u0578\u0580\u0565\u056c\u0578\u0582 \u0570\u0561\u0574\u0561\u0580"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,18 +5,18 @@
|
||||
"already_in_progress": "Nederlands",
|
||||
"cannot_connect": "Nederlands",
|
||||
"no_devices_found": "Nederlands",
|
||||
"unknown": "Nederlands"
|
||||
"unknown": "Onverwachte fout"
|
||||
},
|
||||
"flow_title": "Nederlands",
|
||||
"step": {
|
||||
"bluetooth_confirm": {
|
||||
"description": "Nederlands"
|
||||
"description": "Wilt u {name} instellen?"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"address": "Nederlands"
|
||||
"address": "Apparaat"
|
||||
},
|
||||
"description": "Nederlands"
|
||||
"description": "Kies een apparaat om in te stellen"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
23
homeassistant/components/airthings_ble/translations/sk.json
Normal file
23
homeassistant/components/airthings_ble/translations/sk.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Zariadenie u\u017e je nakonfigurovan\u00e9",
|
||||
"already_in_progress": "Konfigur\u00e1cia u\u017e prebieha",
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165",
|
||||
"no_devices_found": "V sieti sa nena\u0161li \u017eiadne zariadenia",
|
||||
"unknown": "Neo\u010dak\u00e1van\u00e1 chyba"
|
||||
},
|
||||
"flow_title": "{name}",
|
||||
"step": {
|
||||
"bluetooth_confirm": {
|
||||
"description": "Chcete nastavi\u0165 {name}?"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"address": "Zaradenie"
|
||||
},
|
||||
"description": "Vyberte zariadenie, ktor\u00e9 chcete nastavi\u0165"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
homeassistant/components/airtouch4/translations/sk.json
Normal file
19
homeassistant/components/airtouch4/translations/sk.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Zariadenie u\u017e je nakonfigurovan\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165",
|
||||
"no_units": "Nepodarilo sa n\u00e1js\u0165 \u017eiadne skupiny AirTouch 4."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "Hostite\u013e"
|
||||
},
|
||||
"title": "Nastavte podrobnosti pripojenia AirTouch 4."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ from pyairvisual.node import NodeProError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.config_entries import ConfigEntry, OptionsFlow
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_IP_ADDRESS,
|
||||
@ -30,6 +30,10 @@ from homeassistant.const import (
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||
from homeassistant.helpers.schema_config_entry_flow import (
|
||||
SchemaFlowFormStep,
|
||||
SchemaOptionsFlowHandler,
|
||||
)
|
||||
|
||||
from . import async_get_geography_id
|
||||
from .const import (
|
||||
@ -66,6 +70,13 @@ PICK_INTEGRATION_TYPE_SCHEMA = vol.Schema(
|
||||
}
|
||||
)
|
||||
|
||||
OPTIONS_SCHEMA = vol.Schema(
|
||||
{vol.Required(CONF_SHOW_ON_MAP): bool},
|
||||
)
|
||||
OPTIONS_FLOW = {
|
||||
"init": SchemaFlowFormStep(OPTIONS_SCHEMA),
|
||||
}
|
||||
|
||||
|
||||
class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle an AirVisual config flow."""
|
||||
@ -165,9 +176,9 @@ class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow:
|
||||
def async_get_options_flow(config_entry: ConfigEntry) -> SchemaOptionsFlowHandler:
|
||||
"""Define the config flow to handle options."""
|
||||
return AirVisualOptionsFlowHandler(config_entry)
|
||||
return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW)
|
||||
|
||||
async def async_step_geography_by_coords(
|
||||
self, user_input: dict[str, str] | None = None
|
||||
@ -258,30 +269,3 @@ class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
if user_input["type"] == INTEGRATION_TYPE_GEOGRAPHY_NAME:
|
||||
return await self.async_step_geography_by_name()
|
||||
return await self.async_step_node_pro()
|
||||
|
||||
|
||||
class AirVisualOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Handle an AirVisual options flow."""
|
||||
|
||||
def __init__(self, entry: ConfigEntry) -> None:
|
||||
"""Initialize."""
|
||||
self.entry = entry
|
||||
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, str] | None = None
|
||||
) -> FlowResult:
|
||||
"""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.Required(
|
||||
CONF_SHOW_ON_MAP,
|
||||
default=self.entry.options.get(CONF_SHOW_ON_MAP),
|
||||
): bool
|
||||
}
|
||||
),
|
||||
)
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"reauth_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0442\u043e \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044f\u0432\u0430\u043d\u0435 \u0431\u0435\u0448\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e"
|
||||
"reauth_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u0442\u0430 \u0430\u0432\u0442\u0435\u043d\u0442\u0438\u043a\u0430\u0446\u0438\u044f \u0431\u0435\u0448\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u0430"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "\u041d\u0435\u0443\u0441\u043f\u0435\u0445 \u043f\u0440\u0438 \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435",
|
||||
|
@ -1,7 +1,20 @@
|
||||
{
|
||||
"state": {
|
||||
"airvisual__pollutant_label": {
|
||||
"co": "Oxid uho\u013enat\u00fd",
|
||||
"n2": "Oxid dusi\u010dit\u00fd",
|
||||
"o3": "Oz\u00f3n",
|
||||
"p1": "PM10",
|
||||
"p2": "PM2,5",
|
||||
"s2": "Oxid siri\u010dit\u00fd"
|
||||
},
|
||||
"airvisual__pollutant_level": {
|
||||
"good": "Dobr\u00e9"
|
||||
"good": "Dobr\u00e9",
|
||||
"hazardous": "Nebezpe\u010dn\u00e9",
|
||||
"moderate": "Mierne",
|
||||
"unhealthy": "Nezdrav\u00e9",
|
||||
"unhealthy_sensitive": "Nezdrav\u00e9 pre citliv\u00e9 skupiny",
|
||||
"very_unhealthy": "Ve\u013emi nezdrav\u00e9"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,14 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Umiestnenie u\u017e je nakonfigurovan\u00e9 alebo ID uzla/Pro je u\u017e zaregistrovan\u00e9.",
|
||||
"reauth_successful": "Op\u00e4tovn\u00e9 overenie bolo \u00faspe\u0161n\u00e9"
|
||||
},
|
||||
"error": {
|
||||
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d"
|
||||
"cannot_connect": "Nepodarilo sa pripoji\u0165",
|
||||
"general_error": "Neo\u010dak\u00e1van\u00e1 chyba",
|
||||
"invalid_api_key": "Neplatn\u00fd API k\u013e\u00fa\u010d",
|
||||
"location_not_found": "Poloha sa nena\u0161la"
|
||||
},
|
||||
"step": {
|
||||
"geography_by_coords": {
|
||||
@ -12,17 +16,42 @@
|
||||
"api_key": "API k\u013e\u00fa\u010d",
|
||||
"latitude": "Zemepisn\u00e1 \u0161\u00edrka",
|
||||
"longitude": "Zemepisn\u00e1 d\u013a\u017eka"
|
||||
}
|
||||
},
|
||||
"title": "Konfigur\u00e1cia geografie"
|
||||
},
|
||||
"geography_by_name": {
|
||||
"data": {
|
||||
"api_key": "API k\u013e\u00fa\u010d"
|
||||
"api_key": "API k\u013e\u00fa\u010d",
|
||||
"city": "Mesto",
|
||||
"country": "Krajina",
|
||||
"state": "stav"
|
||||
},
|
||||
"title": "Konfigur\u00e1cia geografie"
|
||||
},
|
||||
"node_pro": {
|
||||
"data": {
|
||||
"ip_address": "Hostite\u013e",
|
||||
"password": "Heslo"
|
||||
}
|
||||
},
|
||||
"reauth_confirm": {
|
||||
"data": {
|
||||
"api_key": "API k\u013e\u00fa\u010d"
|
||||
}
|
||||
},
|
||||
"title": "Op\u00e4tovn\u00e9 overenie AirVisual"
|
||||
},
|
||||
"user": {
|
||||
"title": "Nakonfigurujte AirVisual"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"show_on_map": "Zobrazte na mape sledovan\u00fa geografiu"
|
||||
},
|
||||
"title": "Nakonfigurujte AirVisual"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""Config flow for Airzone."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from aioairzone.const import DEFAULT_PORT, DEFAULT_SYSTEM_ID
|
||||
@ -9,13 +10,16 @@ from aioairzone.localapi import AirzoneLocalApi, ConnectionOptions
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import dhcp
|
||||
from homeassistant.const import CONF_HOST, CONF_ID, CONF_PORT
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.data_entry_flow import AbortFlow, FlowResult
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_HOST): str,
|
||||
@ -29,9 +33,17 @@ SYSTEM_ID_SCHEMA = CONFIG_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def short_mac(addr: str) -> str:
|
||||
"""Convert MAC address to short address."""
|
||||
return addr.replace(":", "")[-4:].upper()
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle config flow for an Airzone device."""
|
||||
|
||||
_discovered_ip: str | None = None
|
||||
_discovered_mac: str | None = None
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
@ -60,7 +72,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
errors["base"] = "cannot_connect"
|
||||
else:
|
||||
if mac:
|
||||
await self.async_set_unique_id(format_mac(mac))
|
||||
await self.async_set_unique_id(
|
||||
format_mac(mac), raise_on_progress=False
|
||||
)
|
||||
self._abort_if_unique_id_configured(
|
||||
updates={
|
||||
CONF_HOST: user_input[CONF_HOST],
|
||||
@ -76,3 +90,78 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
data_schema=data_schema,
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_dhcp(self, discovery_info: dhcp.DhcpServiceInfo) -> FlowResult:
|
||||
"""Handle DHCP discovery."""
|
||||
self._discovered_ip = discovery_info.ip
|
||||
self._discovered_mac = discovery_info.macaddress
|
||||
|
||||
_LOGGER.debug(
|
||||
"DHCP discovery detected Airzone WebServer: %s", self._discovered_mac
|
||||
)
|
||||
|
||||
self._async_abort_entries_match({CONF_HOST: self._discovered_ip})
|
||||
|
||||
await self.async_set_unique_id(format_mac(self._discovered_mac))
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
options = ConnectionOptions(self._discovered_ip)
|
||||
airzone = AirzoneLocalApi(
|
||||
aiohttp_client.async_get_clientsession(self.hass), options
|
||||
)
|
||||
try:
|
||||
await airzone.get_version()
|
||||
except AirzoneError as err:
|
||||
raise AbortFlow("cannot_connect") from err
|
||||
|
||||
return await self.async_step_discovered_connection()
|
||||
|
||||
async def async_step_discovered_connection(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Confirm discovery."""
|
||||
assert self._discovered_ip is not None
|
||||
assert self._discovered_mac is not None
|
||||
|
||||
errors = {}
|
||||
base_schema = {vol.Required(CONF_PORT, default=DEFAULT_PORT): int}
|
||||
|
||||
if user_input is not None:
|
||||
airzone = AirzoneLocalApi(
|
||||
aiohttp_client.async_get_clientsession(self.hass),
|
||||
ConnectionOptions(
|
||||
self._discovered_ip,
|
||||
user_input[CONF_PORT],
|
||||
user_input.get(CONF_ID, DEFAULT_SYSTEM_ID),
|
||||
),
|
||||
)
|
||||
|
||||
try:
|
||||
mac = await airzone.validate()
|
||||
except InvalidSystem:
|
||||
base_schema[vol.Required(CONF_ID, default=1)] = int
|
||||
errors[CONF_ID] = "invalid_system_id"
|
||||
except AirzoneError:
|
||||
errors["base"] = "cannot_connect"
|
||||
else:
|
||||
user_input[CONF_HOST] = self._discovered_ip
|
||||
|
||||
if mac is None:
|
||||
mac = self._discovered_mac
|
||||
|
||||
await self.async_set_unique_id(format_mac(mac))
|
||||
self._abort_if_unique_id_configured(
|
||||
updates={
|
||||
CONF_HOST: user_input[CONF_HOST],
|
||||
CONF_PORT: user_input[CONF_PORT],
|
||||
}
|
||||
)
|
||||
|
||||
title = f"Airzone {short_mac(mac)}"
|
||||
return self.async_create_entry(title=title, data=user_input)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="discovered_connection",
|
||||
data_schema=vol.Schema(base_schema),
|
||||
errors=errors,
|
||||
)
|
||||
|
@ -3,8 +3,13 @@
|
||||
"name": "Airzone",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/airzone",
|
||||
"requirements": ["aioairzone==0.4.8"],
|
||||
"requirements": ["aioairzone==0.5.1"],
|
||||
"codeowners": ["@Noltari"],
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairzone"]
|
||||
"loggers": ["aioairzone"],
|
||||
"dhcp": [
|
||||
{
|
||||
"macaddress": "E84F25*"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user