Compare commits

...

176 Commits

Author SHA1 Message Date
Penny Wood
5c8c3917c3 Extra line breaks to make the if/elif more distinct 2023-03-16 07:29:19 +08:00
Erik
336c17112b Improve threshold sensor 2023-03-01 17:00:45 +01:00
epenet
ee78864b05 Adjust entity registry access in homekit tests (#88959) 2023-03-01 16:54:00 +01:00
Erik Montnemery
3818e318db Improve threshold binary sensor tests (#88972) 2023-03-01 16:53:42 +01:00
Erik Montnemery
12933353b2 Drop codeowner from threshold integration (#88973) 2023-03-01 16:46:19 +01:00
Emory Penney
137d2f0d73 Obihai config flow fixes (#88853)
* Commit split issue

* Clearer name

* Add yaml_failure test case

* Not sure why this is failing now

* Update homeassistant/components/obihai/strings.json

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* PR Feedback

* Update homeassistant/components/obihai/config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-03-01 16:33:32 +01:00
Maciej Bieniek
79bcdf43f7 Add current sensor for Shelly RPC devices (#88863) 2023-03-01 16:26:20 +01:00
epenet
b84eead3f8 Adjust entity registry access in helper tests (#88965) 2023-03-01 16:24:31 +01:00
epenet
d65dff3f9e Adjust entity registry access in tests (2) (#88960) 2023-03-01 16:23:36 +01:00
Erik Montnemery
09f1c2318d Disable gc in-between energy sensor tests (#88593) 2023-03-01 16:21:11 +01:00
mkmer
54de16875d Bump Aiosomecomfort to 0.0.11 (#88970) 2023-03-01 16:19:46 +01:00
Mitch
341d046ba7 Bump requests to 2.28.2 (#88956)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-03-01 16:17:55 +01:00
starkillerOG
eae12bd48d Motion Blinds DHCP restrict (#88919)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-03-01 16:16:04 +01:00
epenet
b94dffb7d3 Add missing mock in esphome tests (#88923) 2023-03-01 16:11:21 +01:00
epenet
9762b684c2 Adjust entity registry access in tests (3) (#88964) 2023-03-01 16:04:40 +01:00
epenet
23cdafd12f Use UnitOfVolumeFlowRate in huisbaasje and plugwise (#88967) 2023-03-01 15:26:39 +01:00
Thibaut
0c66346fb0 Add dynamic unit of measurement support for Overkiz sensor (#80490)
* Add dynamic unit support

* Import all units

* Fix typing

* Add fallback to CORE_ELECTRIC_POWER_CONSUMPTION_STATE_MEASURED_VALUE_TYPE

* Fix rebase

* Give priority to the more accurate attribute

* Don’t use hardcoded seconds unit

* Don’t change SensorDescription

* Rework comment
2023-03-01 13:46:26 +01:00
Frédéric Guardia
85f2693353 Fix Google Assistant temperature attribute (#85921) 2023-03-01 12:54:07 +01:00
RogerSelwyn
b75879194d Fix geniushub heating hvac action (#87531) 2023-03-01 12:34:41 +01:00
Aaron Godfrey
ab9bd5c29e Fix todoist filtering custom projects by labels (#87904)
* Fix filtering custom projects by labels.

* Don't lowercase the label.

* Labels are case-sensitive, don't lowercase them.
2023-03-01 12:01:54 +01:00
Mitch
42a69566ac Bump nuheat to 1.0.1 (#88958) 2023-03-01 11:39:14 +01:00
Erik Montnemery
fca5cc6ea3 Add number + sensor device class volume storage (#88312)
* Add number + sensor device class volume storage

* Fix typo

* Format code

* Update device automations
2023-03-01 11:22:57 +01:00
Erik Montnemery
29b049fc57 Don't create new venv if script/setup is run from within a venv (#88906) 2023-03-01 11:11:29 +01:00
epenet
6febe00516 Fix lingering task in entity_platform test (#88957)
* Fix lingering task in entity_platform test

* Speed up the test
2023-03-01 10:49:13 +01:00
epenet
ed3cdd8fb9 Fix lingering task in timeout test (#88953) 2023-03-01 09:42:55 +01:00
epenet
1fa3f32474 Add missing mock in notion tests (#88951) 2023-03-01 09:41:55 +01:00
epenet
853bd52a22 Adjust entity registry access in tests (1) (#88950) 2023-03-01 09:11:14 +01:00
J. Nick Koston
202bed5d51 Fix lingering reload task in notion reauth (#88949)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-03-01 09:07:46 +01:00
Erik Montnemery
9ab95b6348 Revert "Add state_class = MEASUREMENT to Derivative sensor (#88408)" (#88952) 2023-03-01 08:53:05 +01:00
epenet
42b74e7f56 Adjust entity registry access in integrations (3) (#88948) 2023-03-01 08:24:56 +01:00
epenet
f69d76702a Adjust entity registry access in integrations (2) (#88947) 2023-03-01 08:02:51 +01:00
epenet
b3d6f098d2 Adjust entity registry access in integrations (1) (#88946) 2023-03-01 08:02:34 +01:00
epenet
f2b736fad0 Adjust entity registry access in core platforms (#88944)
* Adjust entity registry access in platforms

* Adjust more core components
2023-03-01 08:02:16 +01:00
epenet
50f908ce2d Use load_json_object in fitbit (#88585)
* Use load_json_object in fitbit

* Remove unnecessary cast
2023-03-01 07:44:29 +01:00
epenet
95dd62186e Use json_loads_object in arwn (#88611) 2023-03-01 07:43:33 +01:00
Marius Stedjan
9fc6700c5a Add ZWaveDiscoverySchema for Merten 507801 (#88342)
* Add ZWaveDiscoverySchema for Merten 507801

* Add discovery tests to Merten 507801 z-wave device

* Add Z-Wave discovery schemas for Merten 507801 to disable endpoint 2 by default

* Add more discovery tests for Merten 507801 z-wave device
2023-03-01 00:47:47 -05:00
Chuck Deal
09d0128601 Add diagnostics to VeSync (#86350)
* Add diagnostics to VeSync

* Create unit tests for diagnostics and init

* Improved diagnostic test coverage

* Peer review fixes

* Fixed Peer Review comments

* Updated based on Peer Review

* Additional diagnostic redactions

* Removed account_id from diagnostic output
2023-02-28 22:12:48 -05:00
PatrickGlesner
5b49648846 Update Tado services.yaml defaults (#88929)
Update services.yaml

Deletes default values in 'time_period' and 'requested_overlay' fields in 'set_climate_timer'.
2023-02-28 22:02:52 -05:00
epenet
3e8716b37e Adjust AddEntitiesCallback import (part 2) (#88873) 2023-02-28 22:01:36 -05:00
epenet
c724e7c29f Adjust registry access in openai_conversation (#88882) 2023-02-28 21:59:44 -05:00
epenet
246f9784c8 Adjust registry access in Google Assistant (#88883) 2023-02-28 21:59:26 -05:00
epenet
ee781e4f49 Adjust registry access in scripts (#88884) 2023-02-28 21:58:47 -05:00
epenet
54f709f704 Adjust registry access in intent (#88881) 2023-02-28 21:58:19 -05:00
epenet
1bed5c7775 Adjust registry access in tests root (#88880) 2023-02-28 21:56:46 -05:00
epenet
0e4c32efe2 Adjust registry access in conversation (#88879) 2023-02-28 21:56:18 -05:00
epenet
6ab0b2751d Adjust issue_registry imports (#88878)
* Add issue_registry to RUFF extend aliases

* Adjust code accordingly

* Revert "Add issue_registry to RUFF extend aliases"

This reverts commit 4e73dd567be42c74d0db4a51bac8d7aa9d7c93e7.

* Revert changes to common.py
2023-02-28 21:55:44 -05:00
Volker Stolz
86acc4262e Introduce a UUID configuration option for API token (#88765)
* Introduce a UUID configuration option for API token. (#86547)

If the uuid is configured, it will be used in the HTTP headers. Otherwise,
we'll hash the salted instance URL which should be good enough(tm).

* Generate random 6-digit uuid on startup.
2023-02-28 21:52:45 -05:00
Erik Montnemery
39f5f0946e Store source entity in switch_as_x entity options (#88914) 2023-02-28 21:15:44 -05:00
J. Nick Koston
8f6cfc25c0 Use ulid-transform for constructing ulids (#88939)
* Use ulid-transform for constructing ulids

A future PR will use the new library to reduce the storage
overhead of ulids in the database

* tweak

* tweak

* bump
2023-02-28 21:09:47 -05:00
Michael Hansen
e0bdb3ecc3 Update intent sentences package (#88933)
* Actually use translated state names in response

* Change test result now that locks are excluded from HassTurnOn

* Bump home-assistant-intents and hassil versions
2023-02-28 21:07:18 -05:00
djtimca
c5e39f7039 Add state class to Aurora (#88938)
* Bump aurora_api version to fix issues with NOAA conversion values. Fix #82587

* update requirements for aurora.

* Add state_class to aurora sensor.

* Fixed environment to run requirements_all script.

* Revert "Add state_class to aurora sensor."

This reverts commit 213e21e8424aafd50242e77bcedc39f0a4b50074.

* Add state class to aurora sensor.

* Revert "Fixed environment to run requirements_all script."

This reverts commit f3f624226ee2d1853c4a6220dfa6456b4d86da5c.

* Revert "update requirements for aurora."

This reverts commit a3546ad88d33e127e84030764d0e3e40401a8865.

* Revert "Bump aurora_api version to fix issues with NOAA conversion values. Fix #82587"

This reverts commit faf3ba7b5b25aeedb5041f196de84e4fa55d4c89.

* Move state class to _attr_state_class.
2023-02-28 23:47:29 +01:00
djtimca
dccd3e277e Bump auroranoaa to 0.0.3 (#88927)
* Bump aurora_api version to fix issues with NOAA conversion values. Fix #82587

* update requirements for aurora.

* Add state_class to aurora sensor.

* Fixed environment to run requirements_all script.

* Revert "Add state_class to aurora sensor."

This reverts commit 213e21e8424aafd50242e77bcedc39f0a4b50074.
2023-02-28 23:33:05 +01:00
Tom Harris
47a3c27c9a Bump pyinsteon to 1.3.3 (#88925)
Bump pyinsteon
2023-02-28 15:34:07 -05:00
Erik Montnemery
ad55a5db11 Bump py-dormakaba-dkey to 1.0.3 (#88924)
* Bump py-dormakaba-dkey to 1.0.3

* Log unexpected errors in config flow
2023-02-28 15:33:50 -05:00
Erik Montnemery
69ce6980d6 Add number + sensor device class energy storage (#88310)
* Add number + sensor device class energy storage

* Format code

* Update device automations
2023-02-28 19:35:43 +01:00
b-uwe
c444e1c860 Add virtual integration for HELTUN (#88892) 2023-02-28 18:09:52 +01:00
Franck Nijhof
95ed6fbc08 Small improvements to middleware filter (#88921)
Small improvements middleware filter
2023-02-28 12:07:17 -05:00
Erik Montnemery
8321443193 Fix Dormakaba dKey binary sensor (#88922) 2023-02-28 12:07:01 -05:00
Erik Montnemery
7bfc7f134c Reset state of template cover on error (#88915) 2023-02-28 12:06:40 -05:00
epenet
ac6bbc2f1c Add missing mock in webostv config flow tests (#88913) 2023-02-28 12:04:40 -05:00
epenet
ee144d34a9 Adjust core test to avoid lingering task (#88918) 2023-02-28 12:03:36 -05:00
Marcel van der Veldt
36e6a879ad Bump aiohue library to version 4.6.2 (#88907)
* Bump aiohue library to 4.6.2

* Fix long press (fixed in aiohue lib)

* fix test
2023-02-28 11:53:15 -05:00
Erik Montnemery
c38df1102a Fix typo in thread (#88916) 2023-02-28 11:34:46 -05:00
Erik Montnemery
f93bd8ef2c Only allow channel 15 during configuration of OTBR (#88874)
* Only allow channel 15 during automatic configuration of OTBR

* Also force channel 15 when creating a new network
2023-02-28 11:08:45 -05:00
Marcel van der Veldt
e74613f8be Fix removal of non device-bound resources in Hue (#88897)
Fix removal of non device-bound resources (like entertainment areas)
2023-02-28 11:04:10 -05:00
Erik Montnemery
390daf1723 Sort unit lists sent to frontend (#88898) 2023-02-28 16:12:49 +01:00
Marcel van der Veldt
a2a23564a4 Do not create Area for Hue zones (#88904)
Do not create HA area for Hue zones
2023-02-28 09:50:00 -05:00
Bram Kragten
e3e4b44958 Fix string for OTBR config flow abort (#88902) 2023-02-28 15:02:40 +01:00
epenet
7b5c978b95 Add missing mock in overkiz config flow tests (#88899) 2023-02-28 08:59:48 -05:00
Felix Rotthowe
1c4aa26ab6 Add myself to codeowners of Livisi integration (#88900)
Add @planbnet to codeowners of Livisi integration
2023-02-28 14:48:13 +01:00
Erik Montnemery
f41bec6ba9 Create repairs issue if Thread network is insecure (#88888)
* Bump python-otbr-api to 1.0.5

* Create repairs issue if Thread network is insecure

* Address review comments
2023-02-28 13:50:56 +01:00
Felix Rotthowe
4d58c9de8d Add human readable name for Livisi climate devices (#88891)
* Add human readable climate device name

* Remove room name from entity name and set "has_entity_name"
2023-02-28 13:08:52 +01:00
Erik Montnemery
b6f66b3568 Add WS command weather/convertible_units (#85681) 2023-02-28 11:35:47 +01:00
Jan Bouwhuis
4e66554298 Also set hass.config_entries when mock_hass_config fixture is used (#88669)
* Set `hass.config_entries` with `mock_hass_config`

* Update tests/conftest.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-02-28 11:14:04 +01:00
rodriguestiago0
bef5fde832 Add stop charge button to renault integration (#88003)
* Added service to start/stop charge

* Remove comment

* Fixed service

* removed service for start/stop charge

* Remove version

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Format

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Revert change

* Fix lint

* Add tests

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-02-28 10:28:44 +01:00
Erik Montnemery
d397217b5b Add confirm step to thread zeroconf flow (#88869)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-02-28 10:23:36 +01:00
epenet
d2ea773e7f Adjust AddEntitiesCallback import (part 1) (#88870)
Adjust AddEntitiesCallback import
2023-02-28 08:54:05 +01:00
Diogo Gomes
07c25b3dd8 Prosegur late review comments (#88859)
* address late comments on #76428

* adress review

* extra tweaks
2023-02-28 08:16:22 +01:00
Matthias Alphart
7b3cab1bfe Update xknx to 2.6.0 (#88864) 2023-02-28 00:22:22 +01:00
Paul Bottein
c096ef3fce Update frontend to 20230227.0 (#88857) 2023-02-28 00:20:40 +01:00
Emory Penney
9fed4472f1 Adding Obihai codeowner (#88856)
Obihai: Adding codeowner
2023-02-27 22:29:51 +01:00
puddly
7a5a882687 Bump ZHA dependencies (#88799)
* Bump ZHA dependencies

* Use `importlib.metadata.version` to get package versions
2023-02-27 15:07:57 -05:00
Klaas Schoute
73c7ee4326 Bump odp-amsterdam to v5.1.0 (#88847) 2023-02-27 18:45:29 +01:00
Mick Vleeshouwer
79f96fe900 Support ValveHeatingTemperatureInterface in Overkiz integration (#88804)
* Add ValveHeatingTemperatureInterface support

* Update presets

* Bugfix

* Bugfixes

* Bugfix

* Update manifest

* Apply feedback

* Sort alphabetically

* Update homeassistant/components/overkiz/climate_entities/valve_heating_temperature_interface.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-02-27 17:25:02 +01:00
Mick Vleeshouwer
7cc8712a0c Change string to enum in SomfyThermostat (#88813) 2023-02-27 17:24:02 +01:00
Emory Penney
0e8d28dab0 Add Config Flow to Obihai (#88627)
* Obihai: Config Flow Only

* Remove reboot service

* Update .coveragerc

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* PR Feedback

* Use Issue Registry

* Add config_flow tests

* Another pass with pre-commit

* Resolve cyclical import and move sensorClasses to sensor

* Update homeassistant/components/obihai/config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/obihai/sensor.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/obihai/sensor.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update tests/components/obihai/test_config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Another round of feedback

* More PR feedback

* Offline testing, already_configured is required

* Update homeassistant/components/obihai/config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/obihai/config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/obihai/config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Cleanup

* Update homeassistant/components/obihai/__init__.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* PR feedback

* Backout today's changes: Fix mypy error

* Update tests/components/obihai/test_config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update tests/components/obihai/test_config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update tests/components/obihai/test_config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update tests/components/obihai/test_config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Don't plan ahead

* PR feedback

* Update homeassistant/components/obihai/config_flow.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Cleanup strings

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-02-27 17:22:15 +01:00
StefanIacobLivisi
fd87748b99 LIVISI climate device improvement (#88844)
Code review follow-up
2023-02-27 17:20:10 +01:00
Ernst Klamer
00954dfc1f Add gas sensor to BTHome (#88770)
* Bump bthome

* Add gas sensor
2023-02-27 10:40:08 -05:00
Paul Bottein
e95944bf9f Add filter options to entity and device selectors (#87536)
* Add support for multiple device classes

* Add support for entity filter selector

* Add support for device filter selector

* Apply suggestions

* Fix wrong property name

* Update snapshot

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-02-27 10:38:18 -05:00
avee87
ac70612ec5 Improve helper integration scaffold (#88713) 2023-02-27 16:25:27 +01:00
epenet
7419a92a1b Cleanup YAML import in aladdin_connect (#88694) 2023-02-27 16:20:01 +01:00
Erik Montnemery
ff4de8cd06 Add WS API for creating a Thread network (#88830)
* Add WS API for creating a Thread network

* Add tests
2023-02-27 10:19:13 -05:00
Bouwe Westerdijk
bdb9994b7e Correct Plugwise gas_consumed_interval sensor (#87449)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2023-02-27 16:17:57 +01:00
Paulus Schoutsen
2dcc2f88cc Use snapshots in blueprint import tests (#88843) 2023-02-27 09:57:26 -05:00
Erik Montnemery
db1dd16ab0 Add thread user flow (#88842) 2023-02-27 15:30:04 +01:00
Erik Montnemery
2c2489284b Catch CancelledError when setting up components (#88635)
* Catch CancelledError when setting up components

* Catch CancelledError when setting up components

* Also catch SystemExit
2023-02-27 09:29:14 -05:00
epenet
198ebaff6e Add missing mock in abode config flow tests (#88828) 2023-02-27 14:03:51 +01:00
epenet
5cc9e7fedd Add missing mock in cert_expiry config flow tests (#88835) 2023-02-27 14:01:53 +01:00
epenet
76819fbb23 Add missing mock in brunt config flow tests (#88834) 2023-02-27 14:01:09 +01:00
Erik Montnemery
aeb6c4f078 Tweak OTBR tests (#88839) 2023-02-27 13:59:16 +01:00
Jan Bouwhuis
b25f6e3ffc Prepare for refactoring of MQTT related tests (#88557)
* Update mqtt_mock

* Tests manual_mqtt

* Tests mqtt_json

* Tests mqtt_room
2023-02-27 13:54:56 +01:00
mkmer
b542f6b3ac Bump aiosomecomfort to 0.0.10 (#88766) 2023-02-27 13:48:23 +01:00
landaisbenj
a8d587bc53 Add state_class to qbittorent sensors (#88829)
Update Sensor.py on qbittorent integration

Add stat class fonctionnality to sensor speed.
2023-02-27 11:52:07 +01:00
Erik Montnemery
fe8f3602ff Fix sensor unit conversion bug (#88825)
* Fix sensor unit conversion bug

* Ensure the correct unit is stored in the entity registry
2023-02-27 11:46:55 +01:00
stickpin
735000475a Upgrade caldav to 1.2.0 (#88791) 2023-02-27 11:29:46 +01:00
Michael Davie
ae3e8746f7 Bump env_canada to 0.5.29 (#88821) 2023-02-27 11:19:29 +01:00
StefanIacobLivisi
10bf910f88 Add support for LIVISI climate devices (#86691)
* Add support for LIVISI climate devices

* Remove the reauthentication logic

* Add support for LIVISI climate devices

* Remove the reauthentication support

* Code review follow-up

* Update homeassistant/components/livisi/manifest.json

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/livisi/manifest.json

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Code review follow-up

* Code Review Follow-up

* Code Review Follow-up

* Code review follow-up

* Code review follow-up

* Code review follow-up

* Code review follow-up

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-02-27 10:38:52 +01:00
dependabot[bot]
b7846de311 Bump actions/setup-python from 4.3.0 to 4.5.0 (#88823)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.3.0 to 4.5.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4.3.0...v4.5.0)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-27 09:30:33 +01:00
dependabot[bot]
66b33e1090 Bump actions/checkout from 3.1.0 to 3.3.0 (#88824)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.3.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3.1.0...v3.3.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-27 08:41:23 +01:00
Mick Vleeshouwer
4fd7ca503f Bump pyoverkiz to 1.7.6 (#88808) 2023-02-27 08:09:45 +01:00
Mick Vleeshouwer
33466cdddd Add climate state translations to Overkiz integration (#88809)
Add climate translations
2023-02-27 07:45:53 +01:00
Paulus Schoutsen
0d25eef19c Use a background task for LIFX discovery (#88820) 2023-02-26 22:42:17 -05:00
J. Nick Koston
b5223e1196 Restore previous behavior of only waiting for new tasks at shutdown (#88740)
* Restore previous behavior of only waiting for new tasks at shutdown

* cleanup

* do a swap instead

* await canceled tasks

* await canceled tasks

* fix

* not needed since we no longer clear

* log it

* reword

* wait for airvisual

* tests
2023-02-26 22:36:18 -05:00
J. Nick Koston
1d1c553d9b Avoid starting a bluetooth poll when Home Assistant is stopping (#88819)
* Avoid starting a bluetooth poll when Home Assistant is stopping

* tests
2023-02-26 22:02:52 -05:00
J. Nick Koston
f8934175cb Prevent integrations from retrying setup once shutdown has started (#88818)
* Prevent integrations from retrying setup once shutdown has started

* coverage
2023-02-26 22:01:02 -05:00
J. Nick Koston
4898d22960 Fix flux_led discovery running at shutdown (#88817) 2023-02-26 21:14:54 -05:00
J. Nick Koston
480a495239 Fix unifiprotect discovery running at shutdown (#88802)
* Fix unifiprotect discovery running at shutdown

Move the discovery start into `async_setup` so we only
start discovery once reguardless of how many config entries
for unifiprotect they have (or how many times they reload).

Always make discovery a background task so it does not get
to block shutdown

* missing decorator
2023-02-26 21:08:20 -05:00
J. Nick Koston
d219e7c8b1 Bump yalexs-ble to 2.0.4 (#88798)
changelog: https://github.com/bdraco/yalexs-ble/compare/v2.0.3...v2.0.4
2023-02-26 21:06:27 -05:00
Diogo Gomes
c8fc2dc440 Add Camera platform to Prosegur (#76428)
* add camera to prosegur

* add tests

* address review

* better tests

* clean

* clean

* fix tests

* leftover from merge

* sorting missing

* Update homeassistant/components/prosegur/services.yaml

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

---------

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2023-02-26 20:25:55 -05:00
Paulus Schoutsen
9be3f86a4c Check circular dependencies (#88778) 2023-02-26 20:25:29 -05:00
J. Nick Koston
bea81d3f63 Fix lock services not removing entity fields (#88805) 2023-02-26 18:59:28 -05:00
starkillerOG
0f01866508 Do not block on reolink firmware check fail (#88797)
Do not block on firmware check fail
2023-02-26 21:49:24 +01:00
starkillerOG
588b51bdfa Simplify reolink update unique_id (#88794)
simplify unique_id
2023-02-26 21:45:14 +01:00
puddly
0fb41bdffe Unblock JSON CI by fixing improperly indented JSON in test fixture (#88803) 2023-02-26 14:41:16 -06:00
hahn-th
c9dfa15ed6 Add device HmIP-DLD (#83380)
* Add HmIP-DLD

* Remove commented code

* Fix errors

* Format using black

* Fix device count

* Add missing tests

* Apply changes by reviewer

* Change setup entry code

* Remove jammed state

* Add error messages

* Update homeassistant/components/homematicip_cloud/helpers.py

Co-authored-by: Aaron Bach <bachya1208@gmail.com>

* Add decorator

* Add error log output

* Update test_device.py

---------

Co-authored-by: Aaron Bach <bachya1208@gmail.com>
2023-02-26 10:49:25 -07:00
Joakim Plate
e00ff54869 Update nibe library to 2.0.0 (#88769) 2023-02-26 11:05:31 +01:00
shbatm
7c23de469e Add ISY994 services to set and delete lock codes (#88754) 2023-02-26 01:12:00 -06:00
Yuxin Wang
490a0908d4 Avoiding testing implementation details in apcupsd tests (#88772)
Fix apcupsd tests.
2023-02-26 07:57:31 +01:00
J. Nick Koston
327edabb64 Fix checking if a package is installed on py3.11 (#88768)
pkg_resources is abandoned and we need to move away
from using it https://github.com/pypa/pkg_resources

In the mean time we need to keep it working. This fixes
a new exception in py3.11 when a module is not installed
which allows proper fallback to pkg_resources.Requirement.parse
when needed

```
2023-02-25 15:46:21.101 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
  File "/opt/homebrew/lib/python3.11/site-packages/aiohttp/web_protocol.py", line 433, in _handle_request
    resp = await request_handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/aiohttp/web_app.py", line 504, in _handle
    resp = await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/aiohttp/web_middlewares.py", line 117, in impl
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/components/http/security_filter.py", line 60, in security_filter_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/components/http/forwarded.py", line 100, in forwarded_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/components/http/request_context.py", line 28, in request_context_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/components/http/ban.py", line 80, in ban_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/components/http/auth.py", line 235, in auth_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/components/http/view.py", line 146, in handle
    result = await result
             ^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/components/config/config_entries.py", line 148, in post
    return await super().post(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/components/http/data_validator.py", line 72, in wrapper
    result = await method(view, request, data, *args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/helpers/data_entry_flow.py", line 71, in post
    result = await self._flow_mgr.async_init(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/config_entries.py", line 826, in async_init
    flow, result = await task
                   ^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/config_entries.py", line 844, in _async_init
    flow = await self.async_create_flow(handler, context=context, data=data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/config_entries.py", line 950, in async_create_flow
    await async_process_deps_reqs(self.hass, self._hass_config, integration)
  File "/Users/bdraco/home-assistant/homeassistant/setup.py", line 384, in async_process_deps_reqs
    await requirements.async_get_integration_with_requirements(
  File "/Users/bdraco/home-assistant/homeassistant/requirements.py", line 52, in async_get_integration_with_requirements
    return await manager.async_get_integration_with_requirements(domain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/requirements.py", line 171, in async_get_integration_with_requirements
    await self._async_process_integration(integration, done)
  File "/Users/bdraco/home-assistant/homeassistant/requirements.py", line 186, in _async_process_integration
    await self.async_process_requirements(
  File "/Users/bdraco/home-assistant/homeassistant/requirements.py", line 252, in async_process_requirements
    await self._async_process_requirements(name, missing)
  File "/Users/bdraco/home-assistant/homeassistant/requirements.py", line 284, in _async_process_requirements
    installed, failures = await self.hass.async_add_executor_job(
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.11/3.11.1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/requirements.py", line 113, in _install_requirements_if_missing
    if pkg_util.is_installed(req) or _install_with_retry(req, kwargs):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/bdraco/home-assistant/homeassistant/util/package.py", line 40, in is_installed
    pkg_resources.get_distribution(package)
  File "/opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py", line 478, in get_distribution
    dist = get_provider(dist)
           ^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py", line 354, in get_provider
    return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
                                            ~~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range
``
2023-02-25 22:47:18 -05:00
Robert Svensson
b4a3a663cf Simplify adding unifi entities (#88571) 2023-02-25 08:18:49 -08:00
avee87
1519a78567 Fix log message in recorder on total_increasing reset (#88710) 2023-02-25 12:05:24 +01:00
J. Nick Koston
57360a7528 Prevent new discovery flows from being created when stopping (#88743) 2023-02-25 12:02:07 +01:00
J. Nick Koston
7b61d3763b Log futures that are blocking shutdown stages (#88736) 2023-02-25 12:01:30 +01:00
Joakim Sørensen
0f204d6502 Remove homeassistant_hardware after dependency from zha (#88751) 2023-02-25 12:01:01 +01:00
Arturo
0a3a8c4b3c Fix matter light color capabilities bit map (#88693)
* Adds matter light color capabilities bit map

* Fixed matter light hue and saturation test
2023-02-25 10:25:04 +01:00
Rami Mosleh
091305fc57 Use DataUpdateCoordinator for islamic_prayer_times (#73893)
* use DataUpdateCoordinator for islamic_prayer_times

Add suggested type hints

remove uneccassry options setup

* Use entity_description for sensors

* move coordinator into separate file, sensor_descptions to sensor.py

* add strict typing

* revert strict typing

* fix test coverage

* revert unrelated file changes

* fix sorting

* Update code based on review

* add missing type hint

* more missing type hints

* Update homeassistant/components/islamic_prayer_times/coordinator.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* remove config_entry parameter

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-02-25 10:05:51 +01:00
Austin Mroczek
3499d60401 Bump total_connect_client to v2023.2 (#88729)
* bump total_connect_client to v2023.2

* Trigger Build
2023-02-25 09:20:17 +01:00
Artem Draft
f18c0bf626 Pass assumed_state property in universal media player (#87846)
Pass assumed_state property in universal media player
2023-02-25 07:43:58 +01:00
J. Nick Koston
f52a5f6965 Make hass.async_stop an untracked task (#88738) 2023-02-24 23:11:48 -05:00
Álvaro Fernández Rojas
1edef73c9a Update aioqsw v0.3.2 (#88695)
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2023-02-24 22:10:00 -05:00
mkmer
5a365788b5 Add missing reauth strings to Honeywell (#88733)
Add missing reauth strings
2023-02-24 21:49:49 -05:00
Bram Kragten
a60fd18386 Update frontend to 20230224.0 (#88721) 2023-02-24 21:39:59 -05:00
J. Nick Koston
0223058d25 Reduce overhead to save json data to postgresql (#88717)
* Reduce overhead to strip nulls from json

* Reduce overhead to strip nulls from json

* small cleanup
2023-02-24 21:37:36 -05:00
J. Nick Koston
7b2e743a6b Fix timeout in purpleapi test (#88715)
https://github.com/home-assistant/core/actions/runs/4264644494/jobs/7423099757
2023-02-24 14:33:25 -05:00
J. Nick Koston
69a3738bdb Fix migration failing when existing data has duplicates (#88712) 2023-02-24 11:41:44 -06:00
Jon Caruana
e69091c6db Use strict typing for LiteJet integration (#88629)
* Strict typing for LiteJet.

* Add test for new check.

* PR feedback.

* PR feedback.
2023-02-24 17:51:48 +01:00
J. Nick Koston
ee7dfdae30 Bump aioesphomeapi to 13.4.1 (#88703)
changelog: https://github.com/esphome/aioesphomeapi/releases/tag/v13.4.1
2023-02-24 11:09:12 -05:00
epenet
fdc06c2fc2 Improve type hint in webostv trigger (#88599)
Improve type hint in webostv trigger
2023-02-24 16:54:02 +01:00
StefanIacobLivisi
ba929dfc79 Bump aiolivisi to 0.0.16 (#88700)
Increment aiolivisi library version
2023-02-24 15:22:30 +01:00
epenet
753c790a25 Use async_timeout in integrations (#88697) 2023-02-24 08:13:03 -05:00
Thomas Dietrich
ee8f746808 Change statistics component ownership (#88692) 2023-02-24 08:11:40 -05:00
stickpin
84823d2fcf Upgrade caldav to 1.1.3 (#88681)
* Update caldav to 1.1.3

* update caldav to 1.1.3

* update caldav to 1.1.3

---------

Co-authored-by: Allen Porter <allen@thebends.org>
2023-02-24 06:32:59 +00:00
J. Nick Koston
0ae2fdc08b Switch samsungtv to use async_timeout to avoid task creation (#88679)
wait_for creates a task, async_timeout does the same work
and avoids the task creation
2023-02-23 23:00:08 -05:00
Erik Montnemery
d90ee85118 Allow conditions to be implemented in platforms (#88509)
* Allow conditions to be implemented in platforms

* Update tests

* Tweak typing

* Rebase fixes
2023-02-23 22:30:51 -05:00
Franck Nijhof
2f826a6f86 Modernize uptime tests (#88636)
* Modernize uptime tests

* Fix tests
2023-02-23 22:15:20 -05:00
David Poll
af49b98475 Enable jinja loop controls (break/continue) (#88625)
Enables jinja loop controls (break/continue)
2023-02-23 22:14:28 -05:00
puddly
9575cd9161 Name the Yellow-internal radio and multi-PAN addon as ZHA serial ports (#88208)
* Expose the Yellow-internal radio and multi-PAN addon as named serial ports

* Remove the serial number if it isn't available

* Use consistent names for the addon and Zigbee radio

* Add `homeassistant_hardware` and `_yellow` as `after_dependencies`

* Handle `hassio` not existing when listing serial ports

* Add unit tests
2023-02-23 20:52:53 -05:00
J. Nick Koston
f0b029c363 Bump mopeka_iot_ble to 0.4.1 (#88680)
* Bump mopeka_iot_ble to 0.4.1

closes #88232

* adjust tests
2023-02-23 20:52:31 -05:00
Michael Hansen
a71487a42b Make a copy of matching states so translated state names can be used (#88683) 2023-02-23 20:50:23 -05:00
Michael Hansen
d5f1713498 Include binary_sensor in default Assist exposed domains (#88682) 2023-02-23 19:40:10 -05:00
Marcel van der Veldt
301144993c Fix support for Bridge(d) and composed devices in Matter (#88662)
* Refactor discovery of entities to support composed and bridged devices

* Bump library version to 3.1.0

* move discovery schemas to platforms

* optimize a tiny bit

* simplify even more

* fixed bug in light platform

* fix color control logic

* fix some issues

* Update homeassistant/components/matter/discovery.py

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* fix some tests

* fix light test

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-02-23 14:58:37 -05:00
Bram Kragten
e0601530a0 Update frontend to 20230223.0 (#88677) 2023-02-23 13:38:07 -05:00
Allen Porter
e1e0400b16 Fix local calendar issue with events created with fixed UTC offsets (#88650)
Fix issue with events created with UTC offsets
2023-02-23 13:37:15 -05:00
Raman Gupta
5739782877 Add support for firmware target in zwave_js FirmwareUploadView (#88523)
* Add support for firmware target in zwave_js FirmwareUploadView

fix

* Update tests/components/zwave_js/test_api.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update tests/components/zwave_js/test_api.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update tests/components/zwave_js/test_api.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update tests/components/zwave_js/test_api.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* fix types

* Switch back to using Any

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-02-23 13:24:55 -05:00
Franck Nijhof
6112793b19 Modernize Twentemilieu tests (#88640) 2023-02-23 10:26:17 -05:00
Franck Nijhof
f8314fe007 Update apprise to 1.3.0 (#88658) 2023-02-23 10:23:03 -05:00
epenet
dac3c7179f Add missing async_setup_entry mock in openuv (#88661) 2023-02-23 10:22:39 -05:00
Franck Nijhof
6511b3f355 Update pre-commit to 3.1.0 (#88657) 2023-02-23 10:59:47 +01:00
Artem Draft
6474297d1f Browse media support in universal media player (#85668)
Allow forward and override browse media in universal media player
2023-02-23 09:17:46 +01:00
J. Nick Koston
27ebee1501 Fix untrapped exceptions during Yale Access Bluetooth first setup (#88642) 2023-02-23 08:18:55 +01:00
starkillerOG
23b52025f9 Bump reolink-aio to 0.5.1 and check if update supported (#88641) 2023-02-23 08:13:03 +01:00
epenet
87dc692a20 Use json_loads_object in alexa (#88610) 2023-02-22 22:01:32 +01:00
Erik Montnemery
473db48943 Bump python-otbr-api to 1.0.4 (#88613)
* Bump python-otbr-api to 1.0.4

* Adjust tests
2023-02-22 15:31:02 -05:00
Franck Nijhof
aa3657e071 Bump version to 2023.4.0dev0 (#88630) 2023-02-22 21:29:49 +01:00
puddly
2a819f23c1 Disable the ZHA bellows UART thread when connecting to a TCP coordinator (#88202)
Disable the bellows UART thread when connecting to a TCP coordinator
2023-02-22 15:12:55 -05:00
Paulus Schoutsen
c6ff79aa0e Error checking for OTBR (#88620)
* Error checking for OTBR

* Other errors in flow too

* Tests
2023-02-22 20:58:11 +01:00
524 changed files with 10374 additions and 3741 deletions

View File

@@ -639,6 +639,10 @@ omit =
homeassistant/components/linode/*
homeassistant/components/linux_battery/sensor.py
homeassistant/components/lirc/*
homeassistant/components/livisi/__init__.py
homeassistant/components/livisi/climate.py
homeassistant/components/livisi/coordinator.py
homeassistant/components/livisi/switch.py
homeassistant/components/llamalab_automate/notify.py
homeassistant/components/logi_circle/__init__.py
homeassistant/components/logi_circle/camera.py
@@ -803,7 +807,9 @@ omit =
homeassistant/components/nuki/sensor.py
homeassistant/components/nx584/alarm_control_panel.py
homeassistant/components/oasa_telematics/sensor.py
homeassistant/components/obihai/*
homeassistant/components/obihai/__init__.py
homeassistant/components/obihai/connectivity.py
homeassistant/components/obihai/sensor.py
homeassistant/components/octoprint/__init__.py
homeassistant/components/oem/climate.py
homeassistant/components/ohmconnect/sensor.py
@@ -1363,7 +1369,6 @@ omit =
homeassistant/components/verisure/sensor.py
homeassistant/components/verisure/switch.py
homeassistant/components/versasense/*
homeassistant/components/vesync/__init__.py
homeassistant/components/vesync/common.py
homeassistant/components/vesync/fan.py
homeassistant/components/vesync/light.py

View File

@@ -31,7 +31,7 @@ env:
CACHE_VERSION: 5
PIP_CACHE_VERSION: 4
MYPY_CACHE_VERSION: 4
HA_SHORT_VERSION: 2023.3
HA_SHORT_VERSION: 2023.4
DEFAULT_PYTHON: "3.10"
ALL_PYTHON_VERSIONS: "['3.10', '3.11']"
# 10.3 is the oldest supported version
@@ -1073,10 +1073,10 @@ jobs:
ffmpeg \
postgresql-server-dev-14
- name: Check out code from GitHub
uses: actions/checkout@v3.1.0
uses: actions/checkout@v3.3.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true

View File

@@ -186,6 +186,7 @@ homeassistant.components.ld2410_ble.*
homeassistant.components.lidarr.*
homeassistant.components.lifx.*
homeassistant.components.light.*
homeassistant.components.litejet.*
homeassistant.components.litterrobot.*
homeassistant.components.local_ip.*
homeassistant.components.lock.*

View File

@@ -659,8 +659,8 @@ 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/livisi/ @StefanIacobLivisi @planbnet
/tests/components/livisi/ @StefanIacobLivisi @planbnet
/homeassistant/components/local_calendar/ @allenporter
/tests/components/local_calendar/ @allenporter
/homeassistant/components/local_ip/ @issacg
@@ -825,7 +825,8 @@ build.json @home-assistant/supervisor
/tests/components/nws/ @MatthewFlamm @kamiyo
/homeassistant/components/nzbget/ @chriscla
/tests/components/nzbget/ @chriscla
/homeassistant/components/obihai/ @dshokouhi
/homeassistant/components/obihai/ @dshokouhi @ejpenney
/tests/components/obihai/ @dshokouhi @ejpenney
/homeassistant/components/octoprint/ @rfleming71
/tests/components/octoprint/ @rfleming71
/homeassistant/components/ohmconnect/ @robbiet480
@@ -1138,8 +1139,8 @@ build.json @home-assistant/supervisor
/tests/components/starline/ @anonym-tsk
/homeassistant/components/starlink/ @boswelja
/tests/components/starlink/ @boswelja
/homeassistant/components/statistics/ @fabaff @ThomDietrich
/tests/components/statistics/ @fabaff @ThomDietrich
/homeassistant/components/statistics/ @ThomDietrich
/tests/components/statistics/ @ThomDietrich
/homeassistant/components/steam_online/ @tkdrob
/tests/components/steam_online/ @tkdrob
/homeassistant/components/steamist/ @bdraco
@@ -1212,8 +1213,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/thethingsnetwork/ @fabaff
/homeassistant/components/thread/ @home-assistant/core
/tests/components/thread/ @home-assistant/core
/homeassistant/components/threshold/ @fabaff
/tests/components/threshold/ @fabaff
/homeassistant/components/tibber/ @danielhiversen
/tests/components/tibber/ @danielhiversen
/homeassistant/components/tile/ @bachya

View File

@@ -6,15 +6,12 @@ from typing import TYPE_CHECKING
import attr
if TYPE_CHECKING:
from homeassistant.helpers import (
device_registry as dev_reg,
entity_registry as ent_reg,
)
from homeassistant.helpers import device_registry as dr, entity_registry as er
@attr.s(slots=True)
class PermissionLookup:
"""Class to hold data for permission lookups."""
entity_registry: ent_reg.EntityRegistry = attr.ib()
device_registry: dev_reg.DeviceRegistry = attr.ib()
entity_registry: er.EntityRegistry = attr.ib()
device_registry: dr.DeviceRegistry = attr.ib()

View File

@@ -0,0 +1,5 @@
{
"domain": "heltun",
"name": "HELTUN",
"iot_standards": ["zwave"]
}

View File

@@ -3,7 +3,6 @@ from __future__ import annotations
import asyncio
from collections.abc import Mapping
import logging
from typing import Any
from AIOAladdinConnect import AladdinConnectClient
@@ -20,8 +19,6 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import CLIENT_ID, DOMAIN
_LOGGER = logging.getLogger(__name__)
STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_USERNAME): str,
@@ -134,12 +131,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
)
async def async_step_import(
self, import_data: dict[str, Any] | None = None
) -> FlowResult:
"""Import Aladin Connect config from configuration.yaml."""
return await self.async_step_user(import_data)
class InvalidAuth(HomeAssistantError):
"""Error to indicate there is invalid auth."""

View File

@@ -2,63 +2,24 @@
from __future__ import annotations
from datetime import timedelta
import logging
from typing import Any, Final
from typing import Any
from AIOAladdinConnect import AladdinConnectClient
import voluptuous as vol
from homeassistant.components.cover import (
PLATFORM_SCHEMA as BASE_PLATFORM_SCHEMA,
CoverDeviceClass,
CoverEntity,
)
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import (
CONF_PASSWORD,
CONF_USERNAME,
STATE_CLOSED,
STATE_CLOSING,
STATE_OPENING,
)
from homeassistant.components.cover import CoverDeviceClass, CoverEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_CLOSED, STATE_CLOSING, STATE_OPENING
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import DOMAIN, STATES_MAP, SUPPORTED_FEATURES
from .model import DoorDevice
_LOGGER: Final = logging.getLogger(__name__)
PLATFORM_SCHEMA: Final = BASE_PLATFORM_SCHEMA.extend(
{vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string}
)
SCAN_INTERVAL = timedelta(seconds=300)
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up Aladdin Connect devices yaml depreciated."""
_LOGGER.warning(
"Configuring Aladdin Connect through yaml is deprecated. Please remove it from"
" your configuration as it has already been imported to a config entry"
)
await hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=config,
)
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,

View File

@@ -21,7 +21,7 @@ from homeassistant.const import (
SERVICE_ALARM_TRIGGER,
)
from homeassistant.core import Context, HomeAssistant
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -57,11 +57,11 @@ async def async_get_actions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device actions for Alarm control panel devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
actions = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -21,7 +21,11 @@ from homeassistant.const import (
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import condition, config_validation as cv, entity_registry
from homeassistant.helpers import (
condition,
config_validation as cv,
entity_registry as er,
)
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.entity import get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -64,11 +68,11 @@ async def async_get_conditions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device conditions for Alarm control panel devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
conditions = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -23,7 +23,7 @@ from homeassistant.const import (
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.entity import get_supported_features
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType
@@ -57,11 +57,11 @@ async def async_get_triggers(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device triggers for Alarm control panel devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
triggers: list[dict[str, str]] = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -5,6 +5,7 @@ import asyncio
from http import HTTPStatus
import json
import logging
from typing import cast
import aiohttp
import async_timeout
@@ -15,6 +16,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.event import async_track_state_change
from homeassistant.helpers.significant_change import create_checker
import homeassistant.util.dt as dt_util
from homeassistant.util.json import JsonObjectType, json_loads_object
from .const import API_CHANGE, DATE_FORMAT, DOMAIN, Cause
from .entities import ENTITY_ADAPTERS, AlexaEntity, generate_alexa_id
@@ -162,9 +164,10 @@ async def async_send_changereport_message(
if response.status == HTTPStatus.ACCEPTED:
return
response_json = json.loads(response_text)
response_json = json_loads_object(response_text)
response_payload = cast(JsonObjectType, response_json["payload"])
if response_json["payload"]["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION":
if response_payload["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION":
if invalidate_access_token:
# Invalidate the access token and try again
config.async_invalidate_access_token()
@@ -180,8 +183,8 @@ async def async_send_changereport_message(
_LOGGER.error(
"Error when sending ChangeReport for %s to Alexa: %s: %s",
alexa_entity.entity_id,
response_json["payload"]["code"],
response_json["payload"]["description"],
response_payload["code"],
response_payload["description"],
)
@@ -299,11 +302,12 @@ async def async_send_doorbell_event_message(hass, config, alexa_entity):
if response.status == HTTPStatus.ACCEPTED:
return
response_json = json.loads(response_text)
response_json = json_loads_object(response_text)
response_payload = cast(JsonObjectType, response_json["payload"])
_LOGGER.error(
"Error when sending DoorbellPress event for %s to Alexa: %s: %s",
alexa_entity.entity_id,
response_json["payload"]["code"],
response_json["payload"]["description"],
response_payload["code"],
response_payload["description"],
)

View File

@@ -20,13 +20,12 @@ from homeassistant.components.camera import (
from homeassistant.components.ffmpeg import FFmpegManager, get_ffmpeg_manager
from homeassistant.const import ATTR_ENTITY_ID, CONF_NAME, STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.aiohttp_client import (
async_aiohttp_proxy_stream,
async_aiohttp_proxy_web,
async_get_clientsession,
)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
@@ -146,7 +145,7 @@ async def async_setup_platform(
# with this version, update the old entity with the new unique id.
serial_number = await device.api.async_serial_number
serial_number = serial_number.strip()
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
entity_id = registry.async_get_entity_id(CAMERA_DOMAIN, DOMAIN, serial_number)
if entity_id is not None:
_LOGGER.debug("Updating unique id for camera %s", entity_id)

View File

@@ -5,5 +5,5 @@
"documentation": "https://www.home-assistant.io/integrations/apprise",
"iot_class": "cloud_push",
"loggers": ["apprise"],
"requirements": ["apprise==1.2.1"]
"requirements": ["apprise==1.3.0"]
}

View File

@@ -13,7 +13,7 @@ from homeassistant.const import (
CONF_TYPE,
)
from homeassistant.core import CALLBACK_TYPE, Event, HassJob, HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType
@@ -32,11 +32,11 @@ async def async_get_triggers(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device triggers for Arcam FMJ Receiver control devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
triggers = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain == "media_player":
triggers.append(
{

View File

@@ -1,7 +1,6 @@
"""Support for collecting data from the ARWN project."""
from __future__ import annotations
import json
import logging
from homeassistant.components import mqtt
@@ -11,6 +10,7 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import slugify
from homeassistant.util.json import json_loads_object
_LOGGER = logging.getLogger(__name__)
@@ -102,7 +102,7 @@ async def async_setup_platform(
"""Set up the ARWN platform."""
@callback
def async_sensor_event_received(msg):
def async_sensor_event_received(msg: mqtt.ReceiveMessage) -> None:
"""Process events as sensors.
When a new event on our topic (arwn/#) is received we map it
@@ -115,7 +115,7 @@ async def async_setup_platform(
This lets us dynamically incorporate sensors without any
configuration on our side.
"""
event = json.loads(msg.payload)
event = json_loads_object(msg.payload)
sensors = discover_sensors(msg.topic, event)
if not sensors:
return

View File

@@ -28,5 +28,5 @@
"documentation": "https://www.home-assistant.io/integrations/august",
"iot_class": "cloud_push",
"loggers": ["pubnub", "yalexs"],
"requirements": ["yalexs==1.2.7", "yalexs_ble==2.0.2"]
"requirements": ["yalexs==1.2.7", "yalexs_ble==2.0.4"]
}

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/aurora",
"iot_class": "cloud_polling",
"loggers": ["auroranoaa"],
"requirements": ["auroranoaa==0.0.2"]
"requirements": ["auroranoaa==0.0.3"]
}

View File

@@ -1,5 +1,5 @@
"""Support for Aurora Forecast sensor."""
from homeassistant.components.sensor import SensorEntity
from homeassistant.components.sensor import SensorEntity, SensorStateClass
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PERCENTAGE
from homeassistant.core import HomeAssistant
@@ -28,6 +28,7 @@ class AuroraSensor(AuroraEntity, SensorEntity):
"""Implementation of an aurora sensor."""
_attr_native_unit_of_measurement = PERCENTAGE
_attr_state_class = SensorStateClass.MEASUREMENT
@property
def native_value(self):

View File

@@ -2,7 +2,7 @@
from __future__ import annotations
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry
from homeassistant.helpers import issue_registry as ir
from . import DOMAIN
from .helpers import Observation
@@ -15,13 +15,13 @@ def raise_mirrored_entries(
if len(observations) != 2:
return
if observations[0].is_mirror(observations[1]):
issue_registry.async_create_issue(
ir.async_create_issue(
hass,
DOMAIN,
"mirrored_entry/" + text,
breaks_in_ha_version="2022.10.0",
is_fixable=False,
severity=issue_registry.IssueSeverity.WARNING,
severity=ir.IssueSeverity.WARNING,
translation_key="manual_migration",
translation_placeholders={"entity": text},
learn_more_url="https://github.com/home-assistant/core/pull/67631",
@@ -31,13 +31,13 @@ def raise_mirrored_entries(
# Should deprecate in some future version (2022.10 at time of writing) & make prob_given_false required in schemas.
def raise_no_prob_given_false(hass: HomeAssistant, text: str) -> None:
"""In previous 2022.9 and earlier, prob_given_false was optional and had a default version."""
issue_registry.async_create_issue(
ir.async_create_issue(
hass,
DOMAIN,
f"no_prob_given_false/{text}",
breaks_in_ha_version="2022.10.0",
is_fixable=False,
severity=issue_registry.IssueSeverity.ERROR,
severity=ir.IssueSeverity.ERROR,
translation_key="no_prob_given_false",
translation_placeholders={"entity": text},
learn_more_url="https://github.com/home-assistant/core/pull/67631",

View File

@@ -106,6 +106,8 @@ class ActiveBluetoothDataUpdateCoordinator(
def needs_poll(self, service_info: BluetoothServiceInfoBleak) -> bool:
"""Return true if time to try and poll."""
if self.hass.is_stopping:
return False
poll_age: float | None = None
if self._last_poll:
poll_age = monotonic_time_coarse() - self._last_poll

View File

@@ -99,6 +99,8 @@ class ActiveBluetoothProcessorCoordinator(
def needs_poll(self, service_info: BluetoothServiceInfoBleak) -> bool:
"""Return true if time to try and poll."""
if self.hass.is_stopping:
return False
poll_age: float | None = None
if self._last_poll:
poll_age = monotonic_time_coarse() - self._last_poll

View File

@@ -20,5 +20,5 @@
"dependencies": ["bluetooth_adapters"],
"documentation": "https://www.home-assistant.io/integrations/bthome",
"iot_class": "local_push",
"requirements": ["bthome-ble==2.5.2"]
"requirements": ["bthome-ble==2.7.0"]
}

View File

@@ -119,6 +119,16 @@ SENSOR_DESCRIPTIONS = {
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
# Gas (m3)
(
BTHomeSensorDeviceClass.GAS,
Units.VOLUME_CUBIC_METERS,
): SensorEntityDescription(
key=f"{BTHomeSensorDeviceClass.GAS}_{Units.VOLUME_CUBIC_METERS}",
device_class=SensorDeviceClass.GAS,
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
state_class=SensorStateClass.TOTAL_INCREASING,
),
# Humidity in (percent)
(BTHomeSensorDeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
key=f"{BTHomeSensorDeviceClass.HUMIDITY}_{Units.PERCENTAGE}",

View File

@@ -11,7 +11,7 @@ from homeassistant.const import (
CONF_TYPE,
)
from homeassistant.core import Context, HomeAssistant
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -31,7 +31,7 @@ async def async_get_actions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device actions for button devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
return [
{
CONF_DEVICE_ID: device_id,
@@ -39,7 +39,7 @@ async def async_get_actions(
CONF_ENTITY_ID: entry.entity_id,
CONF_TYPE: "press",
}
for entry in entity_registry.async_entries_for_device(registry, device_id)
for entry in er.async_entries_for_device(registry, device_id)
if entry.domain == DOMAIN
]

View File

@@ -16,7 +16,7 @@ from homeassistant.const import (
CONF_TYPE,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType
@@ -36,7 +36,7 @@ async def async_get_triggers(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device triggers for button devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
return [
{
CONF_PLATFORM: "device",
@@ -45,7 +45,7 @@ async def async_get_triggers(
CONF_ENTITY_ID: entry.entity_id,
CONF_TYPE: "pressed",
}
for entry in entity_registry.async_entries_for_device(registry, device_id)
for entry in er.async_entries_for_device(registry, device_id)
if entry.domain == DOMAIN
]

View File

@@ -5,5 +5,5 @@
"documentation": "https://www.home-assistant.io/integrations/caldav",
"iot_class": "cloud_polling",
"loggers": ["caldav", "vobject"],
"requirements": ["caldav==1.1.1"]
"requirements": ["caldav==1.2.0"]
}

View File

@@ -66,6 +66,55 @@ SCAN_INTERVAL = datetime.timedelta(seconds=60)
# Don't support rrules more often than daily
VALID_FREQS = {"DAILY", "WEEKLY", "MONTHLY", "YEARLY"}
def _has_consistent_timezone(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
"""Verify that all datetime values have a consistent timezone."""
def validate(obj: dict[str, Any]) -> dict[str, Any]:
"""Test that all keys that are datetime values have the same timezone."""
tzinfos = []
for key in keys:
if not (value := obj.get(key)) or not isinstance(value, datetime.datetime):
return obj
tzinfos.append(value.tzinfo)
uniq_values = groupby(tzinfos)
if len(list(uniq_values)) > 1:
raise vol.Invalid("Expected all values to have the same timezone")
return obj
return validate
def _as_local_timezone(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
"""Convert all datetime values to the local timezone."""
def validate(obj: dict[str, Any]) -> dict[str, Any]:
"""Test that all keys that are datetime values have the same timezone."""
for k in keys:
if (value := obj.get(k)) and isinstance(value, datetime.datetime):
obj[k] = dt.as_local(value)
return obj
return validate
def _is_sorted(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
"""Verify that the specified values are sequential."""
def validate(obj: dict[str, Any]) -> dict[str, Any]:
"""Test that all keys in the dict are in order."""
values = []
for k in keys:
if not (value := obj.get(k)):
return obj
values.append(value)
if all(values) and values != sorted(values):
raise vol.Invalid(f"Values were not in order: {values}")
return obj
return validate
CREATE_EVENT_SERVICE = "create_event"
CREATE_EVENT_SCHEMA = vol.All(
cv.has_at_least_one_key(EVENT_START_DATE, EVENT_START_DATETIME, EVENT_IN),
@@ -98,6 +147,10 @@ CREATE_EVENT_SCHEMA = vol.All(
),
},
),
_has_consistent_timezone(EVENT_START_DATETIME, EVENT_END_DATETIME),
_as_local_timezone(EVENT_START_DATETIME, EVENT_END_DATETIME),
_is_sorted(EVENT_START_DATE, EVENT_END_DATE),
_is_sorted(EVENT_START_DATETIME, EVENT_END_DATETIME),
)
@@ -441,36 +494,6 @@ def _has_same_type(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
return validate
def _has_consistent_timezone(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
"""Verify that all datetime values have a consistent timezone."""
def validate(obj: dict[str, Any]) -> dict[str, Any]:
"""Test that all keys that are datetime values have the same timezone."""
values = [obj[k] for k in keys]
if all(isinstance(value, datetime.datetime) for value in values):
uniq_values = groupby(value.tzinfo for value in values)
if len(list(uniq_values)) > 1:
raise vol.Invalid(
f"Expected all values to have the same timezone: {values}"
)
return obj
return validate
def _is_sorted(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
"""Verify that the specified values are sequential."""
def validate(obj: dict[str, Any]) -> dict[str, Any]:
"""Test that all keys in the dict are in order."""
values = [obj[k] for k in keys]
if values != sorted(values):
raise vol.Invalid(f"Values were not in order: {values}")
return obj
return validate
@websocket_api.websocket_command(
{
vol.Required("type"): "calendar/event/create",
@@ -486,6 +509,7 @@ def _is_sorted(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
},
_has_same_type(EVENT_START, EVENT_END),
_has_consistent_timezone(EVENT_START, EVENT_END),
_as_local_timezone(EVENT_START, EVENT_END),
_is_sorted(EVENT_START, EVENT_END),
)
),
@@ -582,6 +606,7 @@ async def handle_calendar_event_delete(
},
_has_same_type(EVENT_START, EVENT_END),
_has_consistent_timezone(EVENT_START, EVENT_END),
_as_local_timezone(EVENT_START, EVENT_END),
_is_sorted(EVENT_START, EVENT_END),
)
),

View File

@@ -12,7 +12,7 @@ from homeassistant.const import (
)
from homeassistant.core import Context, HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import get_capability, get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -44,11 +44,11 @@ async def async_get_actions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device actions for Climate devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
actions = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -13,7 +13,11 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import condition, config_validation as cv, entity_registry
from homeassistant.helpers import (
condition,
config_validation as cv,
entity_registry as er,
)
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.entity import get_capability, get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -45,11 +49,11 @@ async def async_get_conditions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device conditions for Climate devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
conditions = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -20,7 +20,7 @@ from homeassistant.const import (
PERCENTAGE,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType
@@ -62,11 +62,11 @@ async def async_get_triggers(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device triggers for Climate devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
triggers = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -10,8 +10,7 @@ from coinbase.wallet.error import AuthenticationError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_API_TOKEN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.util import Throttle
from .const import (
@@ -71,10 +70,8 @@ async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> Non
await hass.config_entries.async_reload(config_entry.entry_id)
registry = entity_registry.async_get(hass)
entities = entity_registry.async_entries_for_config_entry(
registry, config_entry.entry_id
)
registry = er.async_get(hass)
entities = er.async_entries_for_config_entry(registry, config_entry.entry_id)
# Remove orphaned entities
for entity in entities:

View File

@@ -8,7 +8,7 @@ from homeassistant.components.automation.config import (
)
from homeassistant.config import AUTOMATION_CONFIG_PATH
from homeassistant.const import CONF_ID, SERVICE_RELOAD
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from . import ACTION_DELETE, EditIdBasedConfigView
@@ -23,7 +23,7 @@ async def async_setup(hass):
if action != ACTION_DELETE:
return
ent_reg = entity_registry.async_get(hass)
ent_reg = er.async_get(hass)
entity_id = ent_reg.async_get_entity_id(DOMAIN, DOMAIN, config_key)

View File

@@ -5,7 +5,7 @@ from homeassistant.components.scene import DOMAIN, PLATFORM_SCHEMA
from homeassistant.config import SCENE_CONFIG_PATH
from homeassistant.const import CONF_ID, SERVICE_RELOAD
from homeassistant.core import DOMAIN as HA_DOMAIN
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from . import ACTION_DELETE, EditIdBasedConfigView
@@ -19,7 +19,7 @@ async def async_setup(hass):
await hass.services.async_call(DOMAIN, SERVICE_RELOAD)
return
ent_reg = entity_registry.async_get(hass)
ent_reg = er.async_get(hass)
entity_id = ent_reg.async_get_entity_id(DOMAIN, HA_DOMAIN, config_key)

View File

@@ -3,6 +3,7 @@
DOMAIN = "conversation"
DEFAULT_EXPOSED_DOMAINS = {
"binary_sensor",
"climate",
"cover",
"fan",
@@ -16,3 +17,5 @@ DEFAULT_EXPOSED_DOMAINS = {
"vacuum",
"water_heater",
}
DEFAULT_EXPOSED_ATTRIBUTES = {"device_class"}

View File

@@ -18,9 +18,9 @@ import yaml
from homeassistant import core, setup
from homeassistant.helpers import (
area_registry,
device_registry,
entity_registry,
area_registry as ar,
device_registry as dr,
entity_registry as er,
intent,
template,
translation,
@@ -28,7 +28,7 @@ from homeassistant.helpers import (
from homeassistant.util.json import JsonObjectType, json_loads_object
from .agent import AbstractConversationAgent, ConversationInput, ConversationResult
from .const import DEFAULT_EXPOSED_DOMAINS, DOMAIN
from .const import DEFAULT_EXPOSED_ATTRIBUTES, DEFAULT_EXPOSED_DOMAINS, DOMAIN
_LOGGER = logging.getLogger(__name__)
_DEFAULT_ERROR_TEXT = "Sorry, I couldn't understand that"
@@ -95,12 +95,12 @@ class DefaultAgent(AbstractConversationAgent):
self._config_intents = config_intents
self.hass.bus.async_listen(
area_registry.EVENT_AREA_REGISTRY_UPDATED,
ar.EVENT_AREA_REGISTRY_UPDATED,
self._async_handle_area_registry_changed,
run_immediately=True,
)
self.hass.bus.async_listen(
entity_registry.EVENT_ENTITY_REGISTRY_UPDATED,
er.EVENT_ENTITY_REGISTRY_UPDATED,
self._async_handle_entity_registry_changed,
run_immediately=True,
)
@@ -227,7 +227,21 @@ class DefaultAgent(AbstractConversationAgent):
intent_response: intent.IntentResponse,
recognize_result: RecognizeResult,
) -> str:
all_states = intent_response.matched_states + intent_response.unmatched_states
# Make copies of the states here so we can add translated names for responses.
matched: list[core.State] = []
for state in intent_response.matched_states:
state_copy = core.State.from_dict(state.as_dict())
if state_copy is not None:
matched.append(state_copy)
unmatched: list[core.State] = []
for state in intent_response.unmatched_states:
state_copy = core.State.from_dict(state.as_dict())
if state_copy is not None:
unmatched.append(state_copy)
all_states = matched + unmatched
domains = {state.domain for state in all_states}
translations = await translation.async_get_translations(
self.hass, language, "state", domains
@@ -243,9 +257,9 @@ class DefaultAgent(AbstractConversationAgent):
# This is available in the response template as "state".
state1: core.State | None = None
if intent_response.matched_states:
state1 = intent_response.matched_states[0]
state1 = matched[0]
elif intent_response.unmatched_states:
state1 = intent_response.unmatched_states[0]
state1 = unmatched[0]
# Render response template
speech = response_template.async_render(
@@ -262,13 +276,11 @@ class DefaultAgent(AbstractConversationAgent):
"query": {
# Entity states that matched the query (e.g, "on")
"matched": [
template.TemplateState(self.hass, state)
for state in intent_response.matched_states
template.TemplateState(self.hass, state) for state in matched
],
# Entity states that did not match the query
"unmatched": [
template.TemplateState(self.hass, state)
for state in intent_response.unmatched_states
template.TemplateState(self.hass, state) for state in unmatched
],
},
}
@@ -459,14 +471,20 @@ class DefaultAgent(AbstractConversationAgent):
states = [
state for state in self.hass.states.async_all() if is_entity_exposed(state)
]
entities = entity_registry.async_get(self.hass)
devices = device_registry.async_get(self.hass)
entities = er.async_get(self.hass)
devices = dr.async_get(self.hass)
# Gather exposed entity names
entity_names = []
for state in states:
# Checked against "requires_context" and "excludes_context" in hassil
context = {"domain": state.domain}
if state.attributes:
# Include some attributes
for attr_key, attr_value in state.attributes.items():
if attr_key not in DEFAULT_EXPOSED_ATTRIBUTES:
continue
context[attr_key] = attr_value
entity = entities.async_get(state.entity_id)
if entity is not None:
@@ -494,7 +512,7 @@ class DefaultAgent(AbstractConversationAgent):
entity_names.append((state.name, state.name, context))
# Gather areas from exposed entities
areas = area_registry.async_get(self.hass)
areas = ar.async_get(self.hass)
area_names = []
for area_id in area_ids_with_entities:
area = areas.async_get_area(area_id)
@@ -506,6 +524,9 @@ class DefaultAgent(AbstractConversationAgent):
for alias in area.aliases:
area_names.append((alias, area.id))
_LOGGER.debug("Exposed areas: %s", area_names)
_LOGGER.debug("Exposed entities: %s", entity_names)
self._slot_lists = {
"area": TextSlotList.from_tuples(area_names, allow_template=False),
"name": TextSlotList.from_tuples(entity_names, allow_template=False),

View File

@@ -7,5 +7,5 @@
"integration_type": "system",
"iot_class": "local_push",
"quality_scale": "internal",
"requirements": ["hassil==1.0.5", "home-assistant-intents==2023.2.22"]
"requirements": ["hassil==1.0.6", "home-assistant-intents==2023.2.28"]
}

View File

@@ -8,7 +8,11 @@ import coronavirus
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import aiohttp_client, entity_registry, update_coordinator
from homeassistant.helpers import (
aiohttp_client,
entity_registry as er,
update_coordinator,
)
from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN
@@ -31,16 +35,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)
@callback
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
def _async_migrator(entity_entry: er.RegistryEntry):
"""Migrate away from unstable ID."""
country, info_type = entity_entry.unique_id.rsplit("-", 1)
if not country.isnumeric():
return None
return {"new_unique_id": f"{entry.title}-{info_type}"}
await entity_registry.async_migrate_entries(
hass, entry.entry_id, _async_migrator
)
await er.async_migrate_entries(hass, entry.entry_id, _async_migrator)
if not entry.unique_id:
hass.config_entries.async_update_entry(entry, unique_id=entry.data["country"])

View File

@@ -18,7 +18,7 @@ from homeassistant.const import (
SERVICE_STOP_COVER,
)
from homeassistant.core import Context, HomeAssistant
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -63,11 +63,11 @@ async def async_get_actions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device actions for Cover devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
actions = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -18,7 +18,11 @@ from homeassistant.const import (
STATE_OPENING,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import condition, config_validation as cv, entity_registry
from homeassistant.helpers import (
condition,
config_validation as cv,
entity_registry as er,
)
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.entity import get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -66,11 +70,11 @@ async def async_get_conditions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device conditions for Cover devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
conditions: list[dict[str, str]] = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -24,7 +24,7 @@ from homeassistant.const import (
STATE_OPENING,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.entity import get_supported_features
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType
@@ -71,11 +71,11 @@ async def async_get_triggers(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device triggers for Cover devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
triggers = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -14,7 +14,7 @@ from homeassistant.components.sensor import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_IDLE, Platform, UnitOfDataRate
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import DelugeEntity
@@ -71,9 +71,7 @@ SENSOR_TYPES: tuple[DelugeSensorEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: entity_platform.AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the Deluge sensor."""
async_add_entities(

View File

@@ -7,7 +7,7 @@ from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DelugeEntity
from .const import DOMAIN
@@ -15,9 +15,7 @@ from .coordinator import DelugeDataUpdateCoordinator
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: entity_platform.AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the Deluge switch."""
async_add_entities([DelugeSwitch(hass.data[DOMAIN][entry.entry_id])])

View File

@@ -8,11 +8,7 @@ from typing import TYPE_CHECKING
import voluptuous as vol
from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
SensorEntity,
SensorStateClass,
)
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT,
@@ -135,7 +131,6 @@ class DerivativeSensor(RestoreEntity, SensorEntity):
_attr_icon = ICON
_attr_should_poll = False
_attr_state_class = SensorStateClass.MEASUREMENT
def __init__(
self,

View File

@@ -8,6 +8,7 @@ import voluptuous as vol
from homeassistant.const import CONF_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.condition import ConditionProtocol, trace_condition_function
from homeassistant.helpers.typing import ConfigType
from . import DeviceAutomationType, async_get_device_automation_platform
@@ -17,24 +18,13 @@ if TYPE_CHECKING:
from homeassistant.helpers import condition
class DeviceAutomationConditionProtocol(Protocol):
class DeviceAutomationConditionProtocol(ConditionProtocol, Protocol):
"""Define the format of device_condition modules.
Each module must define either CONDITION_SCHEMA or async_validate_condition_config.
Each module must define either CONDITION_SCHEMA or async_validate_condition_config
from ConditionProtocol.
"""
CONDITION_SCHEMA: vol.Schema
async def async_validate_condition_config(
self, hass: HomeAssistant, config: ConfigType
) -> ConfigType:
"""Validate config."""
def async_condition_from_config(
self, hass: HomeAssistant, config: ConfigType
) -> condition.ConditionCheckerType:
"""Evaluate state based on configuration."""
async def async_get_condition_capabilities(
self, hass: HomeAssistant, config: ConfigType
) -> dict[str, vol.Schema]:
@@ -62,4 +52,4 @@ async def async_condition_from_config(
platform = await async_get_device_automation_platform(
hass, config[CONF_DOMAIN], DeviceAutomationType.CONDITION
)
return platform.async_condition_from_config(hass, config)
return trace_condition_function(platform.async_condition_from_config(hass, config))

View File

@@ -13,7 +13,11 @@ from homeassistant.const import (
STATE_HOME,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import condition, config_validation as cv, entity_registry
from homeassistant.helpers import (
condition,
config_validation as cv,
entity_registry as er,
)
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -33,11 +37,11 @@ async def async_get_conditions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device conditions for Device tracker devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
conditions = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -17,7 +17,7 @@ from homeassistant.const import (
CONF_ZONE,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType
@@ -38,11 +38,11 @@ async def async_get_triggers(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device triggers for Device Tracker devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
triggers = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -12,7 +12,7 @@ from homeassistant.components.device_tracker import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_UNKNOWN, UnitOfFrequency
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
@@ -30,7 +30,7 @@ async def async_setup_entry(
coordinators: dict[
str, DataUpdateCoordinator[list[ConnectedStationInfo]]
] = hass.data[DOMAIN][entry.entry_id]["coordinators"]
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
tracked = set()
@callback
@@ -53,9 +53,7 @@ async def async_setup_entry(
def restore_entities() -> None:
"""Restore clients that are not a part of active clients list."""
missing = []
for entity in entity_registry.async_entries_for_config_entry(
registry, entry.entry_id
):
for entity in er.async_entries_for_config_entry(registry, entry.entry_id):
if (
entity.platform == DOMAIN
and entity.domain == DEVICE_TRACKER_DOMAIN

View File

@@ -21,8 +21,7 @@ from homeassistant.const import CONF_DEVICE_ID, CONF_HOST, CONF_MAC, CONF_TYPE,
from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.exceptions import IntegrationError
from homeassistant.helpers import device_registry
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import config_validation as cv, device_registry as dr
from .const import (
CONF_BROWSE_UNFILTERED,
@@ -501,4 +500,4 @@ async def _async_get_mac_address(hass: HomeAssistant, host: str) -> str | None:
if not mac_address:
return None
return device_registry.format_mac(mac_address)
return dr.format_mac(mac_address)

View File

@@ -29,7 +29,7 @@ from homeassistant.components.media_player import (
)
from homeassistant.const import CONF_DEVICE_ID, CONF_MAC, CONF_TYPE, CONF_URL
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry, entity_registry
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import (
@@ -363,21 +363,21 @@ class DlnaDmrEntity(MediaPlayerEntity):
# device's UDN. They may be the same, if the DMR is the root device.
connections.add(
(
device_registry.CONNECTION_UPNP,
dr.CONNECTION_UPNP,
self._device.profile_device.root_device.udn,
)
)
connections.add((device_registry.CONNECTION_UPNP, self._device.udn))
connections.add((dr.CONNECTION_UPNP, self._device.udn))
if self.mac_address:
# Connection based on MAC address, if known
connections.add(
# Device MAC is obtained from the config entry, which uses getmac
(device_registry.CONNECTION_NETWORK_MAC, self.mac_address)
(dr.CONNECTION_NETWORK_MAC, self.mac_address)
)
# Create linked HA DeviceEntry now the information is known.
dev_reg = device_registry.async_get(self.hass)
dev_reg = dr.async_get(self.hass)
device_entry = dev_reg.async_get_or_create(
config_entry_id=self.registry_entry.config_entry_id,
connections=connections,
@@ -388,7 +388,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
)
# Update entity registry to link to the device
ent_reg = entity_registry.async_get(self.hass)
ent_reg = er.async_get(self.hass)
ent_reg.async_get_or_create(
self.registry_entry.domain,
self.registry_entry.platform,

View File

@@ -19,7 +19,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
from .const import CONF_ASSOCIATION_DATA, DOMAIN, UPDATE_SECONDS
from .models import DormakabaDkeyData
PLATFORMS: list[Platform] = [Platform.LOCK, Platform.SENSOR]
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.LOCK, Platform.SENSOR]
_LOGGER = logging.getLogger(__name__)

View File

@@ -132,7 +132,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
try:
association_data = await lock.associate(user_input["activation_code"])
except BleakError:
except BleakError as err:
_LOGGER.warning("BleakError", exc_info=err)
return self.async_abort(reason="cannot_connect")
except dkey_errors.InvalidActivationCode:
errors["base"] = "invalid_code"

View File

@@ -11,5 +11,5 @@
"documentation": "https://www.home-assistant.io/integrations/dormakaba_dkey",
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["py-dormakaba-dkey==1.0.2"]
"requirements": ["py-dormakaba-dkey==1.0.3"]
}

View File

@@ -16,7 +16,7 @@ from homeassistant.components.sensor import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfEnergy, UnitOfPower
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import EfergyEntity
@@ -104,9 +104,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: entity_platform.AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Efergy sensors."""
api: Efergy = hass.data[DOMAIN][entry.entry_id]

View File

@@ -15,7 +15,10 @@ from homeassistant.components.sensor import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PERCENTAGE, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform as ep
from homeassistant.helpers.entity_platform import (
AddEntitiesCallback,
async_get_current_platform,
)
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from . import EightSleepBaseEntity, EightSleepConfigEntryData
@@ -68,7 +71,7 @@ SERVICE_EIGHT_SCHEMA = {
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: ep.AddEntitiesCallback
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the eight sleep sensors."""
config_entry_data: EightSleepConfigEntryData = hass.data[DOMAIN][entry.entry_id]
@@ -95,7 +98,7 @@ async def async_setup_entry(
async_add_entities(all_sensors)
platform = ep.async_get_current_platform()
platform = async_get_current_platform()
platform.async_register_entity_service(
SERVICE_HEAT_SET,
SERVICE_EIGHT_SCHEMA,

View File

@@ -9,8 +9,7 @@ import voluptuous as vol
from homeassistant.components.switch import PLATFORM_SCHEMA, SwitchEntity
from homeassistant.const import CONF_ID, CONF_NAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
@@ -38,7 +37,7 @@ def _migrate_to_new_unique_id(hass: HomeAssistant, dev_id, channel) -> None:
"""Migrate old unique ids to new unique ids."""
old_unique_id = f"{combine_hex(dev_id)}"
ent_reg = entity_registry.async_get(hass)
ent_reg = er.async_get(hass)
entity_id = ent_reg.async_get_entity_id(Platform.SWITCH, DOMAIN, old_unique_id)
if entity_id is not None:

View File

@@ -2,6 +2,7 @@
from __future__ import annotations
from datetime import datetime, timedelta
from random import randint
from enturclient import EnturPublicTransportData
import voluptuous as vol
@@ -22,7 +23,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import Throttle
import homeassistant.util.dt as dt_util
API_CLIENT_NAME = "homeassistant-homeassistant"
API_CLIENT_NAME = "homeassistant-{}"
CONF_STOP_IDS = "stop_ids"
CONF_EXPAND_PLATFORMS = "expand_platforms"
@@ -105,7 +106,7 @@ async def async_setup_platform(
quays = [s for s in stop_ids if "Quay" in s]
data = EnturPublicTransportData(
API_CLIENT_NAME,
API_CLIENT_NAME.format(str(randint(100000, 999999))),
stops=stops,
quays=quays,
line_whitelist=line_whitelist,

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
"iot_class": "cloud_polling",
"loggers": ["env_canada"],
"requirements": ["env_canada==0.5.28"]
"requirements": ["env_canada==0.5.29"]
}

View File

@@ -14,6 +14,6 @@
"integration_type": "device",
"iot_class": "local_push",
"loggers": ["aioesphomeapi", "noiseprotocol"],
"requirements": ["aioesphomeapi==13.4.0", "esphome-dashboard-api==1.2.3"],
"requirements": ["aioesphomeapi==13.4.1", "esphome-dashboard-api==1.2.3"],
"zeroconf": ["_esphomelib._tcp.local."]
}

View File

@@ -17,10 +17,10 @@ from homeassistant.config_entries import (
)
from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers import (
config_validation as cv,
discovery_flow,
entity_platform,
from homeassistant.helpers import config_validation as cv, discovery_flow
from homeassistant.helpers.entity_platform import (
AddEntitiesCallback,
async_get_current_platform,
)
from .const import (
@@ -53,9 +53,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: entity_platform.AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up EZVIZ cameras based on a config entry."""
@@ -132,7 +130,7 @@ async def async_setup_entry(
async_add_entities(camera_entities)
platform = entity_platform.async_get_current_platform()
platform = async_get_current_platform()
platform.async_register_entity_service(
SERVICE_PTZ,

View File

@@ -14,7 +14,11 @@ from homeassistant.const import (
STATE_ON,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import condition, config_validation as cv, entity_registry
from homeassistant.helpers import (
condition,
config_validation as cv,
entity_registry as er,
)
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -34,11 +38,11 @@ async def async_get_conditions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device conditions for Fan devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
conditions = []
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -27,7 +27,7 @@ from homeassistant.helpers.icon import icon_for_battery_level
from homeassistant.helpers.json import save_json
from homeassistant.helpers.network import NoURLAvailableError, get_url
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util.json import load_json
from homeassistant.util.json import load_json_object
from homeassistant.util.unit_system import METRIC_SYSTEM
from .const import (
@@ -85,7 +85,7 @@ def request_app_setup(
"""Handle configuration updates."""
config_path = hass.config.path(FITBIT_CONFIG_FILE)
if os.path.isfile(config_path):
config_file = load_json(config_path)
config_file = load_json_object(config_path)
if config_file == DEFAULT_CONFIG:
error_msg = (
f"You didn't correctly modify {FITBIT_CONFIG_FILE}, please try"
@@ -161,7 +161,7 @@ def setup_platform(
"""Set up the Fitbit sensor."""
config_path = hass.config.path(FITBIT_CONFIG_FILE)
if os.path.isfile(config_path):
config_file: ConfigType = cast(ConfigType, load_json(config_path))
config_file = load_json_object(config_path)
if config_file == DEFAULT_CONFIG:
request_app_setup(
hass, config, add_entities, config_path, discovery_info=None
@@ -175,13 +175,10 @@ def setup_platform(
if "fitbit" in _CONFIGURING:
configurator.request_done(hass, _CONFIGURING.pop("fitbit"))
access_token: str | None = config_file.get(ATTR_ACCESS_TOKEN)
refresh_token: str | None = config_file.get(ATTR_REFRESH_TOKEN)
expires_at: int | None = config_file.get(ATTR_LAST_SAVED_AT)
if (
access_token is not None
and refresh_token is not None
and expires_at is not None
(access_token := config_file.get(ATTR_ACCESS_TOKEN)) is not None
and (refresh_token := config_file.get(ATTR_REFRESH_TOKEN)) is not None
and (expires_at := config_file.get(ATTR_LAST_SAVED_AT)) is not None
):
authd_client = Fitbit(
config_file.get(CONF_CLIENT_ID),
@@ -192,7 +189,7 @@ def setup_platform(
refresh_cb=lambda x: None,
)
if int(time.time()) - expires_at > 3600:
if int(time.time()) - cast(int, expires_at) > 3600:
authd_client.client.refresh_token()
user_profile = authd_client.user_profile_get()["user"]

View File

@@ -87,14 +87,23 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
hass, STARTUP_SCAN_TIMEOUT
)
@callback
def _async_start_background_discovery(*_: Any) -> None:
"""Run discovery in the background."""
hass.async_create_background_task(_async_discovery(), "flux_led-discovery")
async def _async_discovery(*_: Any) -> None:
async_trigger_discovery(
hass, await async_discover_devices(hass, DISCOVER_SCAN_TIMEOUT)
)
async_trigger_discovery(hass, domain_data[FLUX_LED_DISCOVERY])
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, _async_discovery)
async_track_time_interval(hass, _async_discovery, DISCOVERY_INTERVAL)
hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STARTED, _async_start_background_discovery
)
async_track_time_interval(
hass, _async_start_background_discovery, DISCOVERY_INTERVAL
)
return True

View File

@@ -20,5 +20,5 @@
"documentation": "https://www.home-assistant.io/integrations/frontend",
"integration_type": "system",
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20230222.0"]
"requirements": ["home-assistant-frontend==20230227.0"]
}

View File

@@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/garages_amsterdam",
"iot_class": "cloud_polling",
"requirements": ["odp-amsterdam==5.0.1"]
"requirements": ["odp-amsterdam==5.1.0"]
}

View File

@@ -79,10 +79,10 @@ class GeniusClimateZone(GeniusHeatingZone, ClimateEntity):
def hvac_action(self) -> str | None:
"""Return the current running hvac operation if supported."""
if "_state" in self._zone.data: # only for v3 API
if self._zone.data["output"] == 1:
return HVACAction.HEATING
if not self._zone.data["_state"].get("bIsActive"):
return HVACAction.OFF
if self._zone.data["_state"].get("bOutRequestHeat"):
return HVACAction.HEATING
return HVACAction.IDLE
return None

View File

@@ -3,7 +3,7 @@ from homeassistant.components.device_tracker import SourceType, TrackerEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@@ -34,7 +34,7 @@ async def async_setup_entry(
] = async_dispatcher_connect(hass, TRACKER_UPDATE, _receive_data)
# Restore previously loaded devices
dev_reg = device_registry.async_get(hass)
dev_reg = dr.async_get(hass)
dev_ids = {
identifier[1]
for device in dev_reg.devices.values()

View File

@@ -21,7 +21,7 @@ from homeassistant.const import (
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@@ -257,7 +257,7 @@ async def async_setup_entry(
hass: HomeAssistant, old_unique_id: str, new_key: str
) -> None:
"""Migrate unique IDs to the new format."""
ent_reg = entity_registry.async_get(hass)
ent_reg = er.async_get(hass)
if entity_id := ent_reg.async_get_entity_id(
Platform.SENSOR, DOMAIN, old_unique_id

View File

@@ -22,7 +22,12 @@ from homeassistant.const import (
STATE_UNAVAILABLE,
)
from homeassistant.core import Context, HomeAssistant, State, callback
from homeassistant.helpers import area_registry, device_registry, entity_registry, start
from homeassistant.helpers import (
area_registry as ar,
device_registry as dr,
entity_registry as er,
start,
)
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.network import get_url
from homeassistant.helpers.storage import Store
@@ -52,15 +57,11 @@ LOCAL_SDK_MIN_VERSION = AwesomeVersion("2.1.5")
@callback
def _get_registry_entries(
hass: HomeAssistant, entity_id: str
) -> tuple[
entity_registry.RegistryEntry | None,
device_registry.DeviceEntry | None,
area_registry.AreaEntry | None,
]:
) -> tuple[er.RegistryEntry | None, dr.DeviceEntry | None, ar.AreaEntry | None,]:
"""Get registry entries."""
ent_reg = entity_registry.async_get(hass)
dev_reg = device_registry.async_get(hass)
area_reg = area_registry.async_get(hass)
ent_reg = er.async_get(hass)
dev_reg = dr.async_get(hass)
area_reg = ar.async_get(hass)
if (entity_entry := ent_reg.async_get(entity_id)) and entity_entry.device_id:
device_entry = dev_reg.devices.get(entity_entry.device_id)

View File

@@ -832,7 +832,7 @@ class TemperatureControlTrait(_Trait):
"temperatureUnitForUX": _google_temp_unit(
self.hass.config.units.temperature_unit
),
"queryOnlyTemperatureSetting": True,
"queryOnlyTemperatureControl": True,
"temperatureRange": {
"minThresholdCelsius": -100,
"maxThresholdCelsius": 100,

View File

@@ -8,7 +8,7 @@ from homeassistant.const import (
ATTR_LONGITUDE,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@@ -44,7 +44,7 @@ async def async_setup_entry(
] = async_dispatcher_connect(hass, TRACKER_UPDATE, _receive_data)
# Restore previously loaded devices
dev_reg = device_registry.async_get(hass)
dev_reg = dr.async_get(hass)
dev_ids = {
identifier[1]
for device in dev_reg.devices.values()

View File

@@ -12,7 +12,7 @@ from aioguardian.errors import GuardianError
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@@ -41,7 +41,7 @@ def async_finish_entity_domain_replacements(
entity_replacement_strategies: Iterable[EntityDomainReplacementStrategy],
) -> None:
"""Remove old entities and create a repairs issue with info on their replacement."""
ent_reg = entity_registry.async_get(hass)
ent_reg = er.async_get(hass)
for strategy in entity_replacement_strategies:
try:
[registry_entry] = [

View File

@@ -5,7 +5,7 @@ from homeassistant.components.remote import ATTR_ACTIVITY, ATTR_DELAY_SECS
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_NAME, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_send
from .const import (
@@ -60,7 +60,7 @@ async def _migrate_old_unique_ids(
names_to_ids = {activity["label"]: activity["id"] for activity in data.activities}
@callback
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
def _async_migrator(entity_entry: er.RegistryEntry):
# Old format for switches was {remote_unique_id}-{activity_name}
# New format is activity_{activity_id}
parts = entity_entry.unique_id.split("-", 1)
@@ -78,7 +78,7 @@ async def _migrate_old_unique_ids(
return None
await entity_registry.async_migrate_entries(hass, entry_id, _async_migrator)
await er.async_migrate_entries(hass, entry_id, _async_migrator)
@callback

View File

@@ -1,7 +1,6 @@
{
"domain": "hassio",
"name": "Home Assistant Supervisor",
"after_dependencies": ["panel_custom"],
"codeowners": ["@home-assistant/supervisor"],
"dependencies": ["http"],
"documentation": "https://www.home-assistant.io/integrations/hassio",

View File

@@ -1,6 +1,7 @@
"""Config flow for HLK-SW16."""
import asyncio
import async_timeout
from hlk_sw16 import create_hlk_sw16_connection
import voluptuous as vol
@@ -35,7 +36,8 @@ async def connect_client(hass, user_input):
reconnect_interval=DEFAULT_RECONNECT_INTERVAL,
keep_alive_interval=DEFAULT_KEEP_ALIVE_INTERVAL,
)
return await asyncio.wait_for(client_aw, timeout=CONNECTION_TIMEOUT)
async with async_timeout.timeout(CONNECTION_TIMEOUT):
return await client_aw
async def validate_input(hass: HomeAssistant, user_input):

View File

@@ -50,8 +50,12 @@ from homeassistant.const import (
)
from homeassistant.core import CoreState, HomeAssistant, ServiceCall, State, callback
from homeassistant.exceptions import HomeAssistantError, Unauthorized
from homeassistant.helpers import device_registry, entity_registry, instance_id
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
entity_registry as er,
instance_id,
)
from homeassistant.helpers.entityfilter import (
BASE_FILTER_SCHEMA,
FILTER_SCHEMA,
@@ -431,20 +435,19 @@ def _async_register_events_and_services(hass: HomeAssistant) -> None:
async def async_handle_homekit_unpair(service: ServiceCall) -> None:
"""Handle unpair HomeKit service call."""
referenced = async_extract_referenced_entity_ids(hass, service)
dev_reg = device_registry.async_get(hass)
dev_reg = dr.async_get(hass)
for device_id in referenced.referenced_devices:
if not (dev_reg_ent := dev_reg.async_get(device_id)):
raise HomeAssistantError(f"No device found for device id: {device_id}")
macs = [
cval
for ctype, cval in dev_reg_ent.connections
if ctype == device_registry.CONNECTION_NETWORK_MAC
if ctype == dr.CONNECTION_NETWORK_MAC
]
matching_instances = [
homekit
for homekit in _async_all_homekit_instances(hass)
if homekit.driver
and device_registry.format_mac(homekit.driver.state.mac) in macs
if homekit.driver and dr.format_mac(homekit.driver.state.mac) in macs
]
if not matching_instances:
raise HomeAssistantError(
@@ -698,7 +701,7 @@ class HomeKit:
return False
def add_bridge_triggers_accessory(
self, device: device_registry.DeviceEntry, device_triggers: list[dict[str, Any]]
self, device: dr.DeviceEntry, device_triggers: list[dict[str, Any]]
) -> None:
"""Add device automation triggers to the bridge."""
if self._would_exceed_max_devices(device.name):
@@ -734,8 +737,8 @@ class HomeKit:
async def async_configure_accessories(self) -> list[State]:
"""Configure accessories for the included states."""
dev_reg = device_registry.async_get(self.hass)
ent_reg = entity_registry.async_get(self.hass)
dev_reg = dr.async_get(self.hass)
ent_reg = er.async_get(self.hass)
device_lookup = ent_reg.async_get_device_class_lookup(
{
(BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.BATTERY_CHARGING),
@@ -830,8 +833,8 @@ class HomeKit:
def _async_register_bridge(self) -> None:
"""Register the bridge as a device so homekit_controller and exclude it from discovery."""
assert self.driver is not None
dev_reg = device_registry.async_get(self.hass)
formatted_mac = device_registry.format_mac(self.driver.state.mac)
dev_reg = dr.async_get(self.hass)
formatted_mac = dr.format_mac(self.driver.state.mac)
# Connections and identifiers are both used here.
#
# connections exists so homekit_controller can know the
@@ -844,7 +847,7 @@ class HomeKit:
# because this was the way you had to fix homekit when pairing
# failed.
#
connection = (device_registry.CONNECTION_NETWORK_MAC, formatted_mac)
connection = (dr.CONNECTION_NETWORK_MAC, formatted_mac)
identifier = (DOMAIN, self._entry_id, BRIDGE_SERIAL_NUMBER)
self._async_purge_old_bridges(dev_reg, identifier, connection)
is_accessory_mode = self._homekit_mode == HOMEKIT_MODE_ACCESSORY
@@ -858,13 +861,13 @@ class HomeKit:
manufacturer=MANUFACTURER,
name=accessory_friendly_name(self._entry_title, self.driver.accessory),
model=f"HomeKit {hk_mode_name}",
entry_type=device_registry.DeviceEntryType.SERVICE,
entry_type=dr.DeviceEntryType.SERVICE,
)
@callback
def _async_purge_old_bridges(
self,
dev_reg: device_registry.DeviceRegistry,
dev_reg: dr.DeviceRegistry,
identifier: tuple[str, str, str],
connection: tuple[str, str],
) -> None:
@@ -920,7 +923,7 @@ class HomeKit:
async def _async_add_trigger_accessories(self) -> None:
"""Add devices with triggers to the bridge."""
dev_reg = device_registry.async_get(self.hass)
dev_reg = dr.async_get(self.hass)
valid_device_ids = []
for device_id in self._devices:
if not dev_reg.async_get(device_id):
@@ -989,7 +992,7 @@ class HomeKit:
@callback
def _async_configure_linked_sensors(
self,
ent_reg_ent: entity_registry.RegistryEntry,
ent_reg_ent: er.RegistryEntry,
device_lookup: dict[str, dict[tuple[str, str | None], str]],
state: State,
) -> None:
@@ -1051,8 +1054,8 @@ class HomeKit:
async def _async_set_device_info_attributes(
self,
ent_reg_ent: entity_registry.RegistryEntry,
dev_reg: device_registry.DeviceRegistry,
ent_reg_ent: er.RegistryEntry,
dev_reg: dr.DeviceRegistry,
entity_id: str,
) -> None:
"""Set attributes that will be used for homekit device info."""
@@ -1070,7 +1073,7 @@ class HomeKit:
ent_cfg[ATTR_INTEGRATION] = ent_reg_ent.platform
def _fill_config_from_device_registry_entry(
self, device_entry: device_registry.DeviceEntry, config: dict[str, Any]
self, device_entry: dr.DeviceEntry, config: dict[str, Any]
) -> None:
"""Populate a config dict from the registry."""
if device_entry.manufacturer:

View File

@@ -28,8 +28,11 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant, callback, split_entity_id
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import device_registry, entity_registry
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
entity_registry as er,
)
from homeassistant.helpers.entityfilter import (
CONF_EXCLUDE_DOMAINS,
CONF_EXCLUDE_ENTITIES,
@@ -630,7 +633,7 @@ async def _async_get_supported_devices(hass: HomeAssistant) -> dict[str, str]:
results = await device_automation.async_get_device_automations(
hass, device_automation.DeviceAutomationType.TRIGGER
)
dev_reg = device_registry.async_get(hass)
dev_reg = dr.async_get(hass)
unsorted: dict[str, str] = {}
for device_id in results:
entry = dev_reg.async_get(device_id)
@@ -639,7 +642,7 @@ async def _async_get_supported_devices(hass: HomeAssistant) -> dict[str, str]:
def _exclude_by_entity_registry(
ent_reg: entity_registry.EntityRegistry,
ent_reg: er.EntityRegistry,
entity_id: str,
include_entity_category: bool,
include_hidden: bool,
@@ -661,7 +664,7 @@ def _async_get_matching_entities(
include_hidden: bool = False,
) -> dict[str, str]:
"""Fetch all entities or entities in the given domains."""
ent_reg = entity_registry.async_get(hass)
ent_reg = er.async_get(hass)
return {
state.entity_id: (
f"{state.attributes.get(ATTR_FRIENDLY_NAME, state.entity_id)} ({state.entity_id})"

View File

@@ -7,7 +7,7 @@ from typing import Any
from pyhap.const import CATEGORY_SENSOR
from homeassistant.core import CALLBACK_TYPE, Context
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.trigger import async_initialize_triggers
from .accessories import TYPES, HomeAccessory
@@ -42,7 +42,7 @@ class DeviceTriggerAccessory(HomeAccessory):
self._remove_triggers: CALLBACK_TYPE | None = None
self.triggers = []
assert device_triggers is not None
ent_reg = entity_registry.async_get(self.hass)
ent_reg = er.async_get(self.hass)
for idx, trigger in enumerate(device_triggers):
type_: str = trigger["type"]
subtype: str | None = trigger.get("subtype")

View File

@@ -14,6 +14,7 @@ PLATFORMS = [
Platform.CLIMATE,
Platform.COVER,
Platform.LIGHT,
Platform.LOCK,
Platform.SENSOR,
Platform.SWITCH,
Platform.WEATHER,

View File

@@ -0,0 +1,39 @@
"""Helper functions for Homematicip Cloud Integration."""
from functools import wraps
import json
import logging
from homeassistant.exceptions import HomeAssistantError
from . import HomematicipGenericEntity
_LOGGER = logging.getLogger(__name__)
def is_error_response(response) -> bool:
"""Response from async call contains errors or not."""
if isinstance(response, dict):
return response.get("errorCode") not in ("", None)
return False
def handle_errors(func):
"""Handle async errors."""
@wraps(func)
async def inner(self: HomematicipGenericEntity) -> None:
"""Handle errors from async call."""
result = await func(self)
if is_error_response(result):
_LOGGER.error(
"Error while execute function %s: %s",
__name__,
json.dumps(result),
)
raise HomeAssistantError(
f"Error while execute function {func.__name__}: {result.get('errorCode')}. See log for more information."
)
return inner

View File

@@ -0,0 +1,95 @@
"""Support for HomematicIP Cloud lock devices."""
from __future__ import annotations
import logging
from typing import Any
from homematicip.aio.device import AsyncDoorLockDrive
from homematicip.base.enums import LockState, MotorState
from homeassistant.components.lock import LockEntity, LockEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericEntity
from .helpers import handle_errors
_LOGGER = logging.getLogger(__name__)
ATTR_AUTO_RELOCK_DELAY = "auto_relock_delay"
ATTR_DOOR_HANDLE_TYPE = "door_handle_type"
ATTR_DOOR_LOCK_DIRECTION = "door_lock_direction"
ATTR_DOOR_LOCK_NEUTRAL_POSITION = "door_lock_neutral_position"
ATTR_DOOR_LOCK_TURNS = "door_lock_turns"
DEVICE_DLD_ATTRIBUTES = {
"autoRelockDelay": ATTR_AUTO_RELOCK_DELAY,
"doorHandleType": ATTR_DOOR_HANDLE_TYPE,
"doorLockDirection": ATTR_DOOR_LOCK_DIRECTION,
"doorLockNeutralPosition": ATTR_DOOR_LOCK_NEUTRAL_POSITION,
"doorLockTurns": ATTR_DOOR_LOCK_TURNS,
}
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the HomematicIP locks from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
async_add_entities(
HomematicipDoorLockDrive(hap, device)
for device in hap.home.devices
if isinstance(device, AsyncDoorLockDrive)
)
class HomematicipDoorLockDrive(HomematicipGenericEntity, LockEntity):
"""Representation of the HomematicIP DoorLockDrive."""
_attr_supported_features = LockEntityFeature.OPEN
@property
def is_locked(self) -> bool | None:
"""Return true if device is locked."""
return (
self._device.lockState == LockState.LOCKED
and self._device.motorState == MotorState.STOPPED
)
@property
def is_locking(self) -> bool:
"""Return true if device is locking."""
return self._device.motorState == MotorState.CLOSING
@property
def is_unlocking(self) -> bool:
"""Return true if device is unlocking."""
return self._device.motorState == MotorState.OPENING
@handle_errors
async def async_lock(self, **kwargs: Any) -> None:
"""Lock the device."""
return await self._device.set_lock_state(LockState.LOCKED)
@handle_errors
async def async_unlock(self, **kwargs: Any) -> None:
"""Unlock the device."""
return await self._device.set_lock_state(LockState.UNLOCKED)
@handle_errors
async def async_open(self, **kwargs: Any) -> None:
"""Open the door latch."""
return await self._device.set_lock_state(LockState.OPEN)
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes of the device."""
return super().extra_state_attributes | {
attr_key: attr_value
for attr, attr_key in DEVICE_DLD_ATTRIBUTES.items()
if (attr_value := getattr(self._device, attr, None)) is not None
}

View File

@@ -421,6 +421,7 @@ class HoneywellUSThermostat(ClimateEntity):
"""Get the latest state from the service."""
try:
await self._device.refresh()
self._attr_available = True
except (
aiosomecomfort.SomeComfortError,
OSError,
@@ -428,8 +429,10 @@ class HoneywellUSThermostat(ClimateEntity):
try:
await self._data.client.login()
except aiosomecomfort.SomeComfortError:
except aiosomecomfort.AuthError:
self._attr_available = False
await self.hass.async_create_task(
self.hass.config_entries.async_reload(self._data.entry_id)
)
except aiosomecomfort.SomeComfortError:
self._attr_available = False

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/honeywell",
"iot_class": "cloud_polling",
"loggers": ["somecomfort"],
"requirements": ["aiosomecomfort==0.0.8"]
"requirements": ["aiosomecomfort==0.0.11"]
}

View File

@@ -7,6 +7,13 @@
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
}
},
"reauth_confirm": {
"title": "[%key:common::config_flow::title::reauth%]",
"description": "The Honeywell integration needs to re-authenticate your account",
"data": {
"password": "[%key:common::config_flow::data::password%]"
}
}
},
"error": {

View File

@@ -5,6 +5,7 @@ from collections.abc import Awaitable, Callable
import logging
import re
from typing import Final
from urllib.parse import unquote
from aiohttp.web import Application, HTTPBadRequest, Request, StreamResponse, middleware
@@ -39,18 +40,24 @@ FILTERS: Final = re.compile(
def setup_security_filter(app: Application) -> None:
"""Create security filter middleware for the app."""
def _recursive_unquote(value: str) -> str:
"""Handle values that are encoded multiple times."""
if (unquoted := unquote(value)) != value:
unquoted = _recursive_unquote(unquoted)
return unquoted
@middleware
async def security_filter_middleware(
request: Request, handler: Callable[[Request], Awaitable[StreamResponse]]
) -> StreamResponse:
"""Process request and tblock commonly known exploit attempts."""
if FILTERS.search(request.path):
"""Process request and block commonly known exploit attempts."""
if FILTERS.search(_recursive_unquote(request.path)):
_LOGGER.warning(
"Filtered a potential harmful request to: %s", request.raw_path
)
raise HTTPBadRequest
if FILTERS.search(request.query_string):
if FILTERS.search(_recursive_unquote(request.query_string)):
_LOGGER.warning(
"Filtered a request with a potential harmful query string: %s",
request.raw_path,

View File

@@ -44,7 +44,7 @@ from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
discovery,
entity_registry,
entity_registry as er,
)
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
from homeassistant.helpers.entity import DeviceInfo, Entity
@@ -359,8 +359,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# Transitional from < 2021.8: update None config entry and entity unique ids
if router_info and (serial_number := router_info.get("SerialNumber")):
hass.config_entries.async_update_entry(entry, unique_id=serial_number)
ent_reg = entity_registry.async_get(hass)
for entity_entry in entity_registry.async_entries_for_config_entry(
ent_reg = er.async_get(hass)
for entity_entry in er.async_entries_for_config_entry(
ent_reg, entry.entry_id
):
if not entity_entry.unique_id.startswith("None-"):

View File

@@ -15,7 +15,7 @@ from homeassistant.components.device_tracker import (
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@@ -66,7 +66,7 @@ async def async_setup_entry(
# Initialize already tracked entities
tracked: set[str] = set()
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
known_entities: list[Entity] = []
track_wired_clients = router.config_entry.options.get(
CONF_TRACK_WIRED_CLIENTS, DEFAULT_TRACK_WIRED_CLIENTS

View File

@@ -18,8 +18,11 @@ from homeassistant.components import zeroconf
from homeassistant.const import CONF_API_KEY, CONF_HOST
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import aiohttp_client, device_registry
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import (
aiohttp_client,
config_validation as cv,
device_registry as dr,
)
from homeassistant.util.network import is_ipv6_address
from .const import (
@@ -306,10 +309,8 @@ class HueV2OptionsFlowHandler(config_entries.OptionsFlow):
# create a list of Hue device ID's that the user can select
# to ignore availability status
dev_reg = device_registry.async_get(self.hass)
entries = device_registry.async_entries_for_config_entry(
dev_reg, self.config_entry.entry_id
)
dev_reg = dr.async_get(self.hass)
entries = dr.async_entries_for_config_entry(dev_reg, self.config_entry.entry_id)
dev_ids = {
identifier[1]: entry.name
for entry in entries

View File

@@ -35,6 +35,7 @@ TRIGGER_TYPE = {
"remote_double_button_long_press": "both {subtype} released after long press",
"remote_double_button_short_press": "both {subtype} released",
"initial_press": "{subtype} pressed initially",
"long_press": "{subtype} long press",
"repeat": "{subtype} held down",
"short_release": "{subtype} released after short press",
"long_release": "{subtype} released after long press",

View File

@@ -11,6 +11,6 @@
"iot_class": "local_push",
"loggers": ["aiohue"],
"quality_scale": "platinum",
"requirements": ["aiohue==4.6.1"],
"requirements": ["aiohue==4.6.2"],
"zeroconf": ["_hue._tcp.local."]
}

View File

@@ -13,9 +13,12 @@ import voluptuous as vol
from homeassistant.components.scene import ATTR_TRANSITION, Scene as SceneEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_platform
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import (
AddEntitiesCallback,
async_get_current_platform,
)
from .bridge import HueBridge
from .const import DOMAIN
@@ -31,7 +34,7 @@ ATTR_BRIGHTNESS = "brightness"
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: entity_platform.AddEntitiesCallback,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up scene platform from Hue group scenes."""
bridge: HueBridge = hass.data[DOMAIN][config_entry.entry_id]
@@ -62,7 +65,7 @@ async def async_setup_entry(
)
# add platform service to turn_on/activate scene with advanced options
platform = entity_platform.async_get_current_platform()
platform = async_get_current_platform()
platform.async_register_entity_service(
SERVICE_ACTIVATE_SCENE,
{
@@ -118,13 +121,14 @@ class HueSceneEntityBase(HueBaseEntity, SceneEntity):
"""Return device (service) info."""
# we create a virtual service/device for Hue scenes
# so we have a parent for grouped lights and scenes
group_type = self.group.type.value.title()
return DeviceInfo(
identifiers={(DOMAIN, self.group.id)},
entry_type=DeviceEntryType.SERVICE,
name=self.group.metadata.name,
manufacturer=self.bridge.api.config.bridge_device.product_data.manufacturer_name,
model=self.group.type.value.title(),
suggested_area=self.group.metadata.name,
suggested_area=self.group.metadata.name if group_type == "Room" else None,
via_device=(DOMAIN, self.bridge.api.config.bridge_device.id),
)

View File

@@ -16,7 +16,7 @@ from homeassistant.const import (
ATTR_VIA_DEVICE,
)
from homeassistant.core import callback
from homeassistant.helpers import device_registry
from homeassistant.helpers import device_registry as dr
from ..const import DOMAIN
@@ -29,11 +29,11 @@ async def async_setup_devices(bridge: "HueBridge"):
entry = bridge.config_entry
hass = bridge.hass
api: HueBridgeV2 = bridge.api # to satisfy typing
dev_reg = device_registry.async_get(hass)
dev_reg = dr.async_get(hass)
dev_controller = api.devices
@callback
def add_device(hue_device: Device) -> device_registry.DeviceEntry:
def add_device(hue_device: Device) -> dr.DeviceEntry:
"""Register a Hue device in device registry."""
model = f"{hue_device.product_data.product_name} ({hue_device.product_data.model_id})"
params = {
@@ -51,9 +51,7 @@ async def async_setup_devices(bridge: "HueBridge"):
params[ATTR_VIA_DEVICE] = (DOMAIN, api.config.bridge_device.id)
zigbee = dev_controller.get_zigbee_connectivity(hue_device.id)
if zigbee and zigbee.mac_address:
params[ATTR_CONNECTIONS] = {
(device_registry.CONNECTION_NETWORK_MAC, zigbee.mac_address)
}
params[ATTR_CONNECTIONS] = {(dr.CONNECTION_NETWORK_MAC, zigbee.mac_address)}
return dev_reg.async_get_or_create(config_entry_id=entry.entry_id, **params)
@@ -77,9 +75,7 @@ async def async_setup_devices(bridge: "HueBridge"):
known_devices = [add_device(hue_device) for hue_device in dev_controller]
# Check for nodes that no longer exist and remove them
for device in device_registry.async_entries_for_config_entry(
dev_reg, entry.entry_id
):
for device in dr.async_entries_for_config_entry(dev_reg, entry.entry_id):
if device not in known_devices:
# handle case where a virtual device was created for a Hue group
hue_dev_id = next(x[1] for x in device.identifiers if x[0] == DOMAIN)

View File

@@ -46,6 +46,7 @@ DEFAULT_BUTTON_EVENT_TYPES = (
ButtonEvent.INITIAL_PRESS,
ButtonEvent.REPEAT,
ButtonEvent.SHORT_RELEASE,
ButtonEvent.LONG_PRESS,
ButtonEvent.LONG_RELEASE,
)

View File

@@ -55,7 +55,13 @@ class HueBaseEntity(Entity):
self._attr_unique_id = resource.id
# device is precreated in main handler
# this attaches the entity to the precreated device
if self.device is not None:
if self.device is None:
# attach all device-less entities to the bridge itself
# e.g. config based sensors like entertainment area
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, bridge.api.config.bridge.bridge_id)},
)
else:
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self.device.id)},
)
@@ -137,17 +143,14 @@ class HueBaseEntity(Entity):
def _handle_event(self, event_type: EventType, resource: HueResource) -> None:
"""Handle status event for this resource (or it's parent)."""
if event_type == EventType.RESOURCE_DELETED:
# remove any services created for zones/rooms
# handle removal of room and zone 'virtual' devices/services
# regular devices are removed automatically by the logic in device.py.
if resource.type in (ResourceTypes.ROOM, ResourceTypes.ZONE):
dev_reg = async_get_device_registry(self.hass)
if device := dev_reg.async_get_device({(DOMAIN, resource.id)}):
dev_reg.async_remove_device(device.id)
if resource.type in (
ResourceTypes.GROUPED_LIGHT,
ResourceTypes.SCENE,
ResourceTypes.SMART_SCENE,
):
# cleanup entities that are not strictly device-bound and have the bridge as parent
if self.device is None:
ent_reg = async_get_entity_registry(self.hass)
ent_reg.async_remove(self.entity_id)
return

View File

@@ -9,7 +9,7 @@ from aiohue.v2.models.relative_rotary import RelativeRotary
from homeassistant.const import CONF_DEVICE_ID, CONF_ID, CONF_TYPE, CONF_UNIQUE_ID
from homeassistant.core import callback
from homeassistant.helpers import device_registry
from homeassistant.helpers import device_registry as dr
from homeassistant.util import slugify
from ..const import ATTR_HUE_EVENT, CONF_SUBTYPE, DOMAIN
@@ -29,7 +29,7 @@ async def async_setup_hue_events(bridge: "HueBridge"):
hass = bridge.hass
api: HueBridgeV2 = bridge.api # to satisfy typing
conf_entry = bridge.config_entry
dev_reg = device_registry.async_get(hass)
dev_reg = dr.async_get(hass)
btn_controller = api.sensors.button
rotary_controller = api.sensors.relative_rotary

View File

@@ -8,14 +8,10 @@ from energyflip.const import (
SOURCE_TYPE_GAS,
)
from homeassistant.const import UnitOfTime, UnitOfVolume
DATA_COORDINATOR = "coordinator"
DOMAIN = "huisbaasje"
FLOW_CUBIC_METERS_PER_HOUR = f"{UnitOfVolume.CUBIC_METERS}/{UnitOfTime.HOURS}"
"""Interval in seconds between polls to huisbaasje."""
POLLING_INTERVAL = 20

View File

@@ -21,7 +21,13 @@ from homeassistant.components.sensor import (
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ID, UnitOfEnergy, UnitOfPower, UnitOfVolume
from homeassistant.const import (
CONF_ID,
UnitOfEnergy,
UnitOfPower,
UnitOfVolume,
UnitOfVolumeFlowRate,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import (
@@ -32,7 +38,6 @@ from homeassistant.helpers.update_coordinator import (
from .const import (
DATA_COORDINATOR,
DOMAIN,
FLOW_CUBIC_METERS_PER_HOUR,
SENSOR_TYPE_RATE,
SENSOR_TYPE_THIS_DAY,
SENSOR_TYPE_THIS_MONTH,
@@ -179,7 +184,7 @@ SENSORS_INFO = [
),
HuisbaasjeSensorEntityDescription(
name="Huisbaasje Current Gas",
native_unit_of_measurement=FLOW_CUBIC_METERS_PER_HOUR,
native_unit_of_measurement=UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR,
sensor_type=SENSOR_TYPE_RATE,
state_class=SensorStateClass.MEASUREMENT,
key=SOURCE_TYPE_GAS,

View File

@@ -14,7 +14,7 @@ from homeassistant.const import (
)
from homeassistant.core import Context, HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry
from homeassistant.helpers import entity_registry as er
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import get_capability, get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -48,11 +48,11 @@ async def async_get_actions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device actions for Humidifier devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN)
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -15,7 +15,11 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import condition, config_validation as cv, entity_registry
from homeassistant.helpers import (
condition,
config_validation as cv,
entity_registry as er,
)
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.entity import get_capability, get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
@@ -41,11 +45,11 @@ async def async_get_conditions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device conditions for Humidifier devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
conditions = await toggle_entity.async_get_conditions(hass, device_id, DOMAIN)
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

View File

@@ -22,7 +22,7 @@ from homeassistant.const import (
PERCENTAGE,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType
@@ -56,11 +56,11 @@ async def async_get_triggers(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device triggers for Humidifier devices."""
registry = entity_registry.async_get(hass)
registry = er.async_get(hass)
triggers = await toggle_entity.async_get_triggers(hass, device_id, DOMAIN)
# Get all the integrations entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id):
for entry in er.async_entries_for_device(registry, device_id):
if entry.domain != DOMAIN:
continue

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