Compare commits

...

151 Commits

Author SHA1 Message Date
Paulus Schoutsen
a141bc08e7 2023.7.2 (#96487) 2023-07-13 12:26:19 -04:00
Paulus Schoutsen
a982958143 Bumped version to 2023.7.2 2023-07-13 11:36:22 -04:00
J. Nick Koston
2822d98544 Ensure ESPHome dashboard connection recovers if its down when core starts (#96449) 2023-07-13 11:36:11 -04:00
J. Nick Koston
4f95039dfd Fix mixed case service schema registration (#96448) 2023-07-13 11:36:10 -04:00
Michael
658e87b6a5 Always add guest wifi qr code entity in AVM Fritz!Tools (#96435) 2023-07-13 11:36:09 -04:00
Joost Lekkerkerker
e6c8e0460f Add explicit device naming to Led BLE (#96421) 2023-07-13 11:36:06 -04:00
Franck Nijhof
c78628aa29 Update RestrictedPython to 6.1 (#96358) 2023-07-13 11:36:04 -04:00
Aaron Bach
3dc1ceed0b Fix extra verbiage in Ridwell rotating category sensor (#96345) 2023-07-13 11:36:03 -04:00
Joost Lekkerkerker
89e737facb Add has entity name to Blink (#96322) 2023-07-13 11:36:02 -04:00
J. Nick Koston
15ab483f61 Bump aiohomekit to 2.6.7 (#96291) 2023-07-13 11:36:01 -04:00
starkillerOG
0b3ff859e6 Bump reolink_aio to 0.7.3 (#96284) 2023-07-13 11:36:00 -04:00
puddly
bdcc9ec984 Fix ZHA serialization issue with warning devices (#96275)
* Bump ZHA dependencies

* Update unit tests to reduce mocks
2023-07-13 11:35:58 -04:00
Joost Lekkerkerker
382bfa24a8 Use explicit device naming for Escea (#96270) 2023-07-13 11:35:57 -04:00
Luke
6a54c18818 Bump Roborock to v0.30.0 (#96268)
bump to v0.30.0
2023-07-13 11:35:56 -04:00
J. Nick Koston
76ac7fa6a0 Fix race fetching ESPHome dashboard when there are no devices set up (#96196)
* Fix fetching ESPHome dashboard when there are no devices setup

fixes #96194

* coverage

* fix
2023-07-13 11:35:55 -04:00
Allen Porter
de1a367cff Enable retries on rainbird devices by loading model and version (#96190)
Update rainbird to load device model and version
2023-07-13 11:35:54 -04:00
Joost Lekkerkerker
e493cd642c Use explicit device name for Stookwijzer (#96184) 2023-07-13 11:35:52 -04:00
Ernst Klamer
c2a41fc21e Bump bthome to 2.12.1 (#96166) 2023-07-13 11:35:51 -04:00
G Johansson
ebc123c355 Fix implicitly using device name in Yale Smart Living (#96161)
Yale Smart Living device name
2023-07-13 11:35:50 -04:00
Robert Hillis
4874e13af8 Bump goalzero to 0.2.2 (#96121) 2023-07-13 11:35:49 -04:00
Jan Bouwhuis
9969f67508 Fix reference to translation reference in buienradar translations (#96119)
Do not  reference a reference
2023-07-13 11:35:47 -04:00
Joost Lekkerkerker
855962d729 Use explicit device name for Yalexs BLE (#96105) 2023-07-13 11:35:46 -04:00
Aaron Bach
98b8e27b08 Fix implicit device name for RainMachine update entity (#96094)
Fix implicit device name for RainMachine update entity
2023-07-13 11:35:45 -04:00
Franck Nijhof
b26e624b2b Fix implicit use of device name in Slimproto (#96081) 2023-07-13 11:35:44 -04:00
Joost Lekkerkerker
3c7ced21ad Use default MyStrom devicetype if not present (#96070)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2023-07-13 11:35:43 -04:00
Joost Lekkerkerker
eec05d4fc8 UPB explicit device name (#96042) 2023-07-13 11:35:41 -04:00
Barry Williams
32927e050f Remove openhome from discovery component (#96021) 2023-07-13 11:35:40 -04:00
Joost Lekkerkerker
c6b7a3d564 Use explicit device naming for Switchbot (#96011)
Use explicit entity naming for Switchbot
2023-07-13 11:35:39 -04:00
Jan Bouwhuis
6f5373fa6e Refactor async_get_hass to rely on threading.local instead of a ContextVar (#96005)
* Test for async_get_hass

* Add Fix
2023-07-13 11:35:38 -04:00
Joost Lekkerkerker
7bd9933092 Get MyStrom device state before checking support (#96004)
* Get device state before checking support

* Add full default device response to test

* Add test mocks

* Add test coverage
2023-07-13 11:35:37 -04:00
Eric Severance
52f60f1e48 Bump pywemo from 0.9.1 to 1.1.0 (#95951) 2023-07-13 11:35:36 -04:00
Aaron Collins
3667eb9400 Bump pydaikin 2.10.5 (#95656) 2023-07-13 11:35:34 -04:00
J. Nick Koston
80b24b23d3 Fix ESPHome deep sleep devices staying unavailable after unexpected disconnect (#96354)
backport of #96353
2023-07-12 10:57:17 -04:00
Paulus Schoutsen
816adce257 2023.7.1 (#96006) 2023-07-06 14:24:50 -04:00
Paulus Schoutsen
d18716e5f8 Disable test case for entity name (#96012) 2023-07-06 13:53:56 -04:00
Paulus Schoutsen
4096614ac0 Bumped version to 2023.7.1 2023-07-06 11:52:01 -04:00
Marcel van der Veldt
ef31608ce0 Fix state of slimproto players (#96000) 2023-07-06 11:51:46 -04:00
Bram Kragten
7408fa4ab6 Make script services always respond when asked (#95991)
* Make script services always respond when asked

* Update test_init.py
2023-07-06 11:51:45 -04:00
Jan-Philipp Benecke
10b97a77c6 Explicitly use device name as entity name for Xiaomi fan and humidifier (#95986) 2023-07-06 11:51:44 -04:00
Bram Kragten
3540c78fb9 Set correct response value in service description when async_set_service_schema is used (#95985)
* Mark scripts as response optional, make it always return a response if return_response is set

* Update test_init.py

* Revert "Update test_init.py"

This reverts commit 8e113e54db.

* Split + add test
2023-07-06 11:51:43 -04:00
Erik Montnemery
866e130967 Add missing qnap translation (#95969) 2023-07-06 11:51:42 -04:00
Allen Porter
d969b89a12 Bump pyrainbird to 2.1.0 (#95968) 2023-07-06 11:51:41 -04:00
micha91
bca5aae3bb Fix grouping feature for MusicCast (#95958)
check the current source for grouping using the source ID instead of the label
2023-07-06 11:51:40 -04:00
neocolis
7a21e858ab Fix matter exception NoneType in set_brightness for optional min/max level values (#95949)
Fix exception NoneType in set_brightness for optional min/max level values
2023-07-06 11:51:39 -04:00
Joost Lekkerkerker
224886eb29 Fix entity name for Flick Electric (#95947)
Fix entity name
2023-07-06 11:51:38 -04:00
Joost Lekkerkerker
95594a23dc Add explicit device naming for Tuya sensors (#95944) 2023-07-06 11:51:37 -04:00
Joost Lekkerkerker
4c10d186c0 Use device name for Nuki (#95941) 2023-07-06 11:51:35 -04:00
puddly
6275932c29 Migrate bracketed IP addresses in ZHA config entry (#95917)
* Automatically correct IP addresses surrounded by brackets

* Simplify regex

* Move pattern inline

* Maintain old behavior of stripping whitespace
2023-07-06 11:51:34 -04:00
J. Nick Koston
4229778cf6 Make SwitchBot no_devices_found message more helpful (#95916) 2023-07-06 11:51:33 -04:00
Bram Kragten
57369be322 Update frontend to 20230705.1 (#95913) 2023-07-06 11:51:32 -04:00
J. Nick Koston
3e19fba7d3 Handle integrations with empty services or failing to load during service description enumeration (#95911)
* wip

* tweaks

* tweaks

* add coverage

* complain loudly as we never execpt this to happen

* ensure not None

* comment it
2023-07-06 11:51:30 -04:00
Jan Bouwhuis
2196bd3a13 Fix not including device_name in friendly name if it is None (#95485)
* Omit device_name in friendly name if it is None

* Fix test
2023-07-06 11:51:29 -04:00
Franck Nijhof
91ea14d9eb 2023.7.0 (#95908) 2023-07-05 17:20:03 +02:00
Franck Nijhof
b90df4bdca Bumped version to 2023.7.0 2023-07-05 16:06:09 +02:00
Franck Nijhof
025969a76f Bumped version to 2023.7.0b6 2023-07-05 09:57:56 +02:00
Bram Kragten
8ed7390a61 Update frontend to 20230705.0 (#95890) 2023-07-05 09:57:39 +02:00
Emilv2
36f6c02c52 Bump pydelijn to 1.1.0 (#95878) 2023-07-05 09:57:35 +02:00
Daniel Gangl
a709b6af4c Bump zamg to 0.2.4 (#95874)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-07-05 09:57:32 +02:00
J. Nick Koston
284926159b Fix ESPHome alarm_control_panel when state is missing (#95871) 2023-07-05 09:57:28 +02:00
J. Nick Koston
8e2c0984b7 Fix reload in cert_expiry (#95867) 2023-07-05 09:57:25 +02:00
Erik Montnemery
0bb0e3fe72 Remove unsupported services and fields from fan/services.yaml (#95858) 2023-07-05 09:57:22 +02:00
Franck Nijhof
c123c22846 Revert "Remove airplay filter now that apple tv supports airplay 2" (#95843) 2023-07-05 09:57:18 +02:00
Martin Hjelmare
577ffef25c Disable legacy device tracker no platform log (#95839) 2023-07-05 09:57:15 +02:00
Martin Hjelmare
10a9b063fa Disable proximity no platform log (#95838) 2023-07-05 09:57:12 +02:00
starkillerOG
e22b79dbd9 Reolink fix missing title_placeholders (#95827) 2023-07-05 09:57:08 +02:00
Robert Svensson
89c580f27d Bump aiounifi to v49 (#95813) 2023-07-05 09:57:05 +02:00
Allen Porter
239cbb7ad1 Fix timezones used in list events (#95804)
* Fix timezones used in list events

* Add additional tests that catch floating vs timezone datetime comparisons
2023-07-05 09:57:00 +02:00
Paulus Schoutsen
d8f8557ae1 Bumped version to 2023.7.0b5 2023-07-03 15:23:57 -04:00
Allen Porter
3df1e9bc99 Ensure that calendar output values are json types (#95797) 2023-07-03 15:23:49 -04:00
Bram Kragten
8db987e0b3 Update frontend to 20230703.0 (#95795) 2023-07-03 15:23:48 -04:00
Joost Lekkerkerker
d77a168121 Fix Growatt translation key (#95784) 2023-07-03 15:23:47 -04:00
Erik Montnemery
3550a9e2d2 Fix execute device actions with WS execute_script (#95783) 2023-07-03 15:23:46 -04:00
Franck Nijhof
0ce3b89139 Fix implicit use of device name in Verisure (#95781) 2023-07-03 15:23:45 -04:00
Franck Nijhof
3c0d234332 Fix implicit use of device name in TwenteMilieu (#95780) 2023-07-03 15:23:44 -04:00
Paul Bottein
601ca8562c Fix datetime parameter validation for list events (#95778) 2023-07-03 15:23:43 -04:00
Jan Bouwhuis
2720e2fade Fix translation growatt inverter temperature (#95775) 2023-07-03 15:23:42 -04:00
Marcel van der Veldt
d0e60f66fa Bump aioslimproto to 2.3.2 (#95754) 2023-07-03 15:23:41 -04:00
Mike Woudenberg
806b0cb1b6 Quality improvement on LOQED integration (#95725)
Remove generated translation
Raise error correctly
Remove obsolete consts
Remove callback, hass assignment and info log
Use name from LOQED API instead of default name
Correct entity name for assertion
2023-07-03 15:23:40 -04:00
Richard Kroegel
2e18641863 Bump bimmer_connected to 0.13.8 (#95660)
Co-authored-by: rikroe <rikroe@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-07-03 15:23:39 -04:00
Michael Hansen
e4e5ecf9b4 Ensure trigger sentences do not contain punctuation (#95633)
* Ensure trigger sentences do not contain punctuation

* Update homeassistant/components/conversation/trigger.py

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

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-07-03 15:23:38 -04:00
Michael Davie
1e66aaff0d Bump env_canada to v0.5.35 (#95497)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-07-03 15:23:37 -04:00
hidaris
ebb28973e0 Add Matter Climate support (#95434)
* Add Matter Climate support

* update set target temp and update callback

* remove print

* remove optional property

* Adjust the code to improve readability.

* add thermostat test

* Remove irrelevant cases in setting the target temperature.

* add temp range support

* update hvac action

* support adjust low high setpoint..

* support set hvac mode

* address some review feedback

* move some methods around

* dont discover climate in switch platform

* set some default values

* fix some of the tests

* fix some typos

* Update thermostat.json

* Update homeassistant/components/matter/climate.py

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

* Update homeassistant/components/matter/climate.py

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

* support heat_cool in hvac_modes

* address some review feedback

* handle hvac mode param in set temp service

* check hvac modes by featuremap

* add comment to thermostat feature class

* make ruff happy..

* use enum to enhance readability.

* use builtin feature bitmap

* fix target temp range and address some feedback

* use instance attribute instead of class attr

* make ruff happy...

* address feedback about single case

* add init docstring

* more test

* fix typo in tests

* make ruff happy

* fix hvac modes test

* test case for update callback

* remove optional check

* more tests

* more tests

* update all attributes in the update callback

* Update climate.py

* fix missing test

---------

Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-07-03 15:23:36 -04:00
Paulus Schoutsen
c260e787aa Bumped version to 2023.7.0b4 2023-07-02 22:50:36 -04:00
J. Nick Koston
fdd8489b93 Handle invalid utf-8 from the ESPHome dashboard (#95743)
If the yaml file has invalid utf-8, the config flow would raise an
unhandled exception. Allow the encryption key to be entered manually
in this case instead of a hard failure

fixes #92772
2023-07-02 22:50:32 -04:00
J. Nick Koston
a77fb14baf Bump python-kasa to 0.5.2 (#95716) 2023-07-02 22:50:31 -04:00
J. Nick Koston
98242b5d54 Bump zeroconf to 0.70.0 (#95714) 2023-07-02 22:50:30 -04:00
Maciej Bieniek
d38aab1607 Fix Shelly button unique_id migration (#95707)
Fix button unique_id migration
2023-07-02 22:50:29 -04:00
Aaron Bach
910aecb33b Fix implicit device name for SimpliSafe locks (#95681) 2023-07-02 22:50:28 -04:00
J. Nick Koston
ca20663c31 Handle missing or incorrect device name and unique id for ESPHome during manual add (#95678)
* Handle incorrect or missing device name for ESPHome noise encryption

If we did not have the device name during setup we could never
get the key from the dashboard. The device will send us
its name if we try encryption which allows us to find the
right key from the dashboard.

This should help get users unstuck when they change the key
and cannot get the device back online after deleting and
trying to set it up again manually

* bump lib to get name

* tweak

* reduce number of connections

* less connections when we know we will fail

* coverage shows it works but it does not

* add more coverage

* fix test

* bump again
2023-07-02 22:50:27 -04:00
Brandon Rothweiler
327a54e65a Upgrade pymazda to 0.3.9 (#95655) 2023-07-02 22:50:26 -04:00
Richard Kroegel
e907585b7f Add bmw connected drive region-specific scan interval (#95649)
Add region-specific scan interval

Co-authored-by: rikroe <rikroe@users.noreply.github.com>
2023-07-02 22:50:25 -04:00
dougiteixeira
3fa009b98c Fix source device when source entity is changed for Utility Meter (#95636)
* Fix source device when source entity is changed

* Update loop

* Complement and add comments in the test_change_device_source test

* Only clean up dev reg when options change

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-07-02 22:50:24 -04:00
Mick Vleeshouwer
226f1d7c73 Fix missing EntityDescription names in Overkiz (#95583)
* Fix labels

* Update homeassistant/components/overkiz/entity.py

* Check if description.name is string

---------

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2023-07-02 22:50:23 -04:00
Paulus Schoutsen
be49f90550 Bumped version to 2023.7.0b3 2023-06-30 15:08:35 -04:00
puddly
4993b6ee90 Fix ZHA startup issue with older Silicon Labs firmwares (#95642)
Bump ZHA dependencies
2023-06-30 15:08:28 -04:00
Bram Kragten
2de0b0f6ac Update frontend to 20230630.0 (#95635) 2023-06-30 15:08:27 -04:00
Marius
313e15a915 Update services.yaml (#95630)
take out 'templates accepted'
2023-06-30 15:08:26 -04:00
J. Nick Koston
11fd9ffa60 Bump aioesphomeapi to 15.0.1 (#95629)
fixes #87223 (the cases were the host gets too far behind,
not the cases were the esp8266 runs out of ram but thats
is not a core issue)
2023-06-30 15:08:25 -04:00
dougiteixeira
4192fdbdfd Fix device source for Utility Meter select (#95624)
Fix Device Source
2023-06-30 15:08:24 -04:00
dougiteixeira
d1e8513d63 Fix device source for Threshold (#95623)
Fix Device Source
2023-06-30 15:08:23 -04:00
dougiteixeira
9a14d437dd Fix device source for Riemann sum integral (#95622)
Fix Device Source
2023-06-30 15:08:22 -04:00
dougiteixeira
19cbedcc05 Fix device source for Derivative (#95621)
Fix Device Source
2023-06-30 15:08:21 -04:00
Joost Lekkerkerker
8a6d54237f Fix explicit device naming for integrations m-r (#95620)
Fix explicit device naming for m-r
2023-06-30 15:08:20 -04:00
Joost Lekkerkerker
70d3dc2ef8 Fix explicit device naming for integrations a-j (#95619)
Fix explicit device naming for a-j
2023-06-30 15:08:19 -04:00
Brett Adams
a8807f600b Explicity use device name in Advantage Air (#95611)
Explicity use device name
2023-06-30 15:08:18 -04:00
Brett Adams
73cb17cbf5 Fix Diagnostics in Advantage Air (#95608)
* Fix diag paths

* Fix key sand add redactions

* Name things better.

* Add super basic test

* Rename docstring

* Add snapshot

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-06-30 15:08:17 -04:00
J. Nick Koston
26d171fc92 Handle DNSError during radio browser setup (#95597)
```
2023-06-29 08:11:06.034 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry Radio Browser for radio_browser
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 390, in async_setup
    result = await component.async_setup_entry(hass, self)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/radio_browser/__init__.py", line 25, in async_setup_entry
    await radios.stats()
  File "/usr/local/lib/python3.11/site-packages/radios/radio_browser.py", line 124, in stats
    response = await self._request("stats")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/backoff/_async.py", line 151, in retry
    ret = await target(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/radios/radio_browser.py", line 73, in _request
    result = await resolver.query("_api._tcp.radio-browser.info", "SRV")
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
aiodns.error.DNSError: (12, 'Timeout while contacting DNS servers')
```
2023-06-30 15:08:16 -04:00
Dr. Drinovac
a4449d39f3 Use explicit naming in Sensibo climate entity (#95591)
* Use explicit naming in Sensibo climate entity

* Fix black

---------

Co-authored-by: G Johansson <goran.johansson@shiftit.se>
2023-06-30 15:08:15 -04:00
tronikos
a9b8e0077d Bump google-generativeai to 0.1.0 (#95515) 2023-06-30 15:08:14 -04:00
tronikos
97d9876cf7 Google Assistant SDK: Always enable conversation agent and support multiple languages (#93201)
* Enable agent and support multiple languages

* fix test
2023-06-30 15:08:13 -04:00
Paulus Schoutsen
0e89d0a26b Bumped version to 2023.7.0b2 2023-06-29 22:21:39 -04:00
puddly
03e7170080 Fix ZHA multi-PAN startup issue (#95595)
Bump ZHA dependencies
2023-06-29 22:21:34 -04:00
Paulus Schoutsen
c67f37d1be Wiz set name explicitely to None (#95593) 2023-06-29 22:21:34 -04:00
dougiteixeira
6aba1a5af3 Fix device source for Utility Meter (#95585)
* Fix Device Source

* Remove debug
2023-06-29 22:21:32 -04:00
J. Nick Koston
1cf472f4e3 Bump bluetooth-data-tools to 1.3.0 (#95576) 2023-06-29 22:21:31 -04:00
RenierM26
b8fc6e0c66 Ezviz IR string align with depreciation. (#95563) 2023-06-29 22:21:30 -04:00
Paulus Schoutsen
a04c98a703 Bumped version to 2023.7.0b1 2023-06-29 13:57:56 -04:00
Paulus Schoutsen
4255a2af15 Fix entity name for iBeacon and Roku (#95574)
* Fix entity nmae for iBeacon and Roku

* Roku remote too
2023-06-29 13:57:45 -04:00
Bram Kragten
c47a43c2b9 Update frontend to 20230629.0 (#95570) 2023-06-29 13:57:43 -04:00
Artem Draft
bcca1c91e6 Fix Android TV Remote entity naming (#95568)
Return None as Android TV Remote entity name
2023-06-29 13:57:42 -04:00
Paulus Schoutsen
9cd7034dbd Fix some entity naming (#95562) 2023-06-29 13:57:41 -04:00
Joost Lekkerkerker
ee72a952de Philips.js explicit device naming (#95551) 2023-06-29 13:57:39 -04:00
Luke
22e32bc737 Bump Roborock to 0.29.2 (#95549)
* init work

* fix tests
2023-06-29 13:57:34 -04:00
J. Nick Koston
2a42622de9 Fix manual specification of multiple advertise_ip with HomeKit (#95548)
fixes #95508
2023-06-29 13:57:33 -04:00
Joost Lekkerkerker
8f88b710f0 Use explicit naming in Nest (#95532) 2023-06-29 13:57:30 -04:00
Joost Lekkerkerker
1df12e8771 Use explicit naming in workday sensor (#95531) 2023-06-29 13:57:29 -04:00
Franck Nijhof
129fee09d3 Bump breaking version for YAML features ADR-0021 (#95525) 2023-06-29 13:57:28 -04:00
Franck Nijhof
61ab84bf04 Revert "Remove Workday YAML configuration (#94102)" (#95524) 2023-06-29 13:57:25 -04:00
Franck Nijhof
4f99a71f61 Revert "Remove snapcast YAML configuration (#93547)" (#95523) 2023-06-29 13:57:23 -04:00
Franck Nijhof
f165357772 Revert "Remove qbittorrent YAML configuration (#93548)" (#95522) 2023-06-29 13:57:19 -04:00
Franck Nijhof
c156951925 Revert "Remove Brottsplatskartan YAML configuration (#94101)" (#95521) 2023-06-29 13:57:15 -04:00
Franck Nijhof
612f33e372 Mark text input required for conversation.process service (#95520) 2023-06-29 13:57:14 -04:00
Marcel van der Veldt
2b274b4e95 Bump Matter Server to 3.6.3 (#95519) 2023-06-29 13:57:11 -04:00
Joost Lekkerkerker
2ac5bb46b1 Add explicit device name to Broadlink (#95516) 2023-06-29 13:57:09 -04:00
Joost Lekkerkerker
c4a46294cc Add explicit device name to Roborock (#95513) 2023-06-29 13:55:47 -04:00
Joost Lekkerkerker
cda5ee5814 Add explicit device name to Switchbot (#95512) 2023-06-29 13:55:46 -04:00
Joost Lekkerkerker
698333f894 Add explicit device name to Tuya (#95511)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2023-06-29 13:55:45 -04:00
Joost Lekkerkerker
b93ceca804 Add explicit device name to Spotify (#95509) 2023-06-29 13:55:44 -04:00
Allen Porter
286cff314a Limit fields returned for the list events service (#95506)
* Limit fields returned for the list events service

* Update websocket tests and fix bugs in response fields

* Omit 'None' fields in the list events response
2023-06-29 13:55:43 -04:00
Raman Gupta
d44ef07082 Fix binary sensor device trigger for lock class (#95505) 2023-06-29 13:55:42 -04:00
Joost Lekkerkerker
8dd2e21d0b Fix YouTube coordinator bug (#95492)
Fix coordinator bug
2023-06-29 13:55:41 -04:00
Matthias Alphart
f55ada5d61 Add reload service to KNX (#95489) 2023-06-29 13:55:39 -04:00
Brandon Rothweiler
1f72a5b1fe Remove incompatible button entities for Mazda electric vehicles (#95486)
* Remove incompatible button entities for Mazda electric vehicles

* Update tests
2023-06-29 13:53:53 -04:00
Evan Jarrett
71b192c072 Update matter locks to support pin code validation (#95481)
Update matter locks to support PINCode validation based on device attributes
2023-06-29 13:52:06 -04:00
Michael Hansen
17c64ed791 Add targeted entities to sentence debug API (#95480)
* Return targets with debug sentence API

* Update test

* Update homeassistant/components/conversation/__init__.py

* Include area/domain in test sentences

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-06-29 13:52:05 -04:00
puddly
4e940df224 Bump ZHA dependencies (#95478)
* Bump ZHA dependencies

* Account for new EZSP metadata keys
2023-06-29 13:52:04 -04:00
Marcel van der Veldt
a23c0e12f1 Fix Matter entity names (#95477) 2023-06-29 13:51:59 -04:00
Bram Kragten
be22195cf4 Add conversation agent selector, use in conversation.process service (#95462) 2023-06-29 13:44:13 -04:00
Michael Hansen
a39ef03ff5 Disconnect VoIP on RTCP bye message (#95452)
* Support RTCP BYE message

* Make RtcpState optional
2023-06-29 13:44:12 -04:00
Barry Williams
1687ff1f28 Add Update Entity for Linn devices (#95217)
* added update entity for Linn devices

* Update homeassistant/components/openhome/update.py

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

* use parent methods for version attributes

* fixed issue with mocking openhome device

* Update homeassistant/components/openhome/update.py

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

* update entity name in tests

---------

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2023-06-29 13:44:09 -04:00
Franck Nijhof
28a5e4735f Bumped version to 2023.7.0b0 2023-06-28 20:45:45 +02:00
283 changed files with 5221 additions and 947 deletions

View File

@@ -182,7 +182,6 @@ omit =
homeassistant/components/crownstone/listeners.py
homeassistant/components/cups/sensor.py
homeassistant/components/currencylayer/sensor.py
homeassistant/components/daikin/__init__.py
homeassistant/components/daikin/climate.py
homeassistant/components/daikin/sensor.py
homeassistant/components/daikin/switch.py

View File

@@ -34,6 +34,7 @@ class AbodeAlarm(AbodeDevice, alarm.AlarmControlPanelEntity):
"""An alarm_control_panel implementation for Abode."""
_attr_icon = ICON
_attr_name = None
_attr_code_arm_required = False
_attr_supported_features = (
AlarmControlPanelEntityFeature.ARM_HOME

View File

@@ -39,6 +39,7 @@ class AbodeCamera(AbodeDevice, Camera):
"""Representation of an Abode camera."""
_device: AbodeCam
_attr_name = None
def __init__(self, data: AbodeSystem, device: AbodeDev, event: Event) -> None:
"""Initialize the Abode device."""

View File

@@ -29,6 +29,7 @@ class AbodeCover(AbodeDevice, CoverEntity):
"""Representation of an Abode cover."""
_device: AbodeCV
_attr_name = None
@property
def is_closed(self) -> bool:

View File

@@ -42,6 +42,7 @@ class AbodeLight(AbodeDevice, LightEntity):
"""Representation of an Abode light."""
_device: AbodeLT
_attr_name = None
def turn_on(self, **kwargs: Any) -> None:
"""Turn on the light."""

View File

@@ -29,6 +29,7 @@ class AbodeLock(AbodeDevice, LockEntity):
"""Representation of an Abode lock."""
_device: AbodeLK
_attr_name = None
def lock(self, **kwargs: Any) -> None:
"""Lock the device."""

View File

@@ -53,7 +53,6 @@ class AbodeSensor(AbodeDevice, SensorEntity):
"""A sensor implementation for Abode devices."""
_device: AbodeSense
_attr_has_entity_name = True
def __init__(
self,

View File

@@ -44,6 +44,7 @@ class AbodeSwitch(AbodeDevice, SwitchEntity):
"""Representation of an Abode switch."""
_device: AbodeSW
_attr_name = None
def turn_on(self, **kwargs: Any) -> None:
"""Turn on the device."""

View File

@@ -90,6 +90,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
_attr_target_temperature_step = PRECISION_WHOLE
_attr_max_temp = 32
_attr_min_temp = 16
_attr_name = None
_attr_hvac_modes = [
HVACMode.OFF,

View File

@@ -9,17 +9,30 @@ from homeassistant.core import HomeAssistant
from .const import DOMAIN as ADVANTAGE_AIR_DOMAIN
TO_REDACT = ["dealerPhoneNumber", "latitude", "logoPIN", "longitude", "postCode"]
TO_REDACT = [
"dealerPhoneNumber",
"latitude",
"logoPIN",
"longitude",
"postCode",
"rid",
"deviceNames",
"deviceIds",
"deviceIdsV2",
"backupId",
]
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
data = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]["coordinator"].data
data = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id].coordinator.data
# Return only the relevant children
return {
"aircons": data["aircons"],
"aircons": data.get("aircons"),
"myLights": data.get("myLights"),
"myThings": data.get("myThings"),
"system": async_redact_data(data["system"], TO_REDACT),
}

View File

@@ -84,6 +84,8 @@ class AdvantageAirZoneEntity(AdvantageAirAcEntity):
class AdvantageAirThingEntity(AdvantageAirEntity):
"""Parent class for Advantage Air Things Entities."""
_attr_name = None
def __init__(self, instance: AdvantageAirData, thing: dict[str, Any]) -> None:
"""Initialize common aspects of an Advantage Air Things entity."""
super().__init__(instance)

View File

@@ -41,6 +41,7 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity):
"""Representation of Advantage Air Light."""
_attr_supported_color_modes = {ColorMode.ONOFF}
_attr_name = None
def __init__(self, instance: AdvantageAirData, light: dict[str, Any]) -> None:
"""Initialize an Advantage Air Light."""

View File

@@ -16,6 +16,7 @@ from .const import DOMAIN
class AndroidTVRemoteBaseEntity(Entity):
"""Android TV Remote Base Entity."""
_attr_name = None
_attr_has_entity_name = True
_attr_should_poll = False

View File

@@ -80,6 +80,7 @@ class AnthemAVR(MediaPlayerEntity):
self._attr_name = f"zone {zone_number}"
self._attr_unique_id = f"{mac_address}_{zone_number}"
else:
self._attr_name = None
self._attr_unique_id = mac_address
self._attr_device_info = DeviceInfo(

View File

@@ -16,7 +16,24 @@
"_touch-able._tcp.local.",
"_appletv-v2._tcp.local.",
"_hscp._tcp.local.",
"_airplay._tcp.local.",
{
"type": "_airplay._tcp.local.",
"properties": {
"model": "appletv*"
}
},
{
"type": "_airplay._tcp.local.",
"properties": {
"model": "audioaccessory*"
}
},
{
"type": "_airplay._tcp.local.",
"properties": {
"am": "airport*"
}
},
{
"type": "_raop._tcp.local.",
"properties": {

View File

@@ -112,8 +112,8 @@ ENTITY_TRIGGERS = {
{CONF_TYPE: CONF_NO_LIGHT},
],
BinarySensorDeviceClass.LOCK: [
{CONF_TYPE: CONF_LOCKED},
{CONF_TYPE: CONF_NOT_LOCKED},
{CONF_TYPE: CONF_LOCKED},
],
BinarySensorDeviceClass.MOISTURE: [
{CONF_TYPE: CONF_MOIST},

View File

@@ -42,6 +42,7 @@ class BlinkSyncModule(AlarmControlPanelEntity):
_attr_icon = ICON
_attr_supported_features = AlarmControlPanelEntityFeature.ARM_AWAY
_attr_name = None
_attr_has_entity_name = True
def __init__(self, data, name, sync):
"""Initialize the alarm control panel."""

View File

@@ -58,13 +58,14 @@ async def async_setup_entry(
class BlinkBinarySensor(BinarySensorEntity):
"""Representation of a Blink binary sensor."""
_attr_has_entity_name = True
def __init__(
self, data, camera, description: BinarySensorEntityDescription
) -> None:
"""Initialize the sensor."""
self.data = data
self.entity_description = description
self._attr_name = f"{DOMAIN} {camera} {description.name}"
self._camera = data.cameras[camera]
self._attr_unique_id = f"{self._camera.serial}-{description.key}"
self._attr_device_info = DeviceInfo(

View File

@@ -38,6 +38,7 @@ async def async_setup_entry(
class BlinkCamera(Camera):
"""An implementation of a Blink Camera."""
_attr_has_entity_name = True
_attr_name = None
def __init__(self, data, name, camera):

View File

@@ -18,7 +18,7 @@
"bleak-retry-connector==3.0.2",
"bluetooth-adapters==0.15.3",
"bluetooth-auto-recovery==1.2.0",
"bluetooth-data-tools==1.2.0",
"bluetooth-data-tools==1.3.0",
"dbus-fast==1.86.0"
]
}

View File

@@ -21,3 +21,9 @@ UNIT_MAP = {
"LITERS": UnitOfVolume.LITERS,
"GALLONS": UnitOfVolume.GALLONS,
}
SCAN_INTERVALS = {
"china": 300,
"north_america": 600,
"rest_of_world": 300,
}

View File

@@ -15,10 +15,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import CONF_GCID, CONF_READ_ONLY, CONF_REFRESH_TOKEN, DOMAIN
from .const import CONF_GCID, CONF_READ_ONLY, CONF_REFRESH_TOKEN, DOMAIN, SCAN_INTERVALS
DEFAULT_SCAN_INTERVAL_SECONDS = 300
SCAN_INTERVAL = timedelta(seconds=DEFAULT_SCAN_INTERVAL_SECONDS)
_LOGGER = logging.getLogger(__name__)
@@ -50,7 +48,7 @@ class BMWDataUpdateCoordinator(DataUpdateCoordinator[None]):
hass,
_LOGGER,
name=f"{DOMAIN}-{entry.data['username']}",
update_interval=SCAN_INTERVAL,
update_interval=timedelta(seconds=SCAN_INTERVALS[entry.data[CONF_REGION]]),
)
async def _async_update_data(self) -> None:

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive",
"iot_class": "cloud_polling",
"loggers": ["bimmer_connected"],
"requirements": ["bimmer-connected==0.13.7"]
"requirements": ["bimmer-connected==0.13.8"]
}

View File

@@ -107,6 +107,7 @@ class BroadlinkRemote(BroadlinkEntity, RemoteEntity, RestoreEntity):
"""Representation of a Broadlink remote."""
_attr_has_entity_name = True
_attr_name = None
def __init__(self, device, codes, flags):
"""Initialize the remote."""

View File

@@ -221,6 +221,7 @@ class BroadlinkSP2Switch(BroadlinkSP1Switch):
_attr_assumed_state = False
_attr_has_entity_name = True
_attr_name = None
def __init__(self, device, *args, **kwargs):
"""Initialize the switch."""

View File

@@ -34,6 +34,21 @@ class BPKConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
VERSION = 1
async def async_step_import(self, config: dict[str, Any]) -> FlowResult:
"""Import a configuration from config.yaml."""
if config.get(CONF_LATITUDE):
config[CONF_LOCATION] = {
CONF_LATITUDE: config[CONF_LATITUDE],
CONF_LONGITUDE: config[CONF_LONGITUDE],
}
if not config.get(CONF_AREA):
config[CONF_AREA] = "none"
else:
config[CONF_AREA] = config[CONF_AREA][0]
return await self.async_step_user(user_input=config)
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:

View File

@@ -5,19 +5,62 @@ from collections import defaultdict
from datetime import timedelta
from brottsplatskartan import ATTRIBUTION, BrottsplatsKartan
import voluptuous as vol
from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.components.sensor import (
PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA,
SensorEntity,
)
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import CONF_APP_ID, CONF_AREA, DOMAIN, LOGGER
from .const import AREAS, CONF_APP_ID, CONF_AREA, DEFAULT_NAME, DOMAIN, LOGGER
SCAN_INTERVAL = timedelta(minutes=30)
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
{
vol.Inclusive(CONF_LATITUDE, "coordinates"): cv.latitude,
vol.Inclusive(CONF_LONGITUDE, "coordinates"): cv.longitude,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_AREA, default=[]): vol.All(cv.ensure_list, [vol.In(AREAS)]),
}
)
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Brottsplatskartan platform."""
async_create_issue(
hass,
DOMAIN,
"deprecated_yaml",
breaks_in_ha_version="2023.11.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml",
)
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=config,
)
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
@@ -40,6 +83,7 @@ class BrottsplatskartanSensor(SensorEntity):
_attr_attribution = ATTRIBUTION
_attr_has_entity_name = True
_attr_name = None
def __init__(self, bpk: BrottsplatsKartan, name: str, entry_id: str) -> None:
"""Initialize the Brottsplatskartan sensor."""

View File

@@ -16,6 +16,12 @@
}
}
},
"issues": {
"deprecated_yaml": {
"title": "The Brottsplatskartan YAML configuration is being removed",
"description": "Configuring Brottsplatskartan using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the Brottsplatskartan YAML configuration from your configuration.yaml file and restart Home Assistant to fix this issue."
}
},
"selector": {
"areas": {
"options": {

View File

@@ -71,6 +71,7 @@ class BSBLANClimate(
"""Defines a BSBLAN climate device."""
_attr_has_entity_name = True
_attr_name = None
# Determine preset modes
_attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE

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.12.0"]
"requirements": ["bthome-ble==2.12.1"]
}

View File

@@ -301,55 +301,55 @@
"name": "Condition 1d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::condition::state::clear%]",
"cloudy": "[%key:component::buienradar::entity::sensor::condition::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::condition::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::condition::state::rainy%]",
"snowy": "[%key:component::buienradar::entity::sensor::condition::state::snowy%]",
"lightning": "[%key:component::buienradar::entity::sensor::condition::state::lightning%]"
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"condition_2d": {
"name": "Condition 2d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::condition::state::clear%]",
"cloudy": "[%key:component::buienradar::entity::sensor::condition::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::condition::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::condition::state::rainy%]",
"snowy": "[%key:component::buienradar::entity::sensor::condition::state::snowy%]",
"lightning": "[%key:component::buienradar::entity::sensor::condition::state::lightning%]"
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"condition_3d": {
"name": "Condition 3d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::condition::state::clear%]",
"cloudy": "[%key:component::buienradar::entity::sensor::condition::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::condition::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::condition::state::rainy%]",
"snowy": "[%key:component::buienradar::entity::sensor::condition::state::snowy%]",
"lightning": "[%key:component::buienradar::entity::sensor::condition::state::lightning%]"
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"condition_4d": {
"name": "Condition 4d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::condition::state::clear%]",
"cloudy": "[%key:component::buienradar::entity::sensor::condition::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::condition::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::condition::state::rainy%]",
"snowy": "[%key:component::buienradar::entity::sensor::condition::state::snowy%]",
"lightning": "[%key:component::buienradar::entity::sensor::condition::state::lightning%]"
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"condition_5d": {
"name": "Condition 5d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::condition::state::clear%]",
"cloudy": "[%key:component::buienradar::entity::sensor::condition::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::condition::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::condition::state::rainy%]",
"snowy": "[%key:component::buienradar::entity::sensor::condition::state::snowy%]",
"lightning": "[%key:component::buienradar::entity::sensor::condition::state::lightning%]"
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"conditioncode_1d": {
@@ -371,76 +371,76 @@
"name": "Detailed condition 1d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::clear%]",
"partlycloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy%]",
"partlycloudy": "[%key:component::weather::entity_component::_::state::partlycloudy%]",
"partlycloudy-fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-fog%]",
"partlycloudy-light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-rain%]",
"partlycloudy-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-rain%]",
"cloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::rainy%]",
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-rain%]",
"light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-snow%]",
"partlycloudy-light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-snow%]",
"partlycloudy-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-snow%]",
"partlycloudy-lightning": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-lightning%]",
"snowy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::snowy%]",
"snowy-rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::snowy-rainy%]",
"lightning": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::lightning%]"
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"snowy-rainy": "[%key:component::weather::entity_component::_::state::snowy-rainy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"conditiondetailed_2d": {
"name": "Detailed condition 2d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::clear%]",
"partlycloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy%]",
"partlycloudy": "[%key:component::weather::entity_component::_::state::partlycloudy%]",
"partlycloudy-fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-fog%]",
"partlycloudy-light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-rain%]",
"partlycloudy-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-rain%]",
"cloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::rainy%]",
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-rain%]",
"light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-snow%]",
"partlycloudy-light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-snow%]",
"partlycloudy-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-snow%]",
"partlycloudy-lightning": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-lightning%]",
"snowy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::snowy%]",
"snowy-rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::snowy-rainy%]",
"lightning": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::lightning%]"
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"snowy-rainy": "[%key:component::weather::entity_component::_::state::snowy-rainy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"conditiondetailed_3d": {
"name": "Detailed condition 3d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::clear%]",
"partlycloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy%]",
"partlycloudy": "[%key:component::weather::entity_component::_::state::partlycloudy%]",
"partlycloudy-fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-fog%]",
"partlycloudy-light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-rain%]",
"partlycloudy-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-rain%]",
"cloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::rainy%]",
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-rain%]",
"light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-snow%]",
"partlycloudy-light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-snow%]",
"partlycloudy-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-snow%]",
"partlycloudy-lightning": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-lightning%]",
"snowy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::snowy%]",
"snowy-rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::snowy-rainy%]",
"lightning": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::lightning%]"
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"snowy-rainy": "[%key:component::weather::entity_component::_::state::snowy-rainy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"conditiondetailed_4d": {
"name": "Detailed condition 4d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::clear%]",
"partlycloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy%]",
"partlycloudy": "[%key:component::weather::entity_component::_::state::partlycloudy%]",
"partlycloudy-fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-fog%]",
"partlycloudy-light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-rain%]",
"partlycloudy-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-rain%]",
"cloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::rainy%]",
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-rain%]",
"light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-snow%]",
"partlycloudy-light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-snow%]",
@@ -455,21 +455,21 @@
"name": "Detailed condition 5d",
"state": {
"clear": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::clear%]",
"partlycloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy%]",
"partlycloudy": "[%key:component::weather::entity_component::_::state::partlycloudy%]",
"partlycloudy-fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-fog%]",
"partlycloudy-light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-rain%]",
"partlycloudy-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-rain%]",
"cloudy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::cloudy%]",
"fog": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::fog%]",
"rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::rainy%]",
"cloudy": "[%key:component::weather::entity_component::_::state::cloudy%]",
"fog": "[%key:component::weather::entity_component::_::state::fog%]",
"rainy": "[%key:component::weather::entity_component::_::state::rainy%]",
"light-rain": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-rain%]",
"light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::light-snow%]",
"partlycloudy-light-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-light-snow%]",
"partlycloudy-snow": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-snow%]",
"partlycloudy-lightning": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::partlycloudy-lightning%]",
"snowy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::snowy%]",
"snowy-rainy": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::snowy-rainy%]",
"lightning": "[%key:component::buienradar::entity::sensor::conditiondetailed::state::lightning%]"
"snowy": "[%key:component::weather::entity_component::_::state::snowy%]",
"snowy-rainy": "[%key:component::weather::entity_component::_::state::snowy-rainy%]",
"lightning": "[%key:component::weather::entity_component::_::state::lightning%]"
}
},
"conditionexact_1d": {

View File

@@ -60,6 +60,7 @@ from .const import (
EVENT_TIME_FIELDS,
EVENT_TYPES,
EVENT_UID,
LIST_EVENT_FIELDS,
CalendarEntityFeature,
)
@@ -263,8 +264,8 @@ SERVICE_LIST_EVENTS_SCHEMA: Final = vol.All(
cv.has_at_most_one_key(EVENT_END_DATETIME, EVENT_DURATION),
cv.make_entity_service_schema(
{
vol.Optional(EVENT_START_DATETIME): datetime.datetime,
vol.Optional(EVENT_END_DATETIME): datetime.datetime,
vol.Optional(EVENT_START_DATETIME): cv.datetime,
vol.Optional(EVENT_END_DATETIME): cv.datetime,
vol.Optional(EVENT_DURATION): vol.All(
cv.time_period, cv.positive_timedelta
),
@@ -415,6 +416,17 @@ def _api_event_dict_factory(obj: Iterable[tuple[str, Any]]) -> dict[str, Any]:
return result
def _list_events_dict_factory(
obj: Iterable[tuple[str, Any]]
) -> dict[str, JsonValueType]:
"""Convert CalendarEvent dataclass items to dictionary of attributes."""
return {
name: value
for name, value in _event_dict_factory(obj).items()
if name in LIST_EVENT_FIELDS and value is not None
}
def _get_datetime_local(
dt_or_d: datetime.datetime | datetime.date,
) -> datetime.datetime:
@@ -781,10 +793,12 @@ async def async_list_events_service(
end = start + service_call.data[EVENT_DURATION]
else:
end = service_call.data[EVENT_END_DATETIME]
calendar_event_list = await calendar.async_get_events(calendar.hass, start, end)
events: list[JsonValueType] = [
dataclasses.asdict(event) for event in calendar_event_list
]
calendar_event_list = await calendar.async_get_events(
calendar.hass, dt_util.as_local(start), dt_util.as_local(end)
)
return {
"events": events,
"events": [
dataclasses.asdict(event, dict_factory=_list_events_dict_factory)
for event in calendar_event_list
]
}

View File

@@ -41,3 +41,12 @@ EVENT_TIME_FIELDS = {
}
EVENT_TYPES = "event_types"
EVENT_DURATION = "duration"
# Fields for the list events service
LIST_EVENT_FIELDS = {
"start",
"end",
EVENT_SUMMARY,
EVENT_DESCRIPTION,
EVENT_LOCATION,
}

View File

@@ -8,10 +8,10 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_HOST,
CONF_PORT,
EVENT_HOMEASSISTANT_STARTED,
Platform,
)
from homeassistant.core import CoreState, HomeAssistant
from homeassistant.core import HomeAssistant
from homeassistant.helpers.start import async_at_started
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DEFAULT_PORT, DOMAIN
@@ -38,19 +38,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if entry.unique_id is None:
hass.config_entries.async_update_entry(entry, unique_id=f"{host}:{port}")
async def async_finish_startup(_):
async def _async_finish_startup(_):
await coordinator.async_refresh()
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
if hass.state == CoreState.running:
await async_finish_startup(None)
else:
entry.async_on_unload(
hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STARTED, async_finish_startup
)
)
async_at_started(hass, _async_finish_startup)
return True

View File

@@ -70,7 +70,7 @@ async def async_setup_platform(
hass,
DOMAIN,
"deprecated_yaml_binary_sensor",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_platform_yaml",

View File

@@ -73,7 +73,7 @@ async def async_setup_platform(
hass,
DOMAIN,
"deprecated_yaml_cover",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_platform_yaml",

View File

@@ -43,7 +43,7 @@ def get_service(
hass,
DOMAIN,
"deprecated_yaml_notify",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_platform_yaml",

View File

@@ -74,7 +74,7 @@ async def async_setup_platform(
hass,
DOMAIN,
"deprecated_yaml_sensor",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_platform_yaml",

View File

@@ -74,7 +74,7 @@ async def async_setup_platform(
hass,
DOMAIN,
"deprecated_yaml_switch",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_platform_yaml",

View File

@@ -8,6 +8,7 @@ import logging
import re
from typing import Any, Literal
from hassil.recognize import RecognizeResult
import voluptuous as vol
from homeassistant import core
@@ -353,6 +354,10 @@ async def websocket_hass_agent_debug(
}
for entity_key, entity in result.entities.items()
},
"targets": {
state.entity_id: {"matched": is_matched}
for state, is_matched in _get_debug_targets(hass, result)
},
}
if result is not None
else None
@@ -362,6 +367,49 @@ async def websocket_hass_agent_debug(
)
def _get_debug_targets(
hass: HomeAssistant,
result: RecognizeResult,
) -> Iterable[tuple[core.State, bool]]:
"""Yield state/is_matched pairs for a hassil recognition."""
entities = result.entities
name: str | None = None
area_name: str | None = None
domains: set[str] | None = None
device_classes: set[str] | None = None
state_names: set[str] | None = None
if "name" in entities:
name = str(entities["name"].value)
if "area" in entities:
area_name = str(entities["area"].value)
if "domain" in entities:
domains = set(cv.ensure_list(entities["domain"].value))
if "device_class" in entities:
device_classes = set(cv.ensure_list(entities["device_class"].value))
if "state" in entities:
# HassGetState only
state_names = set(cv.ensure_list(entities["state"].value))
states = intent.async_match_states(
hass,
name=name,
area_name=area_name,
domains=domains,
device_classes=device_classes,
)
for state in states:
# For queries, a target is "matched" based on its state
is_matched = (state_names is None) or (state.state in state_names)
yield state, is_matched
class ConversationProcessView(http.HomeAssistantView):
"""View to process text."""

View File

@@ -7,6 +7,7 @@ process:
name: Text
description: Transcribed text
example: Turn all lights on
required: true
selector:
text:
language:
@@ -20,4 +21,4 @@ process:
description: Assist engine to process your request
example: homeassistant
selector:
text:
conversation_agent:

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
from typing import Any
from hassil.recognize import PUNCTUATION
import voluptuous as vol
from homeassistant.const import CONF_COMMAND, CONF_PLATFORM
@@ -15,10 +16,22 @@ from . import HOME_ASSISTANT_AGENT, _get_agent_manager
from .const import DOMAIN
from .default_agent import DefaultAgent
def has_no_punctuation(value: list[str]) -> list[str]:
"""Validate result does not contain punctuation."""
for sentence in value:
if PUNCTUATION.search(sentence):
raise vol.Invalid("sentence should not contain punctuation")
return value
TRIGGER_SCHEMA = cv.TRIGGER_BASE_SCHEMA.extend(
{
vol.Required(CONF_PLATFORM): DOMAIN,
vol.Required(CONF_COMMAND): vol.All(cv.ensure_list, [cv.string]),
vol.Required(CONF_COMMAND): vol.All(
cv.ensure_list, [cv.string], has_no_punctuation
),
}
)

View File

@@ -292,7 +292,7 @@ class Counter(collection.CollectionEntity, RestoreEntity):
self.hass,
DOMAIN,
"deprecated_configure_service",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=True,
is_persistent=True,
severity=IssueSeverity.WARNING,

View File

@@ -15,8 +15,9 @@ from homeassistant.const import (
CONF_UUID,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
@@ -52,6 +53,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if not daikin_api:
return False
await async_migrate_unique_id(hass, entry, daikin_api)
hass.data.setdefault(DOMAIN, {}).update({entry.entry_id: daikin_api})
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
@@ -67,7 +70,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return unload_ok
async def daikin_api_setup(hass, host, key, uuid, password):
async def daikin_api_setup(hass: HomeAssistant, host, key, uuid, password):
"""Create a Daikin instance only once."""
session = async_get_clientsession(hass)
@@ -127,3 +130,82 @@ class DaikinApi:
name=info.get("name"),
sw_version=info.get("ver", "").replace("_", "."),
)
async def async_migrate_unique_id(
hass: HomeAssistant, config_entry: ConfigEntry, api: DaikinApi
) -> None:
"""Migrate old entry."""
dev_reg = dr.async_get(hass)
old_unique_id = config_entry.unique_id
new_unique_id = api.device.mac
new_name = api.device.values["name"]
@callback
def _update_unique_id(entity_entry: er.RegistryEntry) -> dict[str, str] | None:
"""Update unique ID of entity entry."""
return update_unique_id(entity_entry, new_unique_id)
if new_unique_id == old_unique_id:
return
# Migrate devices
for device_entry in dr.async_entries_for_config_entry(
dev_reg, config_entry.entry_id
):
for connection in device_entry.connections:
if connection[1] == old_unique_id:
new_connections = {
(CONNECTION_NETWORK_MAC, dr.format_mac(new_unique_id))
}
_LOGGER.debug(
"Migrating device %s connections to %s",
device_entry.name,
new_connections,
)
dev_reg.async_update_device(
device_entry.id,
merge_connections=new_connections,
)
if device_entry.name is None:
_LOGGER.debug(
"Migrating device name to %s",
new_name,
)
dev_reg.async_update_device(
device_entry.id,
name=new_name,
)
# Migrate entities
await er.async_migrate_entries(hass, config_entry.entry_id, _update_unique_id)
new_data = {**config_entry.data, KEY_MAC: dr.format_mac(new_unique_id)}
hass.config_entries.async_update_entry(
config_entry, unique_id=new_unique_id, data=new_data
)
@callback
def update_unique_id(
entity_entry: er.RegistryEntry, unique_id: str
) -> dict[str, str] | None:
"""Update unique ID of entity entry."""
if entity_entry.unique_id.startswith(unique_id):
# Already correct, nothing to do
return None
unique_id_parts = entity_entry.unique_id.split("-")
unique_id_parts[0] = unique_id
entity_new_unique_id = "-".join(unique_id_parts)
_LOGGER.debug(
"Migrating entity %s from %s to new id %s",
entity_entry.entity_id,
entity_entry.unique_id,
entity_new_unique_id,
)
return {"new_unique_id": entity_new_unique_id}

View File

@@ -7,6 +7,6 @@
"iot_class": "local_polling",
"loggers": ["pydaikin"],
"quality_scale": "platinum",
"requirements": ["pydaikin==2.9.0"],
"requirements": ["pydaikin==2.10.5"],
"zeroconf": ["_dkapi._tcp.local."]
}

View File

@@ -42,7 +42,7 @@ async def async_setup_entry(
[
DaikinZoneSwitch(daikin_api, zone_id)
for zone_id, zone in enumerate(zones)
if zone != ("-", "0")
if zone[0] != "-"
]
)
if daikin_api.device.support_advanced_modes:

View File

@@ -5,5 +5,5 @@
"documentation": "https://www.home-assistant.io/integrations/delijn",
"iot_class": "cloud_polling",
"loggers": ["pydelijn"],
"requirements": ["pydelijn==1.0.0"]
"requirements": ["pydelijn==1.1.0"]
}

View File

@@ -108,6 +108,7 @@ async def async_setup_entry(
):
device_info = DeviceInfo(
identifiers=device.identifiers,
connections=device.connections,
)
else:
device_info = None

View File

@@ -726,6 +726,10 @@ class DeviceTracker:
class Device(RestoreEntity):
"""Base class for a tracked device."""
# This entity is legacy and does not have a platform.
# We can't fix this easily without breaking changes.
_no_platform_reported = True
host_name: str | None = None
location_name: str | None = None
gps: GPSType | None = None

View File

@@ -8,6 +8,8 @@ from .devolo_device import DevoloDeviceEntity
class DevoloMultiLevelSwitchDeviceEntity(DevoloDeviceEntity):
"""Representation of a multi level switch device within devolo Home Control. Something like a dimmer or a thermostat."""
_attr_name = None
def __init__(
self, homecontrol: HomeControl, device_instance: Zwave, element_uid: str
) -> None:

View File

@@ -41,6 +41,8 @@ async def async_setup_entry(
class DevoloSwitch(DevoloDeviceEntity, SwitchEntity):
"""Representation of a switch."""
_attr_name = None
def __init__(
self, homecontrol: HomeControl, device_instance: Zwave, element_uid: str
) -> None:

View File

@@ -60,7 +60,6 @@ class ServiceDetails(NamedTuple):
SERVICE_HANDLERS = {
SERVICE_ENIGMA2: ServiceDetails("media_player", "enigma2"),
"yamaha": ServiceDetails("media_player", "yamaha"),
"openhome": ServiceDetails("media_player", "openhome"),
"bluesound": ServiceDetails("media_player", "bluesound"),
}
@@ -87,6 +86,7 @@ MIGRATED_SERVICE_HANDLERS = [
SERVICE_MOBILE_APP,
SERVICE_NETGEAR,
SERVICE_OCTOPRINT,
"openhome",
"philips_hue",
SERVICE_SAMSUNG_PRINTER,
"sonos",

View File

@@ -91,7 +91,7 @@ async def async_setup_platform(
hass,
DOMAIN,
"deprecated_yaml",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml",

View File

@@ -47,6 +47,7 @@ async def async_setup_entry(
class ElgatoLight(ElgatoEntity, LightEntity):
"""Defines an Elgato Light."""
_attr_name = None
_attr_min_mireds = 143
_attr_max_mireds = 344

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.34"]
"requirements": ["env-canada==0.5.35"]
}

View File

@@ -76,6 +76,7 @@ class ControllerEntity(ClimateEntity):
_attr_fan_modes = list(_HA_FAN_TO_ESCEA)
_attr_has_entity_name = True
_attr_name = None
_attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
_attr_icon = ICON
_attr_precision = PRECISION_WHOLE

View File

@@ -388,6 +388,7 @@ async def async_setup_entry( # noqa: C901
assert cli.api_version is not None
entry_data.api_version = cli.api_version
entry_data.available = True
entry_data.expected_disconnect = True
if entry_data.device_info.name:
reconnect_logic.name = entry_data.device_info.name

View File

@@ -33,6 +33,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .entity import (
EsphomeEntity,
esphome_state_property,
platform_async_setup_entry,
)
from .enum_mapper import EsphomeEnumMapper
@@ -111,6 +112,7 @@ class EsphomeAlarmControlPanel(
self._attr_code_arm_required = bool(static_info.requires_code_to_arm)
@property
@esphome_state_property
def state(self) -> str | None:
"""Return the state of the device."""
return _ESPHOME_ACP_STATE_TO_HASS_STATE.from_esphome(self._state.state)

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
from collections import OrderedDict
from collections.abc import Mapping
import json
import logging
from typing import Any
@@ -33,13 +34,15 @@ from .const import (
DEFAULT_NEW_CONFIG_ALLOW_ALLOW_SERVICE_CALLS,
DOMAIN,
)
from .dashboard import async_get_dashboard, async_set_dashboard_info
from .dashboard import async_get_or_create_dashboard_manager, async_set_dashboard_info
ERROR_REQUIRES_ENCRYPTION_KEY = "requires_encryption_key"
ERROR_INVALID_ENCRYPTION_KEY = "invalid_psk"
ESPHOME_URL = "https://esphome.io/"
_LOGGER = logging.getLogger(__name__)
ZERO_NOISE_PSK = "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA="
class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle a esphome config flow."""
@@ -149,11 +152,22 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
async def _async_try_fetch_device_info(self) -> FlowResult:
error = await self.fetch_device_info()
if (
error == ERROR_REQUIRES_ENCRYPTION_KEY
and await self._retrieve_encryption_key_from_dashboard()
):
error = await self.fetch_device_info()
if error == ERROR_REQUIRES_ENCRYPTION_KEY:
if not self._device_name and not self._noise_psk:
# If device name is not set we can send a zero noise psk
# to get the device name which will allow us to populate
# the device name and hopefully get the encryption key
# from the dashboard.
self._noise_psk = ZERO_NOISE_PSK
error = await self.fetch_device_info()
self._noise_psk = None
if (
self._device_name
and await self._retrieve_encryption_key_from_dashboard()
):
error = await self.fetch_device_info()
# If the fetched key is invalid, unset it again.
if error == ERROR_INVALID_ENCRYPTION_KEY:
self._noise_psk = None
@@ -323,7 +337,10 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
self._device_info = await cli.device_info()
except RequiresEncryptionAPIError:
return ERROR_REQUIRES_ENCRYPTION_KEY
except InvalidEncryptionKeyAPIError:
except InvalidEncryptionKeyAPIError as ex:
if ex.received_name:
self._device_name = ex.received_name
self._name = ex.received_name
return ERROR_INVALID_ENCRYPTION_KEY
except ResolveAPIError:
return "resolve_error"
@@ -334,9 +351,8 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
self._name = self._device_info.friendly_name or self._device_info.name
self._device_name = self._device_info.name
await self.async_set_unique_id(
self._device_info.mac_address, raise_on_progress=False
)
mac_address = format_mac(self._device_info.mac_address)
await self.async_set_unique_id(mac_address, raise_on_progress=False)
if not self._reauth_entry:
self._abort_if_unique_id_configured(
updates={CONF_HOST: self._host, CONF_PORT: self._port}
@@ -373,14 +389,15 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
Return boolean if a key was retrieved.
"""
if self._device_name is None:
return False
if (dashboard := async_get_dashboard(self.hass)) is None:
if (
self._device_name is None
or (manager := await async_get_or_create_dashboard_manager(self.hass))
is None
or (dashboard := manager.async_get()) is None
):
return False
await dashboard.async_request_refresh()
if not dashboard.last_update_success:
return False
@@ -394,6 +411,11 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
except aiohttp.ClientError as err:
_LOGGER.error("Error talking to the dashboard: %s", err)
return False
except json.JSONDecodeError as err:
_LOGGER.error(
"Error parsing response from dashboard: %s", err, exc_info=True
)
return False
self._noise_psk = noise_psk
return True

View File

@@ -93,13 +93,6 @@ class ESPHomeDashboardManager:
hass, addon_slug, url, async_get_clientsession(hass)
)
await dashboard.async_request_refresh()
if not cur_dashboard and not dashboard.last_update_success:
# If there was no previous dashboard and the new one is not available,
# we skip setup and wait for discovery.
_LOGGER.error(
"Dashboard unavailable; skipping setup: %s", dashboard.last_exception
)
return
self._current_dashboard = dashboard
@@ -143,7 +136,14 @@ class ESPHomeDashboardManager:
@callback
def async_get_dashboard(hass: HomeAssistant) -> ESPHomeDashboard | None:
"""Get an instance of the dashboard if set."""
"""Get an instance of the dashboard if set.
This is only safe to call after `async_setup` has been completed.
It should not be called from the config flow because there is a race
where manager can be an asyncio.Event instead of the actual manager
because the singleton decorator is not yet done.
"""
manager: ESPHomeDashboardManager | None = hass.data.get(KEY_DASHBOARD_MANAGER)
return manager.async_get() if manager else None

View File

@@ -15,8 +15,8 @@
"iot_class": "local_push",
"loggers": ["aioesphomeapi", "noiseprotocol"],
"requirements": [
"aioesphomeapi==15.0.0",
"bluetooth-data-tools==1.2.0",
"aioesphomeapi==15.1.1",
"bluetooth-data-tools==1.3.0",
"esphome-dashboard-api==1.2.3"
],
"zeroconf": ["_esphomelib._tcp.local."]

View File

@@ -312,7 +312,7 @@ class EzvizCamera(EzvizEntity, Camera):
self.hass,
DOMAIN,
"service_depreciation_detection_sensibility",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
translation_key="service_depreciation_detection_sensibility",

View File

@@ -62,7 +62,7 @@
"issues": {
"service_depreciation_detection_sensibility": {
"title": "Ezviz Detection sensitivity service is being removed",
"description": "Ezviz Detection sensitivity service is deprecated and will be removed in Home Assistant 2023.8; Please adjust the automation or script that uses the service and select submit below to mark this issue as resolved."
"description": "Ezviz Detection sensitivity service is deprecated and will be removed in Home Assistant 2023.12; Please adjust the automation or script that uses the service and select submit below to mark this issue as resolved."
}
}
}

View File

@@ -1,19 +1,4 @@
# Describes the format for available fan services
set_speed:
name: Set speed
description: Set fan speed.
target:
entity:
domain: fan
fields:
speed:
name: Speed
description: Speed setting.
required: true
example: "low"
selector:
text:
set_preset_mode:
name: Set preset mode
description: Set preset mode for a fan device.
@@ -53,12 +38,6 @@ turn_on:
entity:
domain: fan
fields:
speed:
name: Speed
description: Speed setting.
example: "high"
selector:
text:
percentage:
name: Percentage
description: Percentage speed setting.

View File

@@ -34,6 +34,7 @@ class FlickPricingSensor(SensorEntity):
_attr_attribution = "Data provided by Flick Electric"
_attr_native_unit_of_measurement = f"{CURRENCY_CENT}/{UnitOfEnergy.KILO_WATT_HOUR}"
_attr_has_entity_name = True
_attr_translation_key = "power_price"
_attributes: dict[str, Any] = {}

View File

@@ -30,9 +30,6 @@ async def async_setup_entry(
avm_wrapper.fritz_guest_wifi.get_info
)
if not guest_wifi_info.get("NewEnable"):
return
async_add_entities(
[
FritzGuestWifiQRImage(

View File

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

View File

@@ -83,7 +83,7 @@ async def async_setup_platform(
hass,
DOMAIN,
"deprecated_yaml",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml",

View File

@@ -16,5 +16,5 @@
"iot_class": "local_polling",
"loggers": ["goalzero"],
"quality_scale": "silver",
"requirements": ["goalzero==0.2.1"]
"requirements": ["goalzero==0.2.2"]
}

View File

@@ -18,18 +18,11 @@ from homeassistant.helpers.config_entry_oauth2_flow import (
)
from homeassistant.helpers.typing import ConfigType
from .const import (
CONF_ENABLE_CONVERSATION_AGENT,
CONF_LANGUAGE_CODE,
DATA_MEM_STORAGE,
DATA_SESSION,
DOMAIN,
)
from .const import DATA_MEM_STORAGE, DATA_SESSION, DOMAIN, SUPPORTED_LANGUAGE_CODES
from .helpers import (
GoogleAssistantSDKAudioView,
InMemoryStorage,
async_send_text_commands,
default_language_code,
)
SERVICE_SEND_TEXT_COMMAND = "send_text_command"
@@ -82,8 +75,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await async_setup_service(hass)
entry.async_on_unload(entry.add_update_listener(update_listener))
await update_listener(hass, entry)
agent = GoogleAssistantConversationAgent(hass, entry)
conversation.async_set_agent(hass, entry, agent)
return True
@@ -100,8 +93,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
for service_name in hass.services.async_services()[DOMAIN]:
hass.services.async_remove(DOMAIN, service_name)
if entry.options.get(CONF_ENABLE_CONVERSATION_AGENT, False):
conversation.async_unset_agent(hass, entry)
conversation.async_unset_agent(hass, entry)
return True
@@ -125,15 +117,6 @@ async def async_setup_service(hass: HomeAssistant) -> None:
)
async def update_listener(hass, entry):
"""Handle options update."""
if entry.options.get(CONF_ENABLE_CONVERSATION_AGENT, False):
agent = GoogleAssistantConversationAgent(hass, entry)
conversation.async_set_agent(hass, entry, agent)
else:
conversation.async_unset_agent(hass, entry)
class GoogleAssistantConversationAgent(conversation.AbstractConversationAgent):
"""Google Assistant SDK conversation agent."""
@@ -143,6 +126,7 @@ class GoogleAssistantConversationAgent(conversation.AbstractConversationAgent):
self.entry = entry
self.assistant: TextAssistant | None = None
self.session: OAuth2Session | None = None
self.language: str | None = None
@property
def attribution(self):
@@ -155,10 +139,7 @@ class GoogleAssistantConversationAgent(conversation.AbstractConversationAgent):
@property
def supported_languages(self) -> list[str]:
"""Return a list of supported languages."""
language_code = self.entry.options.get(
CONF_LANGUAGE_CODE, default_language_code(self.hass)
)
return [language_code]
return SUPPORTED_LANGUAGE_CODES
async def async_process(
self, user_input: conversation.ConversationInput
@@ -172,12 +153,10 @@ class GoogleAssistantConversationAgent(conversation.AbstractConversationAgent):
if not session.valid_token:
await session.async_ensure_token_valid()
self.assistant = None
if not self.assistant:
if not self.assistant or user_input.language != self.language:
credentials = Credentials(session.token[CONF_ACCESS_TOKEN])
language_code = self.entry.options.get(
CONF_LANGUAGE_CODE, default_language_code(self.hass)
)
self.assistant = TextAssistant(credentials, language_code)
self.language = user_input.language
self.assistant = TextAssistant(credentials, self.language)
resp = self.assistant.assist(user_input.text)
text_response = resp[0] or "<empty response>"

View File

@@ -13,13 +13,7 @@ from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import config_entry_oauth2_flow
from .const import (
CONF_ENABLE_CONVERSATION_AGENT,
CONF_LANGUAGE_CODE,
DEFAULT_NAME,
DOMAIN,
SUPPORTED_LANGUAGE_CODES,
)
from .const import CONF_LANGUAGE_CODE, DEFAULT_NAME, DOMAIN, SUPPORTED_LANGUAGE_CODES
from .helpers import default_language_code
_LOGGER = logging.getLogger(__name__)
@@ -114,12 +108,6 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
CONF_LANGUAGE_CODE,
default=self.config_entry.options.get(CONF_LANGUAGE_CODE),
): vol.In(SUPPORTED_LANGUAGE_CODES),
vol.Required(
CONF_ENABLE_CONVERSATION_AGENT,
default=self.config_entry.options.get(
CONF_ENABLE_CONVERSATION_AGENT
),
): bool,
}
),
)

View File

@@ -5,7 +5,6 @@ DOMAIN: Final = "google_assistant_sdk"
DEFAULT_NAME: Final = "Google Assistant SDK"
CONF_ENABLE_CONVERSATION_AGENT: Final = "enable_conversation_agent"
CONF_LANGUAGE_CODE: Final = "language_code"
DATA_MEM_STORAGE: Final = "mem_storage"

View File

@@ -31,10 +31,8 @@
"step": {
"init": {
"data": {
"enable_conversation_agent": "Enable the conversation agent",
"language_code": "Language code"
},
"description": "Set language for interactions with Google Assistant and whether you want to enable the conversation agent."
}
}
}
},

View File

@@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/google_generative_ai_conversation",
"integration_type": "service",
"iot_class": "cloud_polling",
"requirements": ["google-generativeai==0.1.0rc2"]
"requirements": ["google-generativeai==0.1.0"]
}

View File

@@ -161,7 +161,7 @@ INVERTER_SENSOR_TYPES: tuple[GrowattSensorEntityDescription, ...] = (
),
GrowattSensorEntityDescription(
key="inverter_temperature",
translation_key="inverter_energy_today",
translation_key="inverter_temperature",
api_key="temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,

View File

@@ -83,7 +83,7 @@
"name": "Intelligent Power Management temperature"
},
"inverter_temperature": {
"name": "Energytoday"
"name": "Inverter temperature"
},
"mix_statement_of_charge": {
"name": "Statement of charge"

View File

@@ -168,7 +168,7 @@ BRIDGE_SCHEMA = vol.All(
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_IP_ADDRESS): vol.All(ipaddress.ip_address, cv.string),
vol.Optional(CONF_ADVERTISE_IP): vol.All(
cv.ensure_list, ipaddress.ip_address, cv.string
cv.ensure_list, [ipaddress.ip_address], [cv.string]
),
vol.Optional(CONF_FILTER, default={}): BASE_FILTER_SCHEMA,
vol.Optional(CONF_ENTITY_CONFIG, default={}): validate_entity_config,

View File

@@ -14,6 +14,6 @@
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
"iot_class": "local_push",
"loggers": ["aiohomekit", "commentjson"],
"requirements": ["aiohomekit==2.6.5"],
"requirements": ["aiohomekit==2.6.7"],
"zeroconf": ["_hap._tcp.local.", "_hap._udp.local."]
}

View File

@@ -45,6 +45,7 @@ class HomeWizardSwitchEntityDescription(
SWITCHES = [
HomeWizardSwitchEntityDescription(
key="power_on",
name=None,
device_class=SwitchDeviceClass.OUTLET,
create_fn=lambda coordinator: coordinator.supports_state(),
available_fn=lambda data: data.state is not None and not data.state.switch_lock,

View File

@@ -101,6 +101,7 @@ class HoneywellUSThermostat(ClimateEntity):
"""Representation of a Honeywell US Thermostat."""
_attr_has_entity_name = True
_attr_name = None
def __init__(
self,

View File

@@ -48,6 +48,8 @@ async def async_setup_entry(
class IBeaconTrackerEntity(IBeaconEntity, BaseTrackerEntity):
"""An iBeacon Tracker entity."""
_attr_name = None
def __init__(
self,
coordinator: IBeaconCoordinator,

View File

@@ -162,6 +162,7 @@ async def async_setup_entry(
):
device_info = DeviceInfo(
identifiers=device.identifiers,
connections=device.connections,
)
else:
device_info = None

View File

@@ -90,6 +90,7 @@ class JellyfinMediaPlayer(JellyfinEntity, MediaPlayerEntity):
sw_version=self.app_version,
via_device=(DOMAIN, coordinator.server_id),
)
self._attr_name = None
else:
self._attr_device_info = None
self._attr_has_entity_name = False

View File

@@ -42,6 +42,7 @@ def _count_now_playing(data: JellyfinDataT) -> int:
SENSOR_TYPES: dict[str, JellyfinSensorEntityDescription] = {
"sessions": JellyfinSensorEntityDescription(
key="watching",
name=None,
icon="mdi:television-play",
native_unit_of_measurement="Watching",
value_fn=_count_now_playing,

View File

@@ -52,6 +52,8 @@ async def async_setup_entry(
class JvcProjectorRemote(JvcProjectorEntity, RemoteEntity):
"""Representation of a JVC Projector device."""
_attr_name = None
@property
def is_on(self) -> bool:
"""Return True if entity is on."""

View File

@@ -30,6 +30,7 @@ from homeassistant.const import (
CONF_PORT,
CONF_TYPE,
EVENT_HOMEASSISTANT_STOP,
SERVICE_RELOAD,
Platform,
)
from homeassistant.core import Event, HomeAssistant, ServiceCall
@@ -312,6 +313,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
schema=SERVICE_KNX_EXPOSURE_REGISTER_SCHEMA,
)
async def _reload_integration(call: ServiceCall) -> None:
"""Reload the integration."""
await hass.config_entries.async_reload(entry.entry_id)
hass.bus.async_fire(f"event_{DOMAIN}_reloaded", context=call.context)
async_register_admin_service(hass, DOMAIN, SERVICE_RELOAD, _reload_integration)
await register_panel(hass)
return True

View File

@@ -106,3 +106,6 @@ exposure_register:
default: false
selector:
boolean:
reload:
name: Reload
description: Reload the KNX integration.

View File

@@ -53,7 +53,7 @@ async def async_setup_platform(
hass,
DOMAIN,
"deprecated_yaml",
breaks_in_ha_version="2023.8.0",
breaks_in_ha_version="2023.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml",

View File

@@ -20,5 +20,5 @@
"documentation": "https://www.home-assistant.io/integrations/ld2410_ble/",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["bluetooth-data-tools==1.2.0", "ld2410-ble==0.1.1"]
"requirements": ["bluetooth-data-tools==1.3.0", "ld2410-ble==0.1.1"]
}

View File

@@ -43,6 +43,7 @@ class LEDBLEEntity(CoordinatorEntity, LightEntity):
_attr_supported_color_modes = {ColorMode.RGB, ColorMode.WHITE}
_attr_has_entity_name = True
_attr_name = None
_attr_supported_features = LightEntityFeature.EFFECT
def __init__(

View File

@@ -32,5 +32,5 @@
"dependencies": ["bluetooth_adapters"],
"documentation": "https://www.home-assistant.io/integrations/led_ble/",
"iot_class": "local_polling",
"requirements": ["bluetooth-data-tools==1.2.0", "led-ble==1.0.0"]
"requirements": ["bluetooth-data-tools==1.3.0", "led-ble==1.0.0"]
}

View File

@@ -44,9 +44,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
)
cloud_client = cloud_loqed.LoqedCloudAPI(cloud_api_client)
lock_data = await cloud_client.async_get_locks()
except aiohttp.ClientError:
except aiohttp.ClientError as err:
_LOGGER.error("HTTP Connection error to loqed API")
raise CannotConnect from aiohttp.ClientError
raise CannotConnect from err
try:
selected_lock = next(
@@ -137,7 +137,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
errors["base"] = "invalid_auth"
else:
await self.async_set_unique_id(
re.sub(r"LOQED-([a-f0-9]+)\.local", r"\1", info["bridge_mdns_hostname"])
re.sub(
r"LOQED-([a-f0-9]+)\.local", r"\1", info["bridge_mdns_hostname"]
),
raise_on_progress=False,
)
self._abort_if_unique_id_configured()

View File

@@ -2,5 +2,3 @@
DOMAIN = "loqed"
OAUTH2_AUTHORIZE = "https://app.loqed.com/API/integration_oauth3/login.php"
OAUTH2_TOKEN = "https://app.loqed.com/API/integration_oauth3/token.php"

View File

@@ -8,8 +8,8 @@ from loqedAPI import loqed
from homeassistant.components import webhook
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_WEBHOOK_ID
from homeassistant.core import HomeAssistant, callback
from homeassistant.const import CONF_NAME, CONF_WEBHOOK_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import DOMAIN
@@ -79,17 +79,16 @@ class LoqedDataCoordinator(DataUpdateCoordinator[StatusMessage]):
) -> None:
"""Initialize the Loqed Data Update coordinator."""
super().__init__(hass, _LOGGER, name="Loqed sensors")
self._hass = hass
self._api = api
self._entry = entry
self.lock = lock
self.device_name = self._entry.data[CONF_NAME]
async def _async_update_data(self) -> StatusMessage:
"""Fetch data from API endpoint."""
async with async_timeout.timeout(10):
return await self._api.async_get_lock_details()
@callback
async def _handle_webhook(
self, hass: HomeAssistant, webhook_id: str, request: Request
) -> None:
@@ -116,7 +115,7 @@ class LoqedDataCoordinator(DataUpdateCoordinator[StatusMessage]):
self.hass, DOMAIN, "Loqed", webhook_id, self._handle_webhook
)
webhook_url = webhook.async_generate_url(self.hass, webhook_id)
_LOGGER.info("Webhook URL: %s", webhook_url)
_LOGGER.debug("Webhook URL: %s", webhook_url)
webhooks = await self.lock.getWebhooks()

View File

@@ -23,7 +23,7 @@ class LoqedEntity(CoordinatorEntity[LoqedDataCoordinator]):
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, lock_id)},
manufacturer="LOQED",
name="LOQED Lock",
name=coordinator.device_name,
model="Touch Smart Lock",
connections={(CONNECTION_NETWORK_MAC, lock_id)},
)

View File

@@ -24,7 +24,7 @@ async def async_setup_entry(
"""Set up the Loqed lock platform."""
coordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities([LoqedLock(coordinator, entry.data["name"])])
async_add_entities([LoqedLock(coordinator)])
class LoqedLock(LoqedEntity, LockEntity):
@@ -32,17 +32,17 @@ class LoqedLock(LoqedEntity, LockEntity):
_attr_supported_features = LockEntityFeature.OPEN
def __init__(self, coordinator: LoqedDataCoordinator, name: str) -> None:
def __init__(self, coordinator: LoqedDataCoordinator) -> None:
"""Initialize the lock."""
super().__init__(coordinator)
self._lock = coordinator.lock
self._attr_unique_id = self._lock.id
self._attr_name = name
self._attr_name = None
@property
def changed_by(self) -> str:
"""Return internal ID of last used key."""
return "KeyID " + str(self._lock.last_key_id)
return f"KeyID {self._lock.last_key_id}"
@property
def is_locking(self) -> bool | None:

View File

@@ -12,8 +12,7 @@
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"

View File

@@ -1,22 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Device is already configured"
},
"error": {
"cannot_connect": "Failed to connect",
"invalid_auth": "Invalid authentication",
"unknown": "Unexpected error"
},
"flow_title": "LOQED Touch Smartlock setup",
"step": {
"user": {
"data": {
"api_key": "API Key",
"name": "Name of your lock in the LOQED app."
},
"description": "Login at {config_url} and: \n* Create an API-key by clicking 'Create' \n* Copy the created access token."
}
}
}
}

View File

@@ -96,20 +96,24 @@ class MatterAdapter:
)
self.config_entry.async_on_unload(
self.matter_client.subscribe(
self.matter_client.subscribe_events(
endpoint_added_callback, EventType.ENDPOINT_ADDED
)
)
self.config_entry.async_on_unload(
self.matter_client.subscribe(
self.matter_client.subscribe_events(
endpoint_removed_callback, EventType.ENDPOINT_REMOVED
)
)
self.config_entry.async_on_unload(
self.matter_client.subscribe(node_removed_callback, EventType.NODE_REMOVED)
self.matter_client.subscribe_events(
node_removed_callback, EventType.NODE_REMOVED
)
)
self.config_entry.async_on_unload(
self.matter_client.subscribe(node_added_callback, EventType.NODE_ADDED)
self.matter_client.subscribe_events(
node_added_callback, EventType.NODE_ADDED
)
)
def _setup_node(self, node: MatterNode) -> None:

View File

@@ -65,7 +65,6 @@ DISCOVERY_SCHEMAS = [
entity_description=MatterBinarySensorEntityDescription(
key="HueMotionSensor",
device_class=BinarySensorDeviceClass.MOTION,
name="Motion",
measurement_to_ha=lambda x: (x & 1 == 1) if x is not None else None,
),
entity_class=MatterBinarySensor,
@@ -78,7 +77,6 @@ DISCOVERY_SCHEMAS = [
entity_description=MatterBinarySensorEntityDescription(
key="ContactSensor",
device_class=BinarySensorDeviceClass.DOOR,
name="Contact",
# value is inverted on matter to what we expect
measurement_to_ha=lambda x: not x,
),
@@ -90,7 +88,6 @@ DISCOVERY_SCHEMAS = [
entity_description=MatterBinarySensorEntityDescription(
key="OccupancySensor",
device_class=BinarySensorDeviceClass.OCCUPANCY,
name="Occupancy",
# The first bit = if occupied
measurement_to_ha=lambda x: (x & 1 == 1) if x is not None else None,
),
@@ -102,7 +99,6 @@ DISCOVERY_SCHEMAS = [
entity_description=MatterBinarySensorEntityDescription(
key="BatteryChargeLevel",
device_class=BinarySensorDeviceClass.BATTERY,
name="Battery Status",
measurement_to_ha=lambda x: x
!= clusters.PowerSource.Enums.BatChargeLevelEnum.kOk,
),

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