Compare commits

..

449 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 8e113e54dbf183db06e1d1f0fea95d6bc59e4e80.

* 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
J. Nick Koston
25dc9f5942 Migrate esphome climate platform to use _on_static_info_update (#95471) 2023-06-28 20:37:35 +02:00
Eric Severance
03dac6e171 Remove polling_interval_seconds option from wemo (#95468) 2023-06-28 20:27:10 +02:00
Emory Penney
804b27cc2f Improve Obihai Connection Stability (#94406)
* Improving Obihai Connectivity

* Update homeassistant/components/obihai/sensor.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* PR feedback

---------

Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-06-28 20:12:09 +02:00
Michael
b64be798df Fix qr code data update in AVM Fritz!Tools (#95470)
* use async_update

* improve tests

* use async_image
2023-06-28 19:57:03 +02:00
Michael Hansen
79f1c86789 Bump home-assistant-intents to 2023.6.28 (#95451) 2023-06-28 19:35:18 +02:00
Joost Lekkerkerker
ecfb259438 Add entity translations to iBeacon (#95460)
* Add entity translations to iBeacon

* Add entity translations to iBeacon
2023-06-28 19:32:58 +02:00
Olen
4959fce1e0 Fix setting number of digits for verisure lock PIN (#95449)
* Fix error when setting number of digits

* Update test_config_flow.py

Add test for empty code
2023-06-28 19:18:45 +02:00
Michael Hansen
3d84c6e21c Use "Done" as a default response for sentence triggers (#95463)
* Use "Done" as a default response for sentence triggers

* Move response to trigger callback
2023-06-28 12:34:55 -04:00
Joost Lekkerkerker
d8d580ad58 Make smartthings use the right unit of measurement for illuminance sensors (#95456) 2023-06-28 18:18:24 +02:00
Joost Lekkerkerker
e0d1d16da1 Remove mutable object from hvv sensor (#95454) 2023-06-28 18:18:11 +02:00
Bram Kragten
b2c0ca304b Update frontend to 20230628.0 (#95458) 2023-06-28 18:16:39 +02:00
Martin Hjelmare
de4e3b5ffe Disable sun.sun no platform log (#95450) 2023-06-28 17:06:23 +02:00
Artem Draft
c14a2dd912 Add active_child_template to universal media player (#88816)
* Add active_children_template in universal

* handle multiple updates

* edit docstring

* Rename parameter to active_child_template
2023-06-28 16:36:18 +02:00
Michael
acb7b1fe3b Apply suggestion from late review of #95282 (#95437) 2023-06-28 16:20:23 +02:00
Joost Lekkerkerker
4393aa4f50 Add entity translations to Growatt Server (#95410)
* Add entity translations to Growatt Server

* Fix feedback
2023-06-28 15:28:01 +02:00
Jan Bouwhuis
0a74bffe67 Fix error for stt when async_get_engine is not implemented (#95443)
* Fix error for stt

* Revert "Fix error for stt"

This reverts commit 723cd191fed26b89203a7ec8b78b15f3ae9d9ab9.

* Remove legacy stt platform component
2023-06-28 15:27:06 +02:00
Matthias Alphart
489781c1e6 Add time platform to KNX (#95302) 2023-06-28 15:19:32 +02:00
Erik Montnemery
24ea865553 Fix a couple of typos (#95441) 2023-06-28 14:37:13 +02:00
Jan Bouwhuis
0856121046 Add action topic to MQTT humidifier (#95212)
* Add action topic to MQTT humidifier

* Add tests
2023-06-28 14:21:15 +02:00
Joost Lekkerkerker
e9495c9cc6 Add entity translations for homewizard (#95416)
* Add entity translations for homewizard

* Add entity translations for homewizard

* Add entity translations for homewizard

* Fix tests
2023-06-28 14:02:54 +02:00
avee87
6c2c4c989f Migrate Transmission to new entity naming (#95436) 2023-06-28 14:00:06 +02:00
Joost Lekkerkerker
103375ef95 Add entity translations to HVV Departures (#95442)
* Add entity translations to HVV Departures

* Add entity translations to HVV Departures
2023-06-28 13:57:04 +02:00
Joost Lekkerkerker
ff015310fd Add entity translations to honeywell (#95440) 2023-06-28 13:55:42 +02:00
Sab44
c1953b0ae4 Decouple Hyperion entitites and clear source when light is off (#80478)
* Remove Hyperion Priority Light

* Remove coupling between light entity and led device

* Merge HyperionLight and HyperionBaseLight as we will only have one light entity

* Set state based on whether priority channel is open or not

* Remove leftover variable from Priority Light

* Remove external sources from light entity; use switch entities instead

* Remove external effects from effects to show dropdown

* Remove workaround for hyperion.ng issue 992

---------

Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-06-28 13:51:42 +02:00
starkillerOG
ee4459f41e Extend Reolink update entity (#94323)
Co-authored-by: c0ffeeca7 <38767475+c0ffeeca7@users.noreply.github.com>
2023-06-28 13:32:14 +02:00
Christopher Johnson
c2cd4d0517 Expose host in ubus device tracker (#80621)
* Expose host in ubus device tracker

* Update homeassistant/components/ubus/device_tracker.py

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

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-06-28 13:27:47 +02:00
Dominik
796b5ef196 Bump glances-api to 0.4.3 (#95431) 2023-06-28 13:23:15 +02:00
Denis Shulyaka
ae21ab2945 Add action attribute to Humidifier entity (#95131)
* Add HumidifierAction StrEnum

* Add action attribute to HumidifierEntity

* Update strings.json

* Add action to demo humidifier

* Add tests

* Fix imports

* Add 'off' humidifier action

* Set action to 'off' when state is 'off'

* Add 'off' action to strings.json

* Test that action sets to "off" when state is "off"

* Use is_on instead of state

* Fix typo

* black
2023-06-28 13:21:17 +02:00
Jan Bouwhuis
8b6ed9c6b9 Fix test with time issue for xiaomi_miio button (#95438) 2023-06-28 13:19:24 +02:00
Jan Bouwhuis
fe7857c8ec Add current_humidity device_trigger for humidity component (#95435)
Add current_humidity device_trigger for humidity
2023-06-28 13:13:55 +02:00
Maximilian
0bfb81ecf3 Replace NINA corona filter with regex (#83181)
* Change headline filter to regex

* Add config migration

* Update config flow
2023-06-28 13:00:08 +02:00
Maxim Oei
36b0fc17df Update Telegram bot to support URLs in inlineKeyboard (#70445)
* Update Telegram bot to support URLs in inlineKeyboard

Update creation of InlineKeyboardButton to support url case, on top of callbacks

* linting

* Apply suggestions from code review

---------

Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-06-28 12:56:00 +02:00
Jan Bouwhuis
8b563120b5 Add comment for assumed trigger_type (#95432)
* Add comment for assumed tigger_type

* Update homeassistant/components/climate/device_trigger.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>

---------

Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-06-28 12:22:56 +02:00
Álvaro Fernández Rojas
d430e089d2 Update aioairzone-cloud to v0.2.0 (#95429) 2023-06-28 11:09:17 +02:00
Paulus Schoutsen
149ac4f99e Capitalize a bunch of translations (#95421) 2023-06-28 11:08:53 +02:00
avee87
a5b91cb7e3 Fix invalid unique id for Transmission entities (#84664)
* Update unique id for Transmission entities

* Moved migration to a separate function

* Hopefully fixed coverage

* Extracted dictionary to constant

* review comments

* more comments

* revert accidental name change

* more review comments

* more review comments

* use lists instead of incorrect tuple syntax
2023-06-28 10:45:13 +02:00
Joost Lekkerkerker
2747da784c Move Fjaraskupan coordinator to separate file (#95342)
* Move coordinator to separate file

* Move coordinator to separate file

* Move coordinator to separate file
2023-06-28 10:41:50 +02:00
Franck Nijhof
98a94fea99 Merge branch 'master' into dev 2023-06-28 10:23:20 +02:00
Luke
f6aae8b01b Remove unneded construct import for Eddystone (#95418) 2023-06-28 10:02:01 +02:00
Jan Bouwhuis
265ccae54f Do not allow zerovalue as total_increasing for homewizard sensors (#90982)
* Do not allow zerovalue  as total_increasing

* Fix for solar exports

* Revert not needed change

* Adjust handling, making tests pass

---------

Co-authored-by: Franck Nijhof <git@frenck.dev>
2023-06-28 09:53:33 +02:00
cpolhout
cfb133d431 Add new integration Loqed (#70080) 2023-06-28 09:42:12 +02:00
dependabot[bot]
ebd5eb4470 Bump sigstore/cosign-installer from 3.1.0 to 3.1.1 (#95427)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-28 09:41:08 +02:00
aschobba
f5b2273fc1 Add support for HmIP-BS2 to HomematicIP Cloud (#93599)
* Add support for HmIP-BS2

Add support for HmIP-BS2

* Run ruff fix

---------

Co-authored-by: Franck Nijhof <git@frenck.dev>
2023-06-28 09:33:48 +02:00
hcross13
5955be46a4 Fix ness_alarm tasks being fired before required sensors and panel are loaded asynchronously (#94590)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-06-28 09:30:48 +02:00
Ruben Bokobza
7a82176670 Add preset support to electrasmart climate (#94068) 2023-06-28 09:29:58 +02:00
starkillerOG
d2cd0c9934 Add reolink channel based record, push, email, ftp, and buzzer switches (#91006)
* Add channel based email, ftp, push, rec and buzzer switches

* fix dataclass
2023-06-28 09:18:14 +02:00
Don Holly
04e277ac95 Add AirQuality SensorState support for Google Assistant (#80579)
* Add AirQuality SensorState support for Google Assistant

* Code formatting

* Apply suggestions from code review

Co-authored-by: Joakim Plate <elupus@ecce.se>

* Update trait.py

* Update trait.py

* Fix google_assistant tests

* Update trait.py

* Simplify sensor state payload and tests

* Add more tests to fix coverage

* fix tests

* Truncate once

---------

Co-authored-by: Joakim Plate <elupus@ecce.se>
Co-authored-by: Erik <erik@montnemery.com>
2023-06-28 08:55:00 +02:00
J. Nick Koston
72806bfaf2 Add more test coverage for ESPHome lights (#95415) 2023-06-28 08:40:21 +02:00
Joost Lekkerkerker
b53b162d05 Add entity translations to Flo (#95347)
* Add entity translations to Flo

* Add entity translations to Flo
2023-06-28 08:36:10 +02:00
Michael
4daacf9c4b Add Guest WiFi QR-Code image entity to AVM Fritz!Tools (#95282) 2023-06-27 23:48:28 +02:00
Joost Lekkerkerker
aaa4ee79b8 Add entity translations to HERE Travel time (#95412) 2023-06-27 23:35:12 +02:00
shbatm
4e05205174 Add updated ISY994/IoX Units of Measurement (#95408) 2023-06-27 16:17:36 -05:00
Nathan Spencer
ec8988f8ea Add time entity for sleep mode start time to Litter-Robot 3 (#94194) 2023-06-27 22:25:29 +02:00
Joost Lekkerkerker
21c619e702 Add entity translations to Guardian (#95411) 2023-06-27 22:24:41 +02:00
zry98
bafb81337b Add buttons for resetting vacuum consumable status in xiaomi_miio (#91483)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: Eugenio Panadero <eugenio.panadero@gmail.com>
2023-06-27 21:58:29 +02:00
Dave T
7fa86d3998 Simplify parsing of user input during config flow for generic (#86256)
Co-authored-by: Dave T <davet2001@users.noreply.github.com>
2023-06-27 21:29:06 +02:00
Álvaro Fernández Rojas
78380c0cd4 Allow turning Airzone slave zones on with any HVAC mode (#94721)
airzone: climate: allow turning slave zone on with any hvac mode

If the user selects a different mode on a slave zone from the one selected on
the master zone, it will raise an exception and it won't change the operation
mode or turn it on.
Change this behaviour so that the exception will still be raised but the slave
zone will be turned on and the hvac mode won't be changed.
This allows commanding airzone slave zones from limited APIs like homekit.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2023-06-27 21:25:41 +02:00
Marcel van der Veldt
ed2daf1f65 Change subscription logic for Matter devices (#95387) 2023-06-27 21:12:29 +02:00
Joost Lekkerkerker
a885ceefa2 Add entity translations to Gios (#95403) 2023-06-27 20:58:03 +02:00
Eric Severance
a4a6972237 Set webhook local_only deprecation to 2023.11.0 (#95401) 2023-06-27 20:43:11 +02:00
Charles Garwood
34827571ba Add set_config service to Fully Kiosk Browser integration (#95318)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-06-27 20:42:18 +02:00
micha91
16fe79db75 Improve the source labels for MusicCast players (#74954) 2023-06-27 20:34:04 +02:00
Joost Lekkerkerker
dd3693caca Add entity translations to Github (#95404) 2023-06-27 20:33:27 +02:00
Ian Foster
286bdff8bc Fix keyboard_remote device_descriptor when using symbolic links (#94744) 2023-06-27 20:31:41 +02:00
Marcel van der Veldt
e7f29263e3 Fix sending a (default) pincode to Matter Lock operations (#95402) 2023-06-27 20:27:48 +02:00
Mick Vleeshouwer
99a622c8ee Bump pyoverkiz to 1.9.0 (#95400) 2023-06-27 20:25:31 +02:00
Erik Montnemery
179e1da164 Use entity registry id in text device actions (#95398) 2023-06-27 20:24:40 +02:00
Franck Nijhof
d7b7deb95f Improve climate turn_on service (#94645) 2023-06-27 20:17:13 +02:00
Eric Severance
bbae2061e7 Add wemo options enable_subscription & enable_long_press (#56972)
* Add wemo options enable_subscription & enable_long_press

* Also add polling_interval_seconds option

* Give feedback about invalid option combinations

* Use a frozen dataclass for Options

* Validate polling_interval_seconds

* Describe message arg

* Replace broad exception with PyWeMoException
2023-06-27 20:10:13 +02:00
Joost Lekkerkerker
6a85e227db Show all YouTube subscriptions in config flow (#94287) 2023-06-27 20:07:44 +02:00
Franck Nijhof
48776f86dc Use identify device class in Elgato identify button entity (#95361)
* Use identify device class in Elgato identify button entity

* Clean up strings
2023-06-27 13:59:49 -04:00
Erik Montnemery
0fc51ac75a Remove current humidity humidifier device trigger (#95394) 2023-06-27 19:55:59 +02:00
Richard Kroegel
f1a54a510c Re-add "deactivate air conditioning" button to bmw_connected_drive (#94765) 2023-06-27 19:55:46 +02:00
Mike Knoop
2092bd225d Distinguish multiple raise lower buttons on one Lutron keypad (#92380) 2023-06-27 19:52:46 +02:00
Erik Montnemery
e18f7dffb0 Teach validate_config to validate lists of conditions (#95380)
* Teach validate_config to validate lists of conditions

* Update test
2023-06-27 19:44:23 +02:00
Joost Lekkerkerker
e8cb9fba7b Add entity translations to Geocaching (#95396) 2023-06-27 19:42:55 +02:00
Paulus Schoutsen
243abf32c0 Add test to stop action (#95376) 2023-06-27 19:38:30 +02:00
Paul Bottein
8b25fd8563 Use total increasing for ecowitt precipitation and lightning count (#90099) 2023-06-27 19:32:06 +02:00
Maciej Bieniek
8d6a711cac Make unique_id of the Shelly button entity immutable (#95160) 2023-06-27 19:10:12 +02:00
aschmitz
1dc9c77a3e Tag Aranet diagnostic entities appropriately (#95218) 2023-06-27 18:56:46 +02:00
Joost Lekkerkerker
e4eb7e4796 Add entity translations to FireServiceRota (#95337) 2023-06-27 18:55:40 +02:00
Joost Lekkerkerker
09bfb08067 Add entity translations to Flume (#95350) 2023-06-27 18:54:32 +02:00
Joost Lekkerkerker
0b32a6e0d1 Use shorthand attributes for freedompro (#95358) 2023-06-27 18:53:29 +02:00
Joost Lekkerkerker
b0834472bc Use device class translations for Fritz (#95362) 2023-06-27 18:48:03 +02:00
Erik Montnemery
68db751ce1 Refactor template image (#95353) 2023-06-27 18:46:36 +02:00
Joost Lekkerkerker
1a8bc1930c Add entity translations to FiveM (#95370) 2023-06-27 18:44:26 +02:00
Franck Nijhof
4b9bfe9a50 Support importing Blueprints from the Home Assistant websites (#95340)
* Support importing Blueprints from the Home Assistant websites

* Improve test coverage
2023-06-27 12:40:53 -04:00
J. Nick Koston
a8b2c1edfa Add more coverage for ESPHome lights (#95384) 2023-06-27 18:27:09 +02:00
Erik Montnemery
bff4b0c79c Use entity registry id in arcam_fmj device triggers (#95391) 2023-06-27 18:25:17 +02:00
Erik Montnemery
5a90a44233 Use entity registry id in kodi device triggers (#95392) 2023-06-27 18:24:53 +02:00
Erik Montnemery
1fec407a24 Set scripts which fail validation unavailable (#95381) 2023-06-27 18:24:34 +02:00
Erik Montnemery
17ac1a6d32 Set automations which fail validation unavailable (#94856) 2023-06-27 18:23:33 +02:00
Pascal Vizeli
5c4d010b90 Fix machine build templates (#95393) 2023-06-27 18:00:12 +02:00
Joost Lekkerkerker
8bbb396048 Move freedompro coordinator to separate file (#95360)
* Move coordinator to separate file for freedompro

* Move coordinator to separate file for freedompro
2023-06-27 17:48:36 +02:00
Joakim Sørensen
db01aecb02 Add contents to connection_info handler in cloud client (#95059) 2023-06-27 17:45:41 +02:00
Robert Hillis
cd26de73b4 Add button platform to Dremel 3D printer (#94517)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2023-06-27 17:44:29 +02:00
Franck Nijhof
3e85a29b86 Move overlapping pylint rules to ruff, disable mypy overlap (#94359) 2023-06-27 17:42:46 +02:00
disforw
7c676c0a7d Add config_flow to QNAP (#80450)
* Create config_flow.py

* Update __init__.py

* Create const.py

* Create strings.json

* Update sensor.py

* Update manifest.json

* Update manifest.json

* Add device name to entities

* Correcting health sensor

* Update manifest.json

* Adding integration_type

* Update sensor.py

* Update __init__.py

* Enums

* Update sensor.py

* Removed unused notify_create

* Switch to SensorDeviceClass.TEMPERATURE

* Update enums

* Remove SENSOR_TYPES from const.py

* Add SENSOR_TYPES to sensor.py

* Removed dependancies

* Removed import yaml

* Removed entity_registry_enabled_default

* Update const.py remove dups

* Update manifest.json removed dups

* Update __init__.py

* Update const.py

* Update manifest.json

* Update sensor.py

* Update sensor.py

* Update sensor.py

* Update sensor.py

* Update sensor.py

* Update sensor.py

* Update sensor.py remove unused

* Update sensor.py add docstring

* Update sensor.py add super

* Remove FOLDER sensors

* Remove VOLUME_NAME

* fix cli

* fix cli

* Add config flow tests

* Update requirements_test_all.txt

* Update CODEOWNERS

* Update homeassistant/components/qnap/config_flow.py

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

* Update homeassistant/components/qnap/config_flow.py

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

* Update homeassistant/components/qnap/config_flow.py

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

* Update __init__.py

Change unload to walrus
Remove async_setup

* Update const.py remove PLATFORMS

* Update __init__.py add Platform Enum

As per epenet

* Update __init__.py

* Update config_flow.py

* Update sensor.py

* Update __init__.py

ruff

* Update config_flow.py

Ruff

* Update sensor.py

* Update const.py remove attrs

* Update sensor.py add attrs

* Revert tuple for sensor extend

* Update sensor.py

* Update coordinator.py

* Update coordinator.py

* Update sensor.py

* Update coordinator.py

* Update homeassistant/components/qnap/__init__.py

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

* Update homeassistant/components/qnap/const.py

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

* Update homeassistant/components/qnap/__init__.py

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

* Update coordinator.py

* Update __init__.py

* Update coordinator.py

* Update sensor.py

* Add device_info

* Update sensor.py

* Update sensor.py self._attr_unique_id

* Update sensor.py

* Update sensor.py

* Type Hints

* Move tuples

* Drive sensor name

* Remove caps

* Remove caps

* Add YAML import

* Update sensor.py fix ruff

* Revert tuples

* Update sensor.py as per review

* Update sensor.py

* Update sensor.py

* Update sensor.py

* Update sensor.py

* Update sensor.py

* Update sensor.py

* Update sensor.py

* assert uid is not None

* Update homeassistant/components/qnap/sensor.py

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

* Update homeassistant/components/qnap/sensor.py

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

* Update .coveragerc

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

* Update homeassistant/components/qnap/config_flow.py

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

* Update homeassistant/components/qnap/config_flow.py

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

* Update homeassistant/components/qnap/const.py

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

* Update homeassistant/components/qnap/const.py

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

* Apply suggestions from code review

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

* Apply suggestions from code review

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

* Update sensor.py

* Update config_flow.py add imports

* Update const.py

* Update sensor.py move confs to const

* Update config_flow.py add const

* Update test_config_flow.py remove const name

* Update test_config_flow.py remove standard result const

* Update test_config_flow.py

* Combine tests

* Update test_config_flow.py

* Update config_flow.py

* Update test_config_flow.py

* Update config_flow.py

* Update test_config_flow.py

* Update test_config_flow.py

* Update sensor.py change UID as requested

* Update sensor.py added check for monitor_device

* fix tests

* Remove rounding

* Revert "Remove rounding"

This reverts commit 61bf653c069d37cd7c20e3dd2f555f80b6e5d94f.

---------

Co-authored-by: starkillerOG <starkiller.og@gmail.com>
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-06-27 17:42:27 +02:00
Franck Nijhof
43fe30f6ee Use identify device class in ZHA identify button entity (#95373) 2023-06-27 17:42:13 +02:00
Joost Lekkerkerker
e7cc839a96 Add entity translations to Fully Kiosk (#95368) 2023-06-27 17:41:41 +02:00
J. Nick Koston
df65fa3899 Bump pyatv to 0.13.2 (#95388) 2023-06-27 17:38:15 +02:00
Marcel van der Veldt
30fcfaf1ec Some small fixes for the Matter light platform (#95343) 2023-06-27 17:33:10 +02:00
Erik Montnemery
cb22fb16f8 Allow returning a script variable from a script (#95346)
* Allow returning a script variable from a script

* Don't allow returning a template result

* Raise if response variable is undefined

* Add test

* Update homeassistant/helpers/script.py

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

* Format code

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-06-27 17:13:53 +02:00
Joost Lekkerkerker
e19b29d6ae Add entity translations to Flux led (#95355) 2023-06-27 16:58:57 +02:00
Marc Mueller
90854df5b2 Add editable install back [ci] (#95379) 2023-06-27 16:10:03 +02:00
Diogo Gomes
96bf8ef8d6 Add Risk of Fire sensor to IPMA (#80295) 2023-06-27 16:00:10 +02:00
Erik Montnemery
f3fc741a71 Bump hass-nabucassa to 0.69.0 (#95367) 2023-06-27 15:29:30 +02:00
Erik Montnemery
190d67b56c Improve content type handling in ImageEntity (#95365) 2023-06-27 15:28:49 +02:00
Franck Nijhof
116dd67472 Use identify device class in LIFX identify button entity (#95372) 2023-06-27 14:52:44 +02:00
J. Nick Koston
878d41a472 Remove senseme integration (#94363) 2023-06-27 14:43:19 +02:00
Joost Lekkerkerker
50e36fbdda Add entity translations to Flick electric (#95345) 2023-06-27 14:38:36 +02:00
Erik Montnemery
071d3a474f Base entity ids on English for languages not using Latin script (#91357) 2023-06-27 14:37:50 +02:00
Dylan Owen
fe28067481 Updated pyopnsense to support a 20 second timeout (#95314)
* Updated pyopnsense to support a timeout

* Self Review

* Removed the yaml configuration portion
2023-06-27 08:31:02 -04:00
Franck Nijhof
9ca0a095ab Use identify device class in HomeWizard identify button entity (#95369) 2023-06-27 14:30:46 +02:00
Joost Lekkerkerker
c1e8eb7c96 Use device class translations for Fritzbox (#95363) 2023-06-27 14:06:57 +02:00
Erik Montnemery
e9eb366f3b Improve MQTT image tests (#95359) 2023-06-27 13:53:38 +02:00
Haim Gelfenbeyn
0c66ccebd1 Verify that the MAC address that Fully Kiosk reported is usable (#94887) 2023-06-27 13:34:07 +02:00
Erik Montnemery
723f6d35b0 Address late review comments on image entity URL support (#95338) 2023-06-27 13:22:59 +02:00
Joost Lekkerkerker
968bc25259 Add entity translations to Flipr (#95344) 2023-06-27 13:20:30 +02:00
Joost Lekkerkerker
f61332c9b4 Clean up forecast_solar const file (#95356) 2023-06-27 13:19:10 +02:00
Joost Lekkerkerker
d8e73b6a6b Move FiveM entity class to separate file (#95348) 2023-06-27 13:17:51 +02:00
Martin Hjelmare
4d2fa5bdbc Onboard Google Translate (#95352) 2023-06-27 13:12:25 +02:00
Joost Lekkerkerker
2c9213baa1 Bump python-opensky to 0.0.10 (#94335) 2023-06-27 13:10:09 +02:00
Jan Bouwhuis
4d05a3ae79 Add url support for mqtt image platform (#95249)
* Add url support for mqtt image platform

* Refactor url fetch code to use base platform

* Update after rebase

---------

Co-authored-by: Erik <erik@montnemery.com>
2023-06-27 12:49:31 +02:00
Joost Lekkerkerker
a80862f3db Add entity translations to Fjaraskupan (#95341) 2023-06-27 12:38:32 +02:00
Franck Nijhof
c225c46853 Clean up device class based entity translations in Community.Sensors (#95011) 2023-06-27 12:31:57 +02:00
Erik Montnemery
3c015f85f4 Revert "Change the device class name volatile organic compounds parts to VOCs ratio" (#95332) 2023-06-27 12:28:31 +02:00
Joakim Sørensen
4d4e7522f4 Adjust the analytics collector to only report configured integrations (#95246) 2023-06-27 12:08:51 +02:00
Erik Montnemery
90c1263501 Adjust image entity URL support (#95330) 2023-06-27 11:59:24 +02:00
Franck Nijhof
39f76b757d Clean up wheels building, removing cp310 abi (#95334) 2023-06-27 11:53:19 +02:00
Franck Nijhof
9de2b6c253 Use Python 3.11 in translations and builder workflows (#95335) 2023-06-27 11:52:45 +02:00
Patrick ZAJDA
58f8f9c82a Add state attribute translations to Switchbot (#90861) 2023-06-27 11:52:20 +02:00
Jan Bouwhuis
22f29e8c84 Add validation of content_type to image entity (#95248) 2023-06-27 11:46:31 +02:00
Joost Lekkerkerker
af7b25d748 Move FiveM coordinator to separate file (#95339)
Move coordinator to separate file
2023-06-27 12:40:38 +03:00
G Johansson
30d22fe49b Add new attributes into Template Weather (#95100) 2023-06-27 11:19:51 +02:00
Pascal Vizeli
b62080cb78 Using builder 2023.06.1 (#95333)
* Using builder 2023.06.1

* revert downgrade of cosign
2023-06-27 10:34:31 +02:00
Joost Lekkerkerker
ba244b7af7 Add entity translations to Efergy (#95291)
* Add entity translations to Efergy

* Add entity translations to Efergy
2023-06-27 10:22:08 +02:00
dependabot[bot]
b12109dcde Bump sigstore/cosign-installer from 3.0.5 to 3.1.0 (#95327)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-27 10:21:36 +02:00
Robert Hillis
10f116a507 Add entity translations to Google Mail (#95312) 2023-06-27 10:19:47 +02:00
Robert Hillis
16bcbe3d22 Add entity translations to Lidarr (#95313) 2023-06-27 10:19:20 +02:00
Joost Lekkerkerker
4ab8411145 Make Dexcom use shorthand attributes (#95231) 2023-06-27 10:17:09 +02:00
Robert Hillis
7add36d847 Add entity translations to Litterrobot (#95316) 2023-06-27 10:12:02 +02:00
Pascal Vizeli
c3d02d68b7 Fix Cosign Image build (#95328) 2023-06-27 09:29:45 +02:00
Erik Montnemery
c2f7e5840b Use entity registry id in climate device actions (#95268)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2023-06-27 09:28:54 +02:00
Robert Hillis
8d1cd39044 Add entity translations to Radarr (#95317) 2023-06-27 08:45:27 +02:00
Joost Lekkerkerker
73bc5a4e8f Add entity translations to Aurora ABB PowerOne (#95132) 2023-06-27 08:42:09 +02:00
Jan Bouwhuis
98cc45ec10 Add image url support (#95301)
* Add image url support

* Use hass as parameter

* Add verify ssl parameter and improve exception handling

* Improve error handling, ignore empty URL's

* Update existing image platforms

---------

Co-authored-by: Erik <erik@montnemery.com>
2023-06-27 08:36:12 +02:00
dougiteixeira
363dab7ce4 Change the device class name volatile organic compounds parts to VOCs ratio (#95126) 2023-06-27 08:33:11 +02:00
Joost Lekkerkerker
2c3a50fdb1 Add entity translations to Awair (#95308) 2023-06-27 08:27:33 +02:00
J. Nick Koston
6d47feb595 Add tests for ESPHome cover platform (#95321) 2023-06-27 08:26:35 +02:00
Paulus Schoutsen
5f14cdf69d Allow stopping a script with a response value (#95284) 2023-06-27 08:24:22 +02:00
Erik Montnemery
51aa2ba835 Use entity registry id in water_heater device actions (#95276) 2023-06-27 08:21:15 +02:00
Erik Montnemery
9dc586bd98 Use entity registry id in number device actions (#95273) 2023-06-27 08:20:45 +02:00
Erik Montnemery
c2457b8574 Use entity registry id in cover device actions (#95269) 2023-06-27 08:20:05 +02:00
J. Nick Koston
0af71851a4 Fix ESPHome button not getting device updates (#95311) 2023-06-26 22:34:37 -05:00
Paulus Schoutsen
d6cd5648b9 Change conversation default agent behavior (#95225)
* Change conversation default agent behavior

* Fix tests
2023-06-26 22:10:17 -04:00
J. Nick Koston
c4288e7b1f Use cached_property in entity.py instead of manual cache (#95307) 2023-06-26 19:18:46 -05:00
Erik Montnemery
398dbed72e Improve type annotations of cached_property backport (#95309) 2023-06-26 18:36:01 -05:00
J. Nick Koston
9fe24c54e9 Add test coverage for ESPHome switch platform (#95306) 2023-06-26 17:49:00 -05:00
Joost Lekkerkerker
dbe4252d34 Add entity translation to Aussie broadband (#95134) 2023-06-26 23:39:02 +02:00
Joost Lekkerkerker
185936deda Use DeviceInfo type for Aurora ABB PowerOne (#95133) 2023-06-26 23:36:06 +02:00
Michael Hansen
b70a67404b Check end stage as well when preparing pipeline (#95303) 2023-06-26 16:36:02 -05:00
Joost Lekkerkerker
9734f45202 Add entity translations to Eufylife BLE (#95296) 2023-06-26 23:32:37 +02:00
Erik Montnemery
a568885ad2 Add backport of cached_property from CPython 3.12 (#95292) 2023-06-26 16:23:07 -05:00
Joost Lekkerkerker
b02cb56988 Clean up Awair const (#95135) 2023-06-26 23:22:43 +02:00
Erik Montnemery
3635508a08 Use entity registry id in vacuum device actions (#95275) 2023-06-26 23:21:15 +02:00
Joost Lekkerkerker
a44f3e62e3 Add entity translations to Energyzero (#95293) 2023-06-26 23:20:34 +02:00
Joost Lekkerkerker
cb9cbdfb28 Add entity translations to ecobee (#95281) 2023-06-26 23:12:48 +02:00
Erik Montnemery
320003bf15 Use entity registry id in lock device actions (#95272) 2023-06-26 23:09:26 +02:00
Erik Montnemery
b12c5a5ba2 Use entity registry id in humidifier device actions (#95270) 2023-06-26 23:08:30 +02:00
Joost Lekkerkerker
ad9bf431a8 Add entity translations to filesize (#95299) 2023-06-26 23:06:27 +02:00
J. Nick Koston
7737271a30 Migrate esphome alarm_control_panel platform to use _on_static_info_update (#94961) 2023-06-26 22:58:17 +02:00
Michael Hansen
0f08e6699c Add VAD sensitivity to ESPHome (#95283)
* Change to "finished speaking detection"

* Add select entity to ESPHome for finished speaking detection

* Fix entity name

* Use vad select in stt stream

---------

Co-authored-by: J. Nick Koston <nick@koston.org>
2023-06-26 16:47:32 -04:00
Robert Hillis
c6775920f5 Tweak Dremel 3D Printer sensors (#94552) 2023-06-26 22:39:10 +02:00
Erik Montnemery
4efe217d9b Use entity registry id in select device actions (#95274) 2023-06-26 22:29:14 +02:00
Joost Lekkerkerker
ec120608c2 Add entity translations to edl21 (#95289) 2023-06-26 22:28:12 +02:00
Erik Montnemery
433d640071 Use entity registry id in light device actions (#95271) 2023-06-26 22:27:19 +02:00
Paulus Schoutsen
bc8be9caea Rename HomeKit Controller to HomeKit Device (#95286) 2023-06-26 22:26:16 +02:00
Joost Lekkerkerker
2872b6cf61 Add entity translations to Environment Canada (#95295) 2023-06-26 22:23:43 +02:00
Erik Montnemery
9b1b0937eb Use entity registry id in button device actions (#95267) 2023-06-26 22:22:15 +02:00
J. Nick Koston
fde82ee323 Keep esphome update entity available when disconnected is expected (#95278) 2023-06-26 22:20:56 +02:00
starkillerOG
0bec93fa37 Reolink ONVIF long polling (#94770) 2023-06-26 21:54:40 +02:00
Petro31
f9707cc87b Add optional limits to compensation sensors (#85886)
Co-authored-by: Tom Harris <tomharris@harrisnj.net>
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-06-26 14:36:59 -05:00
Erik Montnemery
b71e0302d6 Use entity registry id in sensor device conditions (#95260) 2023-06-26 21:20:40 +02:00
Erik Montnemery
2930845b23 Use entity registry id in vacuum device conditions (#95261) 2023-06-26 20:31:06 +02:00
Erik Montnemery
eb7ad2eb09 Use entity registry id in select device conditions (#95259) 2023-06-26 20:30:29 +02:00
Erik Montnemery
4021662b48 Use entity registry id in media_player device conditions (#95258) 2023-06-26 20:30:22 +02:00
Erik Montnemery
2cfa889750 Use entity registry id in lock device conditions (#95257) 2023-06-26 20:30:05 +02:00
Erik Montnemery
c4589ad4e5 Use entity registry id in fan device conditions (#95255) 2023-06-26 20:29:52 +02:00
Erik Montnemery
16ec9b1e9f Use entity registry id in device_tracker device conditions (#95254) 2023-06-26 20:29:39 +02:00
Erik Montnemery
a691846b5d Use entity registry id in climate device conditions (#95252) 2023-06-26 20:29:28 +02:00
Franck Nijhof
c1a37185b4 Mark Plugwise Illuminance sensor as diagnostic (#95240) 2023-06-26 19:40:30 +02:00
Richard Kroegel
410b15df92 Improve exception handling for BMW remote services (#92199)
Co-authored-by: rikroe <rikroe@users.noreply.github.com>
2023-06-26 19:05:50 +02:00
Marc Mueller
f5975d4039 Update build system (#95237) 2023-06-26 19:03:56 +02:00
Joost Lekkerkerker
1525901ffc Add entity translations to dormakaba (#95230) 2023-06-26 19:02:52 +02:00
Álvaro Fernández Rojas
3f0393154e Remove unused ConfigEntry from Airzone Cloud entities (#95103) 2023-06-26 18:58:51 +02:00
Joost Lekkerkerker
844a1ebbc6 Add entity translations to BMW Connected Drive (#95142) 2023-06-26 18:57:56 +02:00
Paulus Schoutsen
d95c241a1a Add service response values to service descriptions (#95262) 2023-06-26 12:57:43 -04:00
Martin Hjelmare
fa03324bbd Remove stale dep from google translate (#95247) 2023-06-26 18:49:01 +02:00
Joost Lekkerkerker
36ded01264 Add entity translations to Blink (#95138) 2023-06-26 18:29:33 +02:00
Erik Montnemery
07936884a3 Use entity registry id in alarm_control_panel device conditions (#95250) 2023-06-26 18:26:21 +02:00
Joost Lekkerkerker
a64940cf42 Use shorthand attribute for EAFM (#95233) 2023-06-26 18:25:39 +02:00
Joost Lekkerkerker
9e3706e3b9 Move Aurora entity to separate file (#95245) 2023-06-26 18:24:14 +02:00
Joost Lekkerkerker
91e6e918c3 Code tidyness for Dexcom (#95232) 2023-06-26 18:22:44 +02:00
Erik Montnemery
f0493b22d4 Use entity registry id in binary_sensor device conditions (#95251) 2023-06-26 18:17:27 +02:00
Erik Montnemery
02ad93db53 Use entity registry id in cover device conditions (#95253) 2023-06-26 18:14:23 +02:00
Erik Montnemery
e77a06412a Use entity registry id in humidifier device conditions (#95256) 2023-06-26 18:13:48 +02:00
Mick Vleeshouwer
de1b5626e1 Set explicit None for entity name in Overkiz when using device name (#95238) 2023-06-26 18:11:57 +02:00
dougiteixeira
39229ce098 Add the device of the source entity in the helper entities for Utility Meter (#94734)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2023-06-26 18:08:13 +02:00
dougiteixeira
403496eb92 Add the device of the source entity in the helper entities for Derivative (#94751)
* Adds the device of the original entity in the helper entities for Derivative

* Update

* Update
2023-06-26 18:06:25 +02:00
dougiteixeira
26016b29f7 Add the device of the source entity in the helper entities for Threshold (#94753) 2023-06-26 18:05:11 +02:00
G Johansson
537cc9ed86 Use new attributes in Met (#95099) 2023-06-26 18:04:10 +02:00
Franck Nijhof
78222bd51c 2023.6.3 (#95119) 2023-06-23 19:08:57 +02:00
Franck Nijhof
9f6dab0643 Remove incompatible config schema for Fully Kiosk 2023-06-23 17:56:25 +02:00
Franck Nijhof
4cf9beccd8 Bumped version to 2023.6.3 2023-06-23 16:46:52 +02:00
Matthias Alphart
8f9425f09f Fix KNX device trigger passing info data (#95076) 2023-06-23 16:46:33 +02:00
Marcel van der Veldt
0fa954040e Fix removal of orphaned Matter devices (#95044) 2023-06-23 16:46:30 +02:00
Hmmbob
e26b8e11d3 Fix goodwe midnight error (#95041) 2023-06-23 16:45:56 +02:00
Richard Kroegel
ced6968e85 Bump bimmer_connected to 0.13.7 (#95017) 2023-06-23 16:45:16 +02:00
Raman Gupta
44e7243e25 Fix zwave_js device diagnostics dump (#94999)
* Fix zwave_js device diagnostics dump

* Update tests/components/zwave_js/test_diagnostics.py

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

* Update tests/components/zwave_js/test_diagnostics.py

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

* Update tests/components/zwave_js/test_diagnostics.py

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

* Update tests/components/zwave_js/test_diagnostics.py

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

* Update tests/components/zwave_js/test_diagnostics.py

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

* Update tests/components/zwave_js/test_diagnostics.py

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

* improve test

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-06-23 16:43:34 +02:00
Marcel van der Veldt
bbbc9f646f Bump Matter Server to 3.5.1: some small fixes and stability improvements (#94985) 2023-06-23 16:43:31 +02:00
epenet
cda784c969 Add error handling to hassio issues (#94951) 2023-06-23 16:43:28 +02:00
Quentame
34ef89b16b Fix Meteo France blocked config entry when weather alert API fails (#94911)
* Fix: do not block config entry when weather alert API fails

* PR review
2023-06-23 16:43:24 +02:00
Allen Porter
f8cfaa6147 Bump ical to 4.5.4 (#94894) 2023-06-23 16:43:21 +02:00
Álvaro Fernández Rojas
5da5522481 Update aioairzone to v0.6.4 (#94873) 2023-06-23 16:43:18 +02:00
Ernst Klamer
cee8004641 Bump bthome to 2.12.0 (#94822) 2023-06-23 16:43:15 +02:00
J. Nick Koston
e1751647f4 Bump HAP-python to 4.7.0 (#94812) 2023-06-23 16:43:11 +02:00
Austin Mroczek
f33d671a5d Fix Totalconnect BinarySensorDeviceClass logic (#94772)
* handle temperature

* test for temperature

* test for unknown
2023-06-23 16:43:07 +02:00
Jan Čermák
254b1fd314 Fix warning from rapt_ble caused by payload version 2 (#94718) 2023-06-23 16:43:04 +02:00
Raman Gupta
89c6494056 Fix zwave_js trigger event reattach logic (#94702) 2023-06-23 16:43:01 +02:00
Dirk Sarodnick
b52cfd3324 Fix bluetooth tracker asyncio usage (#94695)
* fix for asyncio usage

fixes the error "Passing coroutines is forbidden, use tasks explicitly", caused by passing an async function into asyncio.wait directly instead of creating a task for it.

* removes unnecessary default param

* corrects formatting for black
2023-06-23 16:42:55 +02:00
Joost Lekkerkerker
6329f6bc07 Add strings for YouTube reauthentication (#94655) 2023-06-23 16:38:29 +02:00
Joost Lekkerkerker
57dd62e7d6 Make YouTube select lower quality thumbnails (#94652)
* Make YouTube select lower quality thumbnails

* Make YouTube select lower quality thumbnails

* Make YouTube select lower quality thumbnails

* Make YouTube select lower quality thumbnails

* Add tests

* Add tests

* Add tests

* Add tests

* Add tests
2023-06-23 16:38:21 +02:00
Dominik
203820d836 Fix glances raid plugin data (#94597)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-06-23 16:38:14 +02:00
Dominik
e1c486fc4a Bump minimum typing_extensions to 4.6.3 (#94587) 2023-06-23 16:37:27 +02:00
Alistair Tudor
78bbec0a6e Fix unit for Habitica text sensors (#94550) 2023-06-23 16:35:33 +02:00
Tom Harris
ffe35c73b6 Handle Insteon events correctly (#94549)
Make events generalized
2023-06-23 16:35:30 +02:00
Joost Lekkerkerker
d2385f97a7 Handle LastFM unavailable (#94456) 2023-06-23 16:35:27 +02:00
Kim Frellsen
bd0b8dc0bc Fortios device tracker updates (#92331)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-06-23 16:35:24 +02:00
Mike Heath
3f936993a9 Register Fully Kiosk services regardless of setup result (#88647)
* Register services at integration level

If HA is unable to connect to Fully Kiosk, the services don't get
registered. This can cause repair to create notifications saying
that the 'fully_kiosk.load_url' service is unknown.

Fixes #85444

* Validate config entry is loaded

* Refactor service invocation

Raises `HomeAssistantError` when the user provides an device id that is
not in the device registry or a device that is not a Fully Kiosk
device. If the device's config entry is not loaded, a warning is
logged.

* Update homeassistant/components/fully_kiosk/services.py

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

* Assert HomeAssistantError when integration unloaded

* Remove unused import

* Set CONFIG_SCHEMA

* Update homeassistant/components/fully_kiosk/__init__.py

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

* Add test for non fkb devices targets in service calls

* Apply suggestions from code review

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-06-23 16:35:19 +02:00
Paulus Schoutsen
e5c5790768 2023.6.2 (#94621) 2023-06-15 00:19:30 -04:00
Paulus Schoutsen
905bdd0dd5 Bumped version to 2023.6.2 2023-06-14 21:18:40 -04:00
Erik Montnemery
9cbcfca2cd Improve multipan debug logging (#94580) 2023-06-14 21:18:35 -04:00
Chris Talkington
e6b8e4fd48 Fix failed recovery in ipp (#94573) 2023-06-14 21:18:34 -04:00
Chris Talkington
8f437c5833 Fix failed recovery in roku (#94572) 2023-06-14 21:18:33 -04:00
Ian Foster
d28d909114 Fix keyboard_remote for python 3.11 (#94570)
* started work to update keyboard_remote to work with python 3.11

* updated function names

* all checks pass

* fixed asyncio for python 3.11

* cleanup

* Update homeassistant/components/keyboard_remote/__init__.py

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

* Update __init__.py

added:
from __future__ import annotations

* Fix typing

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-06-14 21:18:32 -04:00
Maciej Bieniek
f67577ebe0 Catch InvalidAuthError in shutdown() method for Shelly gen2 devices (#94563)
* Catch InvalidAuthError in shutdown() method

* Add test

* Revert unwanted change in tests
2023-06-14 21:18:31 -04:00
Franck Nijhof
70d33129d4 Update Home Assistant base image to 2023.06.0 (#94556) 2023-06-14 21:18:29 -04:00
Aaron Bach
a63ce8100e Bump regenmaschine to 2023.06.0 (#94554) 2023-06-14 21:18:28 -04:00
J. Nick Koston
d557c6e43e Bump yalexs-ble to 2.1.18 (#94547) 2023-06-14 21:18:27 -04:00
Raman Gupta
fd0404bb4a Fix entity and device selector TypedDict's (#94510) 2023-06-14 21:18:26 -04:00
Chris Phillips
576cf52573 Bump russound_rio to 1.0.0 (#94500) 2023-06-14 21:17:51 -04:00
mover85
e83f0bb7a5 Revert "Bump pydaikin 2.9.1 (#93635)" (#94469)
Revert to pydaikin 2.9.0
2023-06-14 21:17:08 -04:00
Raman Gupta
fa8e952324 Set default value for endpoint in zwave device automations (#94445)
* Set default value for endpoint in zwave device automations

* add test case
2023-06-14 21:17:07 -04:00
G Johansson
25a4679266 Fix reload service in Command Line (#94436)
* Fix reload in Command Line

* Add read new yaml
2023-06-14 21:17:06 -04:00
G Johansson
f5aa4f5866 Fix manual update for Command Line (#94433)
Manual update command line
2023-06-14 21:17:04 -04:00
Yuxin Wang
0083649e43 Add unit inference for Amps and VA in APCUPSD integration (#94431)
* Add unit inference for Amps and VA

* Rename `init_integration` to `async_init_integration` for better consistency with HA naming style
2023-06-14 21:17:03 -04:00
Sander
2505de35c9 Fix: Xiaomi Miio Fan, delay off countdown unit conversion (#94428) 2023-06-14 21:17:02 -04:00
Christopher Bailey
238eebb0b6 Bump unifiprotect to 4.10.3 (#94416)
* Bump unifiprotect to 4.10.3

* Reqs
2023-06-14 21:17:01 -04:00
Matthias Alphart
4cb30e69ac Update knx-frontend to 2023.6.9.195839 (#94404) 2023-06-14 21:16:19 -04:00
Joost Lekkerkerker
ac00977e57 Abort youtube configuration if user has no channel (#94402)
* Abort configuration if user has no channel

* Clean up

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-06-14 21:15:21 -04:00
jasonkuster
b2db849798 Fix ZHA binding api to actually return responses (#94388) 2023-06-14 21:15:20 -04:00
Raman Gupta
2c7a176580 Re-add event listeners after Z-Wave server disconnection (#94383)
* Re-add event listeners after Z-Wave server disconnection

* switch order

* Add tests
2023-06-14 21:15:19 -04:00
Matthias Alphart
4dbc408696 Update xknxproject to 3.1.1 (#94375) 2023-06-14 21:14:42 -04:00
Sebastian Muszynski
582fd11a70 Fix deprecated asyncio.wait use with coroutines (#94371) 2023-06-14 21:13:25 -04:00
Jan Bouwhuis
96cb5ff8b0 Fix dep noaa-coops for noaa_tides (#94370)
Bump noaa-coops to 0.1.9
2023-06-14 21:13:23 -04:00
Jafar Atili
6029e23ab7 fix: electrasmart - cast temperature to int in set_temperature (#94368)
fix: cast temperature to int
2023-06-14 21:13:22 -04:00
Jonathan Keljo
3434d74993 Upgrade sisyphus-control to 3.1.3 (#94310) 2023-06-14 21:13:21 -04:00
Nathan Spencer
e091793b6c Bump pylitterbot to 2023.4.2 (#94301) 2023-06-14 21:13:20 -04:00
Glenn Waters
9c8444da0e Bump elkm1-lib to 2.2.5 (#94296)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-06-14 21:13:19 -04:00
Tom Harris
427f0f4bee Fix issue with Insteon linked devices maintaining current state (#94286)
* Bump pyinsteon

* Update tests
2023-06-14 21:13:18 -04:00
FFT
95528f875e Change pyoppleio to pyoppleio-legacy (#88050)
* Change pyoppleio to pyoppleio-310 (#75268)

* [m] change opple component's dependency to a new working one
2023-06-14 21:13:17 -04:00
Paulus Schoutsen
a5f86bff45 2023.6.1 (#94288) 2023-06-08 14:57:37 -04:00
Paulus Schoutsen
d991970754 Bumped version to 2023.6.1 2023-06-08 13:39:33 -04:00
Tom Harris
d745b44180 Fix Insteon startup for users with X10 devices (#94277) 2023-06-08 13:39:10 -04:00
Tom Harris
602fcd6b1b Restructure Insteon start-up (#92818)
* Restructure startup

* Code review

* Further typing

* Fix circular import
2023-06-08 13:39:09 -04:00
Franck Nijhof
b39b0a960e Fix repair issue about no yaml for config entries (#94271) 2023-06-08 13:35:08 -04:00
Paulus Schoutsen
40bb796f03 Fix default value when logger used (#94269) 2023-06-08 13:28:54 -04:00
Christopher Bailey
2801ba6cad Bump unifiprotect to 4.10.2 (#94263) 2023-06-08 13:28:52 -04:00
Paul Bottein
5da0ef36ea Update frontend to 20230608.0 (#94256) 2023-06-08 13:28:51 -04:00
Joost Lekkerkerker
d861292900 Retrieve friends in an async manner in Lastfm (#94255) 2023-06-08 13:28:50 -04:00
Jc2k
a3fda43c64 Bump aiohomekit to 2.6.5 (fixes python 3.11 regression) (#94245) 2023-06-08 13:28:49 -04:00
Joost Lekkerkerker
8705a26a1a Catch exception when user has no lastfm friends (#94235) 2023-06-08 13:28:48 -04:00
jan iversen
2b1c45c28c Solve wrong return code from modbus. (#94234) 2023-06-08 13:28:47 -04:00
Jan Bouwhuis
0cf3825183 Fix imap crash on email without subject (#94230) 2023-06-08 13:28:46 -04:00
Kostas Chatzikokolakis
413e1c97d7 Bump pulsectl to 23.5.2 (#94227) 2023-06-08 13:28:45 -04:00
Joost Lekkerkerker
3b27a3aabf Bump python-opensky to 0.0.9 (#94224) 2023-06-08 13:28:44 -04:00
Joost Lekkerkerker
4509e13ceb Bump python-opensky (#93916) 2023-06-08 13:28:43 -04:00
Álvaro Fernández Rojas
33bf8c600b Update aioairzone-cloud to v0.1.8 (#94223) 2023-06-08 13:27:46 -04:00
Jan-Philipp Benecke
b508875f17 Set httpx log level to warning (#94217)
Set log level of httpx to warning
2023-06-08 13:27:45 -04:00
Allen Porter
ac963a2b6e Require pydantic 1.10.8 or higher (#94208)
* Requied pydantic 1.10.9 or higher

* Simplify constraint to 2.0

* Drop constraint by one patch release to 1.10.8 or higher

* Add package constraints to gen requirements script
2023-06-08 13:27:43 -04:00
James Connor
13029cf26f Fix ambiclimate for Python 3.11 (#94203)
Fix ambiclimate python 3.11 break
2023-06-08 13:27:42 -04:00
Paulus Schoutsen
f39a6b96ff Rename Local Media to My Media (#94201)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
2023-06-08 13:27:41 -04:00
Mick Vleeshouwer
c6a17d6832 Bump pyoverkiz to 1.8.0 (#94176) 2023-06-08 13:27:40 -04:00
Joost Lekkerkerker
74c0552a12 Fix Abode unit of measurement (#94168)
Change unit of measurement to HA const
2023-06-08 13:27:38 -04:00
Justin Vanderhooft
f24b514c9a Bump melnor-bluetooth to fix a timezone issue (#94159) 2023-06-08 13:27:37 -04:00
Erik Montnemery
e1c47fdb61 Fix OTBR reset (#94157) 2023-06-08 13:27:36 -04:00
j4n-e4t
93baf24394 Add error handling to input_select integration (#93940) 2023-06-08 12:27:23 -04:00
899 changed files with 21874 additions and 7094 deletions

View File

@@ -91,6 +91,7 @@ omit =
homeassistant/components/aurora/__init__.py
homeassistant/components/aurora/binary_sensor.py
homeassistant/components/aurora/coordinator.py
homeassistant/components/aurora/entity.py
homeassistant/components/aurora/sensor.py
homeassistant/components/avea/light.py
homeassistant/components/avion/light.py
@@ -123,7 +124,6 @@ omit =
homeassistant/components/bluetooth_tracker/*
homeassistant/components/bmw_connected_drive/__init__.py
homeassistant/components/bmw_connected_drive/binary_sensor.py
homeassistant/components/bmw_connected_drive/button.py
homeassistant/components/bmw_connected_drive/coordinator.py
homeassistant/components/bmw_connected_drive/lock.py
homeassistant/components/bmw_connected_drive/notify.py
@@ -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
@@ -307,13 +306,9 @@ omit =
homeassistant/components/escea/discovery.py
homeassistant/components/esphome/__init__.py
homeassistant/components/esphome/bluetooth/*
homeassistant/components/esphome/button.py
homeassistant/components/esphome/camera.py
homeassistant/components/esphome/cover.py
homeassistant/components/esphome/domain_data.py
homeassistant/components/esphome/entry_data.py
homeassistant/components/esphome/light.py
homeassistant/components/esphome/switch.py
homeassistant/components/etherscan/sensor.py
homeassistant/components/eufy/*
homeassistant/components/eufylife_ble/__init__.py
@@ -359,10 +354,13 @@ omit =
homeassistant/components/fitbit/*
homeassistant/components/fivem/__init__.py
homeassistant/components/fivem/binary_sensor.py
homeassistant/components/fivem/coordinator.py
homeassistant/components/fivem/entity.py
homeassistant/components/fivem/sensor.py
homeassistant/components/fixer/sensor.py
homeassistant/components/fjaraskupan/__init__.py
homeassistant/components/fjaraskupan/binary_sensor.py
homeassistant/components/fjaraskupan/coordinator.py
homeassistant/components/fjaraskupan/fan.py
homeassistant/components/fjaraskupan/light.py
homeassistant/components/fjaraskupan/number.py
@@ -942,6 +940,8 @@ omit =
homeassistant/components/pyload/sensor.py
homeassistant/components/qbittorrent/__init__.py
homeassistant/components/qbittorrent/sensor.py
homeassistant/components/qnap/__init__.py
homeassistant/components/qnap/coordinator.py
homeassistant/components/qnap/sensor.py
homeassistant/components/qrcode/image_processing.py
homeassistant/components/quantum_gateway/device_tracker.py
@@ -1046,12 +1046,6 @@ omit =
homeassistant/components/sense/__init__.py
homeassistant/components/sense/binary_sensor.py
homeassistant/components/sense/sensor.py
homeassistant/components/senseme/__init__.py
homeassistant/components/senseme/discovery.py
homeassistant/components/senseme/entity.py
homeassistant/components/senseme/fan.py
homeassistant/components/senseme/light.py
homeassistant/components/senseme/switch.py
homeassistant/components/senz/__init__.py
homeassistant/components/senz/api.py
homeassistant/components/senz/climate.py

View File

@@ -10,7 +10,7 @@ on:
env:
BUILD_TYPE: core
DEFAULT_PYTHON: "3.10"
DEFAULT_PYTHON: "3.11"
jobs:
init:
@@ -197,7 +197,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build base image
uses: home-assistant/builder@2023.06.0
uses: home-assistant/builder@2023.06.1
with:
args: |
$BUILD_ARGS \
@@ -274,7 +274,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build base image
uses: home-assistant/builder@2023.06.0
uses: home-assistant/builder@2023.06.1
with:
args: |
$BUILD_ARGS \
@@ -324,12 +324,16 @@ jobs:
if: github.repository_owner == 'home-assistant'
needs: ["init", "build_base"]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout the repository
uses: actions/checkout@v3.5.3
- name: Install Cosign
uses: sigstore/cosign-installer@v3.0.5
uses: sigstore/cosign-installer@v3.1.1
with:
cosign-release: "v2.0.2"

View File

@@ -492,10 +492,10 @@ jobs:
python -m venv venv
. venv/bin/activate
python --version
pip install --cache-dir=$PIP_CACHE -U "pip>=21.0,<23.2" setuptools wheel
pip install --cache-dir=$PIP_CACHE -U "pip>=21.3.1,<23.2" setuptools wheel
pip install --cache-dir=$PIP_CACHE -r requirements_all.txt
pip install --cache-dir=$PIP_CACHE -r requirements_test.txt
pip install -e .
pip install -e . --config-settings editable_mode=compat
hassfest:
name: Check hassfest

View File

@@ -10,7 +10,7 @@ on:
- "**strings.json"
env:
DEFAULT_PYTHON: "3.10"
DEFAULT_PYTHON: "3.11"
jobs:
upload:

View File

@@ -47,10 +47,7 @@ jobs:
echo "GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=true"
echo "GRPC_PYTHON_BUILD_WITH_CYTHON=true"
echo "GRPC_PYTHON_DISABLE_LIBC_COMPATIBILITY=true"
# GRPC on armv7 needs -lexecinfo (issue #56669) since home assistant installs
# execinfo-dev when building wheels. The setuptools build setup does not have an option for
# adding a single LDFLAG so copy all relevant linux flags here (as of 1.43.0)
echo "GRPC_PYTHON_LDFLAGS=-lpthread -Wl,-wrap,memcpy -static-libgcc -lexecinfo"
echo "GRPC_PYTHON_LDFLAGS=-lpthread -Wl,-wrap,memcpy -static-libgcc"
# Fix out of memory issues with rust
echo "CARGO_NET_GIT_FETCH_WITH_CLI=true"
@@ -83,7 +80,7 @@ jobs:
strategy:
fail-fast: false
matrix:
abi: ["cp310", "cp311"]
abi: ["cp311"]
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
@@ -113,7 +110,7 @@ jobs:
requirements-diff: "requirements_diff.txt"
requirements: "requirements.txt"
integrations_cp310:
integrations_cp311:
name: Build wheels ${{ matrix.abi }} for ${{ matrix.arch }}
if: github.repository_owner == 'home-assistant'
needs: init
@@ -121,7 +118,7 @@ jobs:
strategy:
fail-fast: false
matrix:
abi: ["cp310"]
abi: ["cp311"]
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
@@ -137,152 +134,10 @@ jobs:
with:
name: requirements_diff
- name: Uncomment packages
run: |
requirement_files="requirements_all.txt requirements_diff.txt"
for requirement_file in ${requirement_files}; do
sed -i "s|# pybluez|pybluez|g" ${requirement_file}
sed -i "s|# beacontools|beacontools|g" ${requirement_file}
sed -i "s|# fritzconnection|fritzconnection|g" ${requirement_file}
sed -i "s|# pyuserinput|pyuserinput|g" ${requirement_file}
sed -i "s|# evdev|evdev|g" ${requirement_file}
sed -i "s|# pycups|pycups|g" ${requirement_file}
sed -i "s|# homekit|homekit|g" ${requirement_file}
sed -i "s|# decora_wifi|decora_wifi|g" ${requirement_file}
sed -i "s|# python-gammu|python-gammu|g" ${requirement_file}
sed -i "s|# opencv-python-headless|opencv-python-headless|g" ${requirement_file}
done
- name: Split requirements all
run: |
# We split requirements all into two different files.
# This is to prevent the build from running out of memory when
# resolving packages on 32-bits systems (like armhf, armv7).
split -l $(expr $(expr $(cat requirements_all.txt | wc -l) + 1) / 3) requirements_all.txt requirements_all.txt
- name: Adjust build env
run: |
if [ "${{ matrix.arch }}" = "i386" ]; then
echo "NPY_DISABLE_SVML=1" >> .env_file
fi
(
# cmake > 3.22.2 have issue on arm
# Tested until 3.22.5
echo "cmake==3.22.2"
) >> homeassistant/package_constraints.txt
# Do not pin numpy in wheels building
sed -i "/numpy/d" homeassistant/package_constraints.txt
- name: Build wheels (part 1)
uses: home-assistant/wheels@2023.04.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
arch: ${{ matrix.arch }}
wheels-key: ${{ secrets.WHEELS_KEY }}
env-file: true
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev"
skip-binary: aiohttp;grpcio;sqlalchemy;protobuf
constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtaa"
- name: Build wheels (part 2)
uses: home-assistant/wheels@2023.04.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
arch: ${{ matrix.arch }}
wheels-key: ${{ secrets.WHEELS_KEY }}
env-file: true
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev"
skip-binary: aiohttp;grpcio;sqlalchemy;protobuf
constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtab"
- name: Build wheels (part 3)
uses: home-assistant/wheels@2023.04.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
arch: ${{ matrix.arch }}
wheels-key: ${{ secrets.WHEELS_KEY }}
env-file: true
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev"
skip-binary: aiohttp;grpcio;sqlalchemy;protobuf
constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtac"
# Wheels building for the cp311 ABI is currently split
# This is mainly until we have figured out to get all wheels built.
# Without harming our current workflow.
integrations_cp311:
name: Build wheels ${{ matrix.abi }} for ${{ matrix.arch }}
if: github.repository_owner == 'home-assistant'
needs: init
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
abi: ["cp311"]
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v3.5.3
- name: Write alternative env-file for cp311
run: |
(
echo "GRPC_BUILD_WITH_BORING_SSL_ASM=false"
echo "GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=true"
echo "GRPC_PYTHON_BUILD_WITH_CYTHON=true"
echo "GRPC_PYTHON_DISABLE_LIBC_COMPATIBILITY=true"
# GRPC on armv7 needed -lexecinfo (issue #56669) since home assistant installed
# execinfo-dev when building wheels. However, this package is no longer available
# Alpine 3.17, which we use for the cp311 ABI, so the flag should no longer be needed.
echo "GRPC_PYTHON_LDFLAGS=-lpthread -Wl,-wrap,memcpy -static-libgcc" # -lexecinfo
# Fix out of memory issues with rust
echo "CARGO_NET_GIT_FETCH_WITH_CLI=true"
# OpenCV headless installation
echo "CI_BUILD=1"
echo "ENABLE_HEADLESS=1"
# Use C-Extension for sqlalchemy
echo "REQUIRE_SQLALCHEMY_CEXT=1"
) > .env_file
- name: Download requirements_diff
uses: actions/download-artifact@v3
with:
name: requirements_diff
- name: (Un)comment packages
run: |
requirement_files="requirements_all.txt requirements_diff.txt"
for requirement_file in ${requirement_files}; do
# PyBluez no longer compiles. Commented it out for now.
# It need further cleanup down the line, as all machine images
# try to install it.
# sed -i "s|# pybluez|pybluez|g" ${requirement_file}
# beacontools requires PyBluez.
# sed -i "s|# beacontools|beacontools|g" ${requirement_file}
# It doesn't build for some reason, so we skip it for now.
# Bumping to the latest version (4.7.0.72) supporting Python 3.11
# doesn't help. Reverted bump in #91871. There are 8 registered
# instances using this integration according to analytics.
# sed -i "s|# opencv-python-headless|opencv-python-headless|g" ${requirement_file}
sed -i "s|# fritzconnection|fritzconnection|g" ${requirement_file}
sed -i "s|# pyuserinput|pyuserinput|g" ${requirement_file}
sed -i "s|# evdev|evdev|g" ${requirement_file}
@@ -319,13 +174,6 @@ jobs:
echo "NPY_DISABLE_SVML=1" >> .env_file
fi
# Probably not an issue anymore. Removing for now.
# (
# # cmake > 3.22.2 have issue on arm
# # Tested until 3.22.5
# echo "cmake==3.22.2"
# ) >> homeassistant/package_constraints.txt
# Do not pin numpy in wheels building
sed -i "/numpy/d" homeassistant/package_constraints.txt

View File

@@ -277,7 +277,6 @@ homeassistant.components.scene.*
homeassistant.components.schedule.*
homeassistant.components.scrape.*
homeassistant.components.select.*
homeassistant.components.senseme.*
homeassistant.components.sensibo.*
homeassistant.components.sensirion_ble.*
homeassistant.components.sensor.*

View File

@@ -703,6 +703,8 @@ build.json @home-assistant/supervisor
/tests/components/logi_circle/ @evanjd
/homeassistant/components/lookin/ @ANMalko @bdraco
/tests/components/lookin/ @ANMalko @bdraco
/homeassistant/components/loqed/ @mikewoudenberg
/tests/components/loqed/ @mikewoudenberg
/homeassistant/components/lovelace/ @home-assistant/frontend
/tests/components/lovelace/ @home-assistant/frontend
/homeassistant/components/luci/ @mzdrale
@@ -970,6 +972,7 @@ build.json @home-assistant/supervisor
/homeassistant/components/qld_bushfire/ @exxamalte
/tests/components/qld_bushfire/ @exxamalte
/homeassistant/components/qnap/ @disforw
/tests/components/qnap/ @disforw
/homeassistant/components/qnap_qsw/ @Noltari
/tests/components/qnap_qsw/ @Noltari
/homeassistant/components/quantum_gateway/ @cisasteelersfan
@@ -1079,8 +1082,6 @@ build.json @home-assistant/supervisor
/tests/components/select/ @home-assistant/core
/homeassistant/components/sense/ @kbickar
/tests/components/sense/ @kbickar
/homeassistant/components/senseme/ @mikelawrence @bdraco
/tests/components/senseme/ @mikelawrence @bdraco
/homeassistant/components/sensibo/ @andrey-git @gjohansson-ST
/tests/components/sensibo/ @andrey-git @gjohansson-ST
/homeassistant/components/sensirion_ble/ @akx

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

@@ -17,7 +17,7 @@
"api_key": "[%key:common::config_flow::data::api_key%]",
"city": "City",
"country": "Country",
"state": "state"
"state": "State"
}
},
"reauth_confirm": {

View File

@@ -193,6 +193,8 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set hvac mode."""
slave_raise = False
params = {}
if hvac_mode == HVACMode.OFF:
params[API_ON] = 0
@@ -202,12 +204,13 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
if self.get_airzone_value(AZD_MASTER):
params[API_MODE] = mode
else:
raise HomeAssistantError(
f"Mode can't be changed on slave zone {self.name}"
)
slave_raise = True
params[API_ON] = 1
await self._async_update_hvac_params(params)
if slave_raise:
raise HomeAssistantError(f"Mode can't be changed on slave zone {self.name}")
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
params = {}

View File

@@ -55,7 +55,6 @@ async def async_setup_entry(
AirzoneZoneBinarySensor(
coordinator,
description,
entry,
zone_id,
zone_data,
)
@@ -95,12 +94,11 @@ class AirzoneZoneBinarySensor(AirzoneZoneEntity, AirzoneBinarySensor):
self,
coordinator: AirzoneUpdateCoordinator,
description: AirzoneBinarySensorEntityDescription,
entry: ConfigEntry,
zone_id: str,
zone_data: dict[str, Any],
) -> None:
"""Initialize."""
super().__init__(coordinator, entry, zone_id, zone_data)
super().__init__(coordinator, zone_id, zone_data)
self._attr_unique_id = f"{zone_id}_{description.key}"
self.entity_description = description

View File

@@ -15,7 +15,6 @@ from aioairzone_cloud.const import (
AZD_ZONES,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@@ -43,7 +42,6 @@ class AirzoneAidooEntity(AirzoneEntity):
def __init__(
self,
coordinator: AirzoneUpdateCoordinator,
entry: ConfigEntry,
aidoo_id: str,
aidoo_data: dict[str, Any],
) -> None:
@@ -73,7 +71,6 @@ class AirzoneWebServerEntity(AirzoneEntity):
def __init__(
self,
coordinator: AirzoneUpdateCoordinator,
entry: ConfigEntry,
ws_id: str,
ws_data: dict[str, Any],
) -> None:
@@ -104,7 +101,6 @@ class AirzoneZoneEntity(AirzoneEntity):
def __init__(
self,
coordinator: AirzoneUpdateCoordinator,
entry: ConfigEntry,
zone_id: str,
zone_data: dict[str, Any],
) -> None:

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/airzone_cloud",
"iot_class": "cloud_polling",
"loggers": ["aioairzone_cloud"],
"requirements": ["aioairzone-cloud==0.1.9"]
"requirements": ["aioairzone-cloud==0.2.0"]
}

View File

@@ -89,7 +89,6 @@ async def async_setup_entry(
AirzoneAidooSensor(
coordinator,
description,
entry,
aidoo_id,
aidoo_data,
)
@@ -103,7 +102,6 @@ async def async_setup_entry(
AirzoneWebServerSensor(
coordinator,
description,
entry,
ws_id,
ws_data,
)
@@ -117,7 +115,6 @@ async def async_setup_entry(
AirzoneZoneSensor(
coordinator,
description,
entry,
zone_id,
zone_data,
)
@@ -148,12 +145,11 @@ class AirzoneAidooSensor(AirzoneAidooEntity, AirzoneSensor):
self,
coordinator: AirzoneUpdateCoordinator,
description: SensorEntityDescription,
entry: ConfigEntry,
aidoo_id: str,
aidoo_data: dict[str, Any],
) -> None:
"""Initialize."""
super().__init__(coordinator, entry, aidoo_id, aidoo_data)
super().__init__(coordinator, aidoo_id, aidoo_data)
self._attr_has_entity_name = True
self._attr_unique_id = f"{aidoo_id}_{description.key}"
@@ -169,12 +165,11 @@ class AirzoneWebServerSensor(AirzoneWebServerEntity, AirzoneSensor):
self,
coordinator: AirzoneUpdateCoordinator,
description: SensorEntityDescription,
entry: ConfigEntry,
ws_id: str,
ws_data: dict[str, Any],
) -> None:
"""Initialize."""
super().__init__(coordinator, entry, ws_id, ws_data)
super().__init__(coordinator, ws_id, ws_data)
self._attr_has_entity_name = True
self._attr_unique_id = f"{ws_id}_{description.key}"
@@ -190,12 +185,11 @@ class AirzoneZoneSensor(AirzoneZoneEntity, AirzoneSensor):
self,
coordinator: AirzoneUpdateCoordinator,
description: SensorEntityDescription,
entry: ConfigEntry,
zone_id: str,
zone_data: dict[str, Any],
) -> None:
"""Initialize."""
super().__init__(coordinator, entry, zone_id, zone_data)
super().__init__(coordinator, zone_id, zone_data)
self._attr_has_entity_name = True
self._attr_unique_id = f"{zone_id}_{description.key}"

View File

@@ -58,7 +58,7 @@ CONDITION_TYPES: Final[set[str]] = {
CONDITION_SCHEMA: Final = DEVICE_CONDITION_BASE_SCHEMA.extend(
{
vol.Required(CONF_ENTITY_ID): cv.entity_id,
vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
vol.Required(CONF_TYPE): vol.In(CONDITION_TYPES),
}
)
@@ -83,7 +83,7 @@ async def async_get_conditions(
CONF_CONDITION: "device",
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,
CONF_ENTITY_ID: entry.id,
}
conditions += [
@@ -126,8 +126,11 @@ def async_condition_from_config(
elif config[CONF_TYPE] == CONDITION_ARMED_CUSTOM_BYPASS:
state = STATE_ALARM_ARMED_CUSTOM_BYPASS
registry = er.async_get(hass)
entity_id = er.async_resolve_entity_id(registry, config[ATTR_ENTITY_ID])
def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
"""Test if an entity is a certain state."""
return condition.state(hass, config[ATTR_ENTITY_ID], state)
return condition.state(hass, entity_id, state)
return test_is_state

View File

@@ -21,12 +21,22 @@ from homeassistant.components.recorder import (
DOMAIN as RECORDER_DOMAIN,
get_instance as get_recorder_instance,
)
import homeassistant.config as conf_util
from homeassistant.config_entries import (
SOURCE_IGNORE,
)
from homeassistant.const import ATTR_DOMAIN, __version__ as HA_VERSION
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.entity_registry as er
from homeassistant.helpers.storage import Store
from homeassistant.helpers.system_info import async_get_system_info
from homeassistant.loader import IntegrationNotFound, async_get_integrations
from homeassistant.loader import (
Integration,
IntegrationNotFound,
async_get_integrations,
)
from homeassistant.setup import async_get_loaded_integrations
from .const import (
@@ -206,8 +216,25 @@ class Analytics:
if self.preferences.get(ATTR_USAGE, False) or self.preferences.get(
ATTR_STATISTICS, False
):
ent_reg = er.async_get(self.hass)
try:
yaml_configuration = await conf_util.async_hass_config_yaml(self.hass)
except HomeAssistantError as err:
LOGGER.error(err)
return
configuration_set = set(yaml_configuration)
er_platforms = {
entity.platform
for entity in ent_reg.entities.values()
if not entity.disabled
}
domains = async_get_loaded_integrations(self.hass)
configured_integrations = await async_get_integrations(self.hass, domains)
enabled_domains = set(configured_integrations)
for integration in configured_integrations.values():
if isinstance(integration, IntegrationNotFound):
continue
@@ -215,7 +242,11 @@ class Analytics:
if isinstance(integration, BaseException):
raise integration
if integration.disabled:
if not self._async_should_report_integration(
integration=integration,
yaml_domains=configuration_set,
entity_registry_platforms=er_platforms,
):
continue
if not integration.is_built_in:
@@ -253,12 +284,12 @@ class Analytics:
if supervisor_info is not None:
payload[ATTR_ADDONS] = addons
if ENERGY_DOMAIN in integrations:
if ENERGY_DOMAIN in enabled_domains:
payload[ATTR_ENERGY] = {
ATTR_CONFIGURED: await energy_is_configured(self.hass)
}
if RECORDER_DOMAIN in integrations:
if RECORDER_DOMAIN in enabled_domains:
instance = get_recorder_instance(self.hass)
engine = instance.database_engine
if engine and engine.version is not None:
@@ -306,3 +337,34 @@ class Analytics:
LOGGER.error(
"Error sending analytics to %s: %r", ANALYTICS_ENDPOINT_URL, err
)
@callback
def _async_should_report_integration(
self,
integration: Integration,
yaml_domains: set[str],
entity_registry_platforms: set[str],
) -> bool:
"""Return a bool to indicate if this integration should be reported."""
if integration.disabled:
return False
# Check if the integration is defined in YAML or in the entity registry
if (
integration.domain in yaml_domains
or integration.domain in entity_registry_platforms
):
return True
# Check if the integration provide a config flow
if not integration.config_flow:
return False
entries = self.hass.config_entries.async_entries(integration.domain)
# Filter out ignored and disabled entries
return any(
entry
for entry in entries
if entry.source != SOURCE_IGNORE and entry.disabled_by is None
)

View File

@@ -296,7 +296,6 @@ class ADBDevice(MediaPlayerEntity):
self._process_config,
)
)
return
@property
def media_image_hash(self) -> str | None:

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

@@ -7,7 +7,7 @@
"documentation": "https://www.home-assistant.io/integrations/apple_tv",
"iot_class": "local_push",
"loggers": ["pyatv", "srptools"],
"requirements": ["pyatv==0.13.0"],
"requirements": ["pyatv==0.13.2"],
"zeroconf": [
"_mediaremotetv._tcp.local.",
"_companion-link._tcp.local.",
@@ -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

@@ -25,6 +25,7 @@ from homeassistant.const import (
ATTR_SW_VERSION,
CONCENTRATION_PARTS_PER_MILLION,
PERCENTAGE,
EntityCategory,
UnitOfPressure,
UnitOfTemperature,
UnitOfTime,
@@ -81,6 +82,7 @@ SENSOR_DESCRIPTIONS = {
device_class=SensorDeviceClass.BATTERY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
"interval": AranetSensorEntityDescription(
key="update_interval",
@@ -90,6 +92,7 @@ SENSOR_DESCRIPTIONS = {
state_class=SensorStateClass.MEASUREMENT,
# The interval setting is not a generally useful entity for most users.
entity_registry_enabled_default=False,
entity_category=EntityCategory.DIAGNOSTIC,
),
}

View File

@@ -3,7 +3,9 @@ from __future__ import annotations
import voluptuous as vol
from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA
from homeassistant.components.device_automation import (
DEVICE_TRIGGER_BASE_SCHEMA,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_DEVICE_ID,
@@ -22,7 +24,7 @@ from .const import DOMAIN, EVENT_TURN_ON
TRIGGER_TYPES = {"turn_on"}
TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
{
vol.Required(CONF_ENTITY_ID): cv.entity_id,
vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES),
}
)
@@ -43,7 +45,7 @@ async def async_get_triggers(
CONF_PLATFORM: "device",
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,
CONF_ENTITY_ID: entry.id,
CONF_TYPE: "turn_on",
}
)
@@ -62,7 +64,8 @@ async def async_attach_trigger(
job = HassJob(action)
if config[CONF_TYPE] == "turn_on":
entity_id = config[CONF_ENTITY_ID]
registry = er.async_get(hass)
entity_id = er.async_resolve_entity_id(registry, config[ATTR_ENTITY_ID])
@callback
def _handle_event(event: Event) -> None:
@@ -74,6 +77,7 @@ async def async_attach_trigger(
**trigger_data,
**config,
"description": f"{DOMAIN} - {entity_id}",
"entity_id": entity_id,
}
},
event.context,

View File

@@ -737,17 +737,30 @@ class PipelineInput:
)
start_stage_index = PIPELINE_STAGE_ORDER.index(self.run.start_stage)
end_stage_index = PIPELINE_STAGE_ORDER.index(self.run.end_stage)
prepare_tasks = []
if start_stage_index <= PIPELINE_STAGE_ORDER.index(PipelineStage.STT):
if (
start_stage_index
<= PIPELINE_STAGE_ORDER.index(PipelineStage.STT)
<= end_stage_index
):
# self.stt_metadata can't be None or we'd raise above
prepare_tasks.append(self.run.prepare_speech_to_text(self.stt_metadata)) # type: ignore[arg-type]
if start_stage_index <= PIPELINE_STAGE_ORDER.index(PipelineStage.INTENT):
if (
start_stage_index
<= PIPELINE_STAGE_ORDER.index(PipelineStage.INTENT)
<= end_stage_index
):
prepare_tasks.append(self.run.prepare_recognize_intent())
if start_stage_index <= PIPELINE_STAGE_ORDER.index(PipelineStage.TTS):
if (
start_stage_index
<= PIPELINE_STAGE_ORDER.index(PipelineStage.TTS)
<= end_stage_index
):
prepare_tasks.append(self.run.prepare_text_to_speech())
if prepare_tasks:

View File

@@ -13,7 +13,7 @@
}
},
"vad_sensitivity": {
"name": "Silence sensitivity",
"name": "Finished speaking detection",
"state": {
"default": "Default",
"aggressive": "Aggressive",

View File

@@ -137,16 +137,15 @@ class VoiceCommandSegmenter:
self._reset_seconds_left -= self._seconds_per_chunk
if self._reset_seconds_left <= 0:
self._speech_seconds_left = self.speech_seconds
elif not is_speech:
self._reset_seconds_left = self.reset_seconds
self._silence_seconds_left -= self._seconds_per_chunk
if self._silence_seconds_left <= 0:
return False
else:
if not is_speech:
self._reset_seconds_left = self.reset_seconds
self._silence_seconds_left -= self._seconds_per_chunk
if self._silence_seconds_left <= 0:
return False
else:
# Reset if enough speech
self._reset_seconds_left -= self._seconds_per_chunk
if self._reset_seconds_left <= 0:
self._silence_seconds_left = self.silence_seconds
# Reset if enough speech
self._reset_seconds_left -= self._seconds_per_chunk
if self._reset_seconds_left <= 0:
self._silence_seconds_left = self.silence_seconds
return True

View File

@@ -8,14 +8,8 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import aiohttp_client
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
)
from .const import (
ATTRIBUTION,
AURORA_API,
CONF_THRESHOLD,
COORDINATOR,
@@ -76,34 +70,3 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
class AuroraEntity(CoordinatorEntity[AuroraDataUpdateCoordinator]):
"""Implementation of the base Aurora Entity."""
_attr_attribution = ATTRIBUTION
def __init__(
self,
coordinator: AuroraDataUpdateCoordinator,
name: str,
icon: str,
) -> None:
"""Initialize the Aurora Entity."""
super().__init__(coordinator=coordinator)
self._attr_name = name
self._attr_unique_id = f"{coordinator.latitude}_{coordinator.longitude}"
self._attr_icon = icon
@property
def device_info(self) -> DeviceInfo:
"""Define the device based on name."""
return DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, str(self.unique_id))},
manufacturer="NOAA",
model="Aurora Visibility Sensor",
name=self.coordinator.name,
)

View File

@@ -4,8 +4,8 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AuroraEntity
from .const import COORDINATOR, DOMAIN
from .entity import AuroraEntity
async def async_setup_entry(

View File

@@ -0,0 +1,48 @@
"""The aurora component."""
import logging
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
)
from .const import (
ATTRIBUTION,
DOMAIN,
)
from .coordinator import AuroraDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
class AuroraEntity(CoordinatorEntity[AuroraDataUpdateCoordinator]):
"""Implementation of the base Aurora Entity."""
_attr_attribution = ATTRIBUTION
def __init__(
self,
coordinator: AuroraDataUpdateCoordinator,
name: str,
icon: str,
) -> None:
"""Initialize the Aurora Entity."""
super().__init__(coordinator=coordinator)
self._attr_name = name
self._attr_unique_id = f"{coordinator.latitude}_{coordinator.longitude}"
self._attr_icon = icon
@property
def device_info(self) -> DeviceInfo:
"""Define the device based on name."""
return DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, str(self.unique_id))},
manufacturer="NOAA",
model="Aurora Visibility Sensor",
name=self.coordinator.name,
)

View File

@@ -5,8 +5,8 @@ from homeassistant.const import PERCENTAGE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AuroraEntity
from .const import COORDINATOR, DOMAIN
from .entity import AuroraEntity
async def async_setup_entry(

View File

@@ -47,10 +47,10 @@ class AuroraEntity(Entity):
@property
def device_info(self) -> DeviceInfo:
"""Return device specific attributes."""
return {
"identifiers": {(DOMAIN, self._data[ATTR_SERIAL_NUMBER])},
"manufacturer": MANUFACTURER,
"model": self._data[ATTR_MODEL],
"name": self._data.get(ATTR_DEVICE_NAME, DEFAULT_DEVICE_NAME),
"sw_version": self._data[ATTR_FIRMWARE],
}
return DeviceInfo(
identifiers={(DOMAIN, self._data[ATTR_SERIAL_NUMBER])},
manufacturer=MANUFACTURER,
model=self._data[ATTR_MODEL],
name=self._data.get(ATTR_DEVICE_NAME, DEFAULT_DEVICE_NAME),
sw_version=self._data[ATTR_FIRMWARE],
)

View File

@@ -34,7 +34,7 @@ SENSOR_TYPES = [
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.WATT,
state_class=SensorStateClass.MEASUREMENT,
name="Power Output",
translation_key="power_output",
),
SensorEntityDescription(
key="temp",
@@ -42,14 +42,13 @@ SENSOR_TYPES = [
entity_category=EntityCategory.DIAGNOSTIC,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
name="Temperature",
),
SensorEntityDescription(
key="totalenergy",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
name="Total Energy",
translation_key="total_energy",
),
]
@@ -75,6 +74,8 @@ async def async_setup_entry(
class AuroraSensor(AuroraEntity, SensorEntity):
"""Representation of a Sensor on a Aurora ABB PowerOne Solar inverter."""
_attr_has_entity_name = True
def __init__(
self,
client: AuroraSerialClient,

View File

@@ -18,5 +18,15 @@
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"no_serial_ports": "No com ports found. Need a valid RS485 device to communicate."
}
},
"entity": {
"sensor": {
"power_output": {
"name": "Power Output"
},
"total_energy": {
"name": "Total Energy"
}
}
}
}

View File

@@ -35,7 +35,7 @@ SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
# Internet Services sensors
SensorValueEntityDescription(
key="usedMb",
name="Data used",
translation_key="data_used",
state_class=SensorStateClass.TOTAL_INCREASING,
native_unit_of_measurement=UnitOfInformation.MEGABYTES,
device_class=SensorDeviceClass.DATA_SIZE,
@@ -43,7 +43,7 @@ SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
),
SensorValueEntityDescription(
key="downloadedMb",
name="Downloaded",
translation_key="downloaded",
state_class=SensorStateClass.TOTAL_INCREASING,
native_unit_of_measurement=UnitOfInformation.MEGABYTES,
device_class=SensorDeviceClass.DATA_SIZE,
@@ -51,7 +51,7 @@ SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
),
SensorValueEntityDescription(
key="uploadedMb",
name="Uploaded",
translation_key="uploaded",
state_class=SensorStateClass.TOTAL_INCREASING,
native_unit_of_measurement=UnitOfInformation.MEGABYTES,
device_class=SensorDeviceClass.DATA_SIZE,
@@ -60,21 +60,21 @@ SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
# Mobile Phone Services sensors
SensorValueEntityDescription(
key="national",
name="National calls",
translation_key="national_calls",
state_class=SensorStateClass.TOTAL_INCREASING,
icon="mdi:phone",
value=lambda x: x.get("calls"),
),
SensorValueEntityDescription(
key="mobile",
name="Mobile calls",
translation_key="mobile_calls",
state_class=SensorStateClass.TOTAL_INCREASING,
icon="mdi:phone",
value=lambda x: x.get("calls"),
),
SensorValueEntityDescription(
key="international",
name="International calls",
translation_key="international_calls",
entity_registry_enabled_default=False,
state_class=SensorStateClass.TOTAL_INCREASING,
icon="mdi:phone-plus",
@@ -82,14 +82,14 @@ SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
),
SensorValueEntityDescription(
key="sms",
name="SMS sent",
translation_key="sms_sent",
state_class=SensorStateClass.TOTAL_INCREASING,
icon="mdi:message-processing",
value=lambda x: x.get("calls"),
),
SensorValueEntityDescription(
key="internet",
name="Data used",
translation_key="data_used",
state_class=SensorStateClass.TOTAL_INCREASING,
native_unit_of_measurement=UnitOfInformation.KILOBYTES,
device_class=SensorDeviceClass.DATA_SIZE,
@@ -98,7 +98,7 @@ SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
),
SensorValueEntityDescription(
key="voicemail",
name="Voicemail calls",
translation_key="voicemail_calls",
entity_registry_enabled_default=False,
state_class=SensorStateClass.TOTAL_INCREASING,
icon="mdi:phone",
@@ -106,7 +106,7 @@ SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
),
SensorValueEntityDescription(
key="other",
name="Other calls",
translation_key="other_calls",
entity_registry_enabled_default=False,
state_class=SensorStateClass.TOTAL_INCREASING,
icon="mdi:phone",
@@ -115,13 +115,13 @@ SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
# Generic sensors
SensorValueEntityDescription(
key="daysTotal",
name="Billing cycle length",
translation_key="billing_cycle_length",
native_unit_of_measurement=UnitOfTime.DAYS,
icon="mdi:calendar-range",
),
SensorValueEntityDescription(
key="daysRemaining",
name="Billing cycle remaining",
translation_key="billing_cycle_remaining",
native_unit_of_measurement=UnitOfTime.DAYS,
icon="mdi:calendar-clock",
),

View File

@@ -46,5 +46,42 @@
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
}
},
"entity": {
"sensor": {
"data_used": {
"name": "Data used"
},
"downloaded": {
"name": "Downloaded"
},
"uploaded": {
"name": "Uploaded"
},
"national_calls": {
"name": "National calls"
},
"mobile_calls": {
"name": "Mobile calls"
},
"international_calls": {
"name": "International calls"
},
"sms_sent": {
"name": "SMS sent"
},
"voicemail_calls": {
"name": "Voicemail calls"
},
"other_calls": {
"name": "Other calls"
},
"billing_cycle_length": {
"name": "Billing cycle length"
},
"billing_cycle_remaining": {
"name": "Billing cycle remaining"
}
}
}
}

View File

@@ -1,6 +1,7 @@
"""Allow to set up simple automation rules via the config file."""
from __future__ import annotations
from abc import ABC, abstractmethod
import asyncio
from collections.abc import Callable, Mapping
from dataclasses import dataclass
@@ -153,7 +154,7 @@ def _automations_with_x(
if DOMAIN not in hass.data:
return []
component: EntityComponent[AutomationEntity] = hass.data[DOMAIN]
component: EntityComponent[BaseAutomationEntity] = hass.data[DOMAIN]
return [
automation_entity.entity_id
@@ -169,7 +170,7 @@ def _x_in_automation(
if DOMAIN not in hass.data:
return []
component: EntityComponent[AutomationEntity] = hass.data[DOMAIN]
component: EntityComponent[BaseAutomationEntity] = hass.data[DOMAIN]
if (automation_entity := component.get_entity(entity_id)) is None:
return []
@@ -219,7 +220,7 @@ def automations_with_blueprint(hass: HomeAssistant, blueprint_path: str) -> list
if DOMAIN not in hass.data:
return []
component: EntityComponent[AutomationEntity] = hass.data[DOMAIN]
component: EntityComponent[BaseAutomationEntity] = hass.data[DOMAIN]
return [
automation_entity.entity_id
@@ -234,7 +235,7 @@ def blueprint_in_automation(hass: HomeAssistant, entity_id: str) -> str | None:
if DOMAIN not in hass.data:
return None
component: EntityComponent[AutomationEntity] = hass.data[DOMAIN]
component: EntityComponent[BaseAutomationEntity] = hass.data[DOMAIN]
if (automation_entity := component.get_entity(entity_id)) is None:
return None
@@ -244,7 +245,7 @@ def blueprint_in_automation(hass: HomeAssistant, entity_id: str) -> str | None:
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up all automations."""
hass.data[DOMAIN] = component = EntityComponent[AutomationEntity](
hass.data[DOMAIN] = component = EntityComponent[BaseAutomationEntity](
LOGGER, DOMAIN, hass
)
@@ -262,7 +263,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
await async_get_blueprints(hass).async_populate()
async def trigger_service_handler(
entity: AutomationEntity, service_call: ServiceCall
entity: BaseAutomationEntity, service_call: ServiceCall
) -> None:
"""Handle forced automation trigger, e.g. from frontend."""
await entity.async_trigger(
@@ -310,7 +311,103 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
return True
class AutomationEntity(ToggleEntity, RestoreEntity):
class BaseAutomationEntity(ToggleEntity, ABC):
"""Base class for automation entities."""
raw_config: ConfigType | None
@property
def capability_attributes(self) -> dict[str, Any] | None:
"""Return capability attributes."""
if self.unique_id is not None:
return {CONF_ID: self.unique_id}
return None
@property
@abstractmethod
def referenced_areas(self) -> set[str]:
"""Return a set of referenced areas."""
@property
@abstractmethod
def referenced_blueprint(self) -> str | None:
"""Return referenced blueprint or None."""
@property
@abstractmethod
def referenced_devices(self) -> set[str]:
"""Return a set of referenced devices."""
@property
@abstractmethod
def referenced_entities(self) -> set[str]:
"""Return a set of referenced entities."""
@abstractmethod
async def async_trigger(
self,
run_variables: dict[str, Any],
context: Context | None = None,
skip_condition: bool = False,
) -> None:
"""Trigger automation."""
class UnavailableAutomationEntity(BaseAutomationEntity):
"""A non-functional automation entity with its state set to unavailable.
This class is instatiated when an automation fails to validate.
"""
_attr_should_poll = False
_attr_available = False
def __init__(
self,
automation_id: str | None,
name: str,
raw_config: ConfigType | None,
) -> None:
"""Initialize an automation entity."""
self._name = name
self._attr_unique_id = automation_id
self.raw_config = raw_config
@property
def name(self) -> str:
"""Return the name of the entity."""
return self._name
@property
def referenced_areas(self) -> set[str]:
"""Return a set of referenced areas."""
return set()
@property
def referenced_blueprint(self) -> str | None:
"""Return referenced blueprint or None."""
return None
@property
def referenced_devices(self) -> set[str]:
"""Return a set of referenced devices."""
return set()
@property
def referenced_entities(self) -> set[str]:
"""Return a set of referenced entities."""
return set()
async def async_trigger(
self,
run_variables: dict[str, Any],
context: Context | None = None,
skip_condition: bool = False,
) -> None:
"""Trigger automation."""
class AutomationEntity(BaseAutomationEntity, RestoreEntity):
"""Entity to show status of entity."""
_attr_should_poll = False
@@ -363,8 +460,6 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
}
if self.action_script.supports_max:
attrs[ATTR_MAX] = self.action_script.max_runs
if self.unique_id is not None:
attrs[CONF_ID] = self.unique_id
return attrs
@property
@@ -686,6 +781,7 @@ class AutomationEntityConfig:
list_no: int
raw_blueprint_inputs: ConfigType | None
raw_config: ConfigType | None
validation_failed: bool
async def _prepare_automation_config(
@@ -700,9 +796,14 @@ async def _prepare_automation_config(
for list_no, config_block in enumerate(conf):
raw_config = cast(AutomationConfig, config_block).raw_config
raw_blueprint_inputs = cast(AutomationConfig, config_block).raw_blueprint_inputs
validation_failed = cast(AutomationConfig, config_block).validation_failed
automation_configs.append(
AutomationEntityConfig(
config_block, list_no, raw_blueprint_inputs, raw_config
config_block,
list_no,
raw_blueprint_inputs,
raw_config,
validation_failed,
)
)
@@ -718,9 +819,9 @@ def _automation_name(automation_config: AutomationEntityConfig) -> str:
async def _create_automation_entities(
hass: HomeAssistant, automation_configs: list[AutomationEntityConfig]
) -> list[AutomationEntity]:
) -> list[BaseAutomationEntity]:
"""Create automation entities from prepared configuration."""
entities: list[AutomationEntity] = []
entities: list[BaseAutomationEntity] = []
for automation_config in automation_configs:
config_block = automation_config.config_block
@@ -728,6 +829,16 @@ async def _create_automation_entities(
automation_id: str | None = config_block.get(CONF_ID)
name = _automation_name(automation_config)
if automation_config.validation_failed:
entities.append(
UnavailableAutomationEntity(
automation_id,
name,
automation_config.raw_config,
)
)
continue
initial_state: bool | None = config_block.get(CONF_INITIAL_STATE)
action_script = Script(
@@ -786,18 +897,18 @@ async def _create_automation_entities(
async def _async_process_config(
hass: HomeAssistant,
config: dict[str, Any],
component: EntityComponent[AutomationEntity],
component: EntityComponent[BaseAutomationEntity],
) -> None:
"""Process config and add automations."""
def automation_matches_config(
automation: AutomationEntity, config: AutomationEntityConfig
automation: BaseAutomationEntity, config: AutomationEntityConfig
) -> bool:
name = _automation_name(config)
return automation.name == name and automation.raw_config == config.raw_config
def find_matches(
automations: list[AutomationEntity],
automations: list[BaseAutomationEntity],
automation_configs: list[AutomationEntityConfig],
) -> tuple[set[int], set[int]]:
"""Find matches between a list of automation entities and a list of configurations.
@@ -843,7 +954,7 @@ async def _async_process_config(
return automation_matches, config_matches
automation_configs = await _prepare_automation_config(hass, config)
automations: list[AutomationEntity] = list(component.entities)
automations: list[BaseAutomationEntity] = list(component.entities)
# Find automations and configurations which have matches
automation_matches, config_matches = find_matches(automations, automation_configs)
@@ -865,8 +976,6 @@ async def _async_process_config(
entities = await _create_automation_entities(hass, updated_automation_configs)
await component.async_add_entities(entities)
return
async def _async_process_if(
hass: HomeAssistant, name: str, config: dict[str, Any]
@@ -970,7 +1079,7 @@ def websocket_config(
msg: dict[str, Any],
) -> None:
"""Get automation config."""
component: EntityComponent[AutomationEntity] = hass.data[DOMAIN]
component: EntityComponent[BaseAutomationEntity] = hass.data[DOMAIN]
automation = component.get_entity(msg["entity_id"])

View File

@@ -41,7 +41,15 @@ from .helpers import async_get_blueprints
PACKAGE_MERGE_HINT = "list"
_CONDITION_SCHEMA = vol.All(cv.ensure_list, [cv.CONDITION_SCHEMA])
_MINIMAL_PLATFORM_SCHEMA = vol.Schema(
{
CONF_ID: str,
CONF_ALIAS: cv.string,
vol.Optional(CONF_DESCRIPTION): cv.string,
},
extra=vol.ALLOW_EXTRA,
)
PLATFORM_SCHEMA = vol.All(
cv.deprecated(CONF_HIDE_ENTITY),
@@ -55,7 +63,7 @@ PLATFORM_SCHEMA = vol.All(
vol.Optional(CONF_INITIAL_STATE): cv.boolean,
vol.Optional(CONF_HIDE_ENTITY): cv.boolean,
vol.Required(CONF_TRIGGER): cv.TRIGGER_SCHEMA,
vol.Optional(CONF_CONDITION): _CONDITION_SCHEMA,
vol.Optional(CONF_CONDITION): cv.CONDITIONS_SCHEMA,
vol.Optional(CONF_VARIABLES): cv.SCRIPT_VARIABLES_SCHEMA,
vol.Optional(CONF_TRIGGER_VARIABLES): cv.SCRIPT_VARIABLES_SCHEMA,
vol.Required(CONF_ACTION): cv.SCRIPT_SCHEMA,
@@ -68,6 +76,7 @@ PLATFORM_SCHEMA = vol.All(
async def _async_validate_config_item(
hass: HomeAssistant,
config: ConfigType,
raise_on_errors: bool,
warn_on_errors: bool,
) -> AutomationConfig:
"""Validate config item."""
@@ -104,6 +113,15 @@ async def _async_validate_config_item(
)
return
def _minimal_config() -> AutomationConfig:
"""Try validating id, alias and description."""
minimal_config = _MINIMAL_PLATFORM_SCHEMA(config)
automation_config = AutomationConfig(minimal_config)
automation_config.raw_blueprint_inputs = raw_blueprint_inputs
automation_config.raw_config = raw_config
automation_config.validation_failed = True
return automation_config
if blueprint.is_blueprint_instance_config(config):
uses_blueprint = True
blueprints = async_get_blueprints(hass)
@@ -115,7 +133,9 @@ async def _async_validate_config_item(
"Failed to generate automation from blueprint: %s",
err,
)
raise
if raise_on_errors:
raise
return _minimal_config()
raw_blueprint_inputs = blueprint_inputs.config_with_inputs
@@ -130,7 +150,9 @@ async def _async_validate_config_item(
blueprint_inputs.inputs,
err,
)
raise HomeAssistantError from err
if raise_on_errors:
raise HomeAssistantError(err) from err
return _minimal_config()
automation_name = "Unnamed automation"
if isinstance(config, Mapping):
@@ -143,10 +165,16 @@ async def _async_validate_config_item(
validated_config = PLATFORM_SCHEMA(config)
except vol.Invalid as err:
_log_invalid_automation(err, automation_name, "could not be validated", config)
raise
if raise_on_errors:
raise
return _minimal_config()
automation_config = AutomationConfig(validated_config)
automation_config.raw_blueprint_inputs = raw_blueprint_inputs
automation_config.raw_config = raw_config
try:
validated_config[CONF_TRIGGER] = await async_validate_trigger_config(
automation_config[CONF_TRIGGER] = await async_validate_trigger_config(
hass, validated_config[CONF_TRIGGER]
)
except (
@@ -156,11 +184,14 @@ async def _async_validate_config_item(
_log_invalid_automation(
err, automation_name, "failed to setup triggers", validated_config
)
raise
if raise_on_errors:
raise
automation_config.validation_failed = True
return automation_config
if CONF_CONDITION in validated_config:
try:
validated_config[CONF_CONDITION] = await async_validate_conditions_config(
automation_config[CONF_CONDITION] = await async_validate_conditions_config(
hass, validated_config[CONF_CONDITION]
)
except (
@@ -170,10 +201,13 @@ async def _async_validate_config_item(
_log_invalid_automation(
err, automation_name, "failed to setup conditions", validated_config
)
raise
if raise_on_errors:
raise
automation_config.validation_failed = True
return automation_config
try:
validated_config[CONF_ACTION] = await script.async_validate_actions_config(
automation_config[CONF_ACTION] = await script.async_validate_actions_config(
hass, validated_config[CONF_ACTION]
)
except (
@@ -183,11 +217,11 @@ async def _async_validate_config_item(
_log_invalid_automation(
err, automation_name, "failed to setup actions", validated_config
)
raise
if raise_on_errors:
raise
automation_config.validation_failed = True
return automation_config
automation_config = AutomationConfig(validated_config)
automation_config.raw_blueprint_inputs = raw_blueprint_inputs
automation_config.raw_config = raw_config
return automation_config
@@ -196,6 +230,7 @@ class AutomationConfig(dict):
raw_config: dict[str, Any] | None = None
raw_blueprint_inputs: dict[str, Any] | None = None
validation_failed: bool = False
async def _try_async_validate_config_item(
@@ -204,7 +239,7 @@ async def _try_async_validate_config_item(
) -> AutomationConfig | None:
"""Validate config item."""
try:
return await _async_validate_config_item(hass, config, True)
return await _async_validate_config_item(hass, config, False, True)
except (vol.Invalid, HomeAssistantError):
return None
@@ -215,7 +250,7 @@ async def async_validate_config_item(
config: dict[str, Any],
) -> AutomationConfig | None:
"""Validate config item, called by EditAutomationConfigView."""
return await _async_validate_config_item(hass, config, False)
return await _async_validate_config_item(hass, config, True, False)
async def async_validate_config(hass: HomeAssistant, config: ConfigType) -> ConfigType:

View File

@@ -2,16 +2,22 @@
from __future__ import annotations
from asyncio import gather
from dataclasses import dataclass
from datetime import timedelta
from aiohttp import ClientSession
from async_timeout import timeout
from python_awair import Awair, AwairLocal
from python_awair.air_data import AirData
from python_awair.devices import AwairBaseDevice, AwairLocalDevice
from python_awair.exceptions import AuthError, AwairError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST, Platform
from homeassistant.const import (
CONF_ACCESS_TOKEN,
CONF_HOST,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.aiohttp_client import async_get_clientsession
@@ -23,7 +29,6 @@ from .const import (
LOGGER,
UPDATE_INTERVAL_CLOUD,
UPDATE_INTERVAL_LOCAL,
AwairResult,
)
PLATFORMS = [Platform.SENSOR]
@@ -72,6 +77,14 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
return unload_ok
@dataclass
class AwairResult:
"""Wrapper class to hold an awair device and set of air data."""
device: AwairBaseDevice
air_data: AirData
class AwairDataUpdateCoordinator(DataUpdateCoordinator[dict[str, AwairResult]]):
"""Define a wrapper class to update Awair data."""

View File

@@ -1,28 +1,9 @@
"""Constants for the Awair component."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
import logging
from python_awair.air_data import AirData
from python_awair.devices import AwairBaseDevice
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
LIGHT_LUX,
PERCENTAGE,
UnitOfSoundPressure,
UnitOfTemperature,
)
API_CO2 = "carbon_dioxide"
API_DUST = "dust"
API_HUMID = "humidity"
@@ -39,109 +20,7 @@ ATTRIBUTION = "Awair air quality sensor"
DOMAIN = "awair"
DUST_ALIASES = [API_PM25, API_PM10]
LOGGER = logging.getLogger(__package__)
UPDATE_INTERVAL_CLOUD = timedelta(minutes=5)
UPDATE_INTERVAL_LOCAL = timedelta(seconds=30)
@dataclass
class AwairRequiredKeysMixin:
"""Mixin for required keys."""
unique_id_tag: str
@dataclass
class AwairSensorEntityDescription(SensorEntityDescription, AwairRequiredKeysMixin):
"""Describes Awair sensor entity."""
SENSOR_TYPE_SCORE = AwairSensorEntityDescription(
key=API_SCORE,
icon="mdi:blur",
native_unit_of_measurement=PERCENTAGE,
name="Score",
unique_id_tag="score", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
)
SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
AwairSensorEntityDescription(
key=API_HUMID,
device_class=SensorDeviceClass.HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
name="Humidity",
unique_id_tag="HUMID", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_LUX,
device_class=SensorDeviceClass.ILLUMINANCE,
native_unit_of_measurement=LIGHT_LUX,
name="Illuminance",
unique_id_tag="illuminance",
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_SPL_A,
device_class=SensorDeviceClass.SOUND_PRESSURE,
native_unit_of_measurement=UnitOfSoundPressure.WEIGHTED_DECIBEL_A,
name="Sound level",
unique_id_tag="sound_level",
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_VOC,
icon="mdi:molecule",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
name="Volatile organic compounds",
unique_id_tag="VOC", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_TEMP,
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
name="Temperature",
unique_id_tag="TEMP", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_CO2,
device_class=SensorDeviceClass.CO2,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
name="Carbon dioxide",
unique_id_tag="CO2", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
)
SENSOR_TYPES_DUST: tuple[AwairSensorEntityDescription, ...] = (
AwairSensorEntityDescription(
key=API_PM25,
device_class=SensorDeviceClass.PM25,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
name="PM2.5",
unique_id_tag="PM25", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_PM10,
device_class=SensorDeviceClass.PM10,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
name="PM10",
unique_id_tag="PM10", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
)
@dataclass
class AwairResult:
"""Wrapper class to hold an awair device and set of air data."""
device: AwairBaseDevice
air_data: AirData

View File

@@ -1,14 +1,30 @@
"""Support for Awair sensors."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, cast
from python_awair.air_data import AirData
from python_awair.devices import AwairBaseDevice, AwairLocalDevice
from homeassistant.components.sensor import SensorEntity
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_CONNECTIONS, ATTR_SW_VERSION
from homeassistant.const import (
ATTR_CONNECTIONS,
ATTR_SW_VERSION,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
LIGHT_LUX,
PERCENTAGE,
UnitOfSoundPressure,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.entity import DeviceInfo
@@ -17,18 +33,106 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import AwairDataUpdateCoordinator, AwairResult
from .const import (
API_CO2,
API_DUST,
API_HUMID,
API_LUX,
API_PM10,
API_PM25,
API_SCORE,
API_SPL_A,
API_TEMP,
API_VOC,
ATTRIBUTION,
DOMAIN,
DUST_ALIASES,
SENSOR_TYPE_SCORE,
SENSOR_TYPES,
SENSOR_TYPES_DUST,
AwairSensorEntityDescription,
)
DUST_ALIASES = [API_PM25, API_PM10]
@dataclass
class AwairRequiredKeysMixin:
"""Mixin for required keys."""
unique_id_tag: str
@dataclass
class AwairSensorEntityDescription(SensorEntityDescription, AwairRequiredKeysMixin):
"""Describes Awair sensor entity."""
SENSOR_TYPE_SCORE = AwairSensorEntityDescription(
key=API_SCORE,
icon="mdi:blur",
native_unit_of_measurement=PERCENTAGE,
translation_key="score",
unique_id_tag="score", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
)
SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
AwairSensorEntityDescription(
key=API_HUMID,
device_class=SensorDeviceClass.HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
unique_id_tag="HUMID", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_LUX,
device_class=SensorDeviceClass.ILLUMINANCE,
native_unit_of_measurement=LIGHT_LUX,
unique_id_tag="illuminance",
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_SPL_A,
device_class=SensorDeviceClass.SOUND_PRESSURE,
native_unit_of_measurement=UnitOfSoundPressure.WEIGHTED_DECIBEL_A,
translation_key="sound_level",
unique_id_tag="sound_level",
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_VOC,
icon="mdi:molecule",
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
unique_id_tag="VOC", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_TEMP,
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
unique_id_tag="TEMP", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_CO2,
device_class=SensorDeviceClass.CO2,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
unique_id_tag="CO2", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
)
SENSOR_TYPES_DUST: tuple[AwairSensorEntityDescription, ...] = (
AwairSensorEntityDescription(
key=API_PM25,
device_class=SensorDeviceClass.PM25,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
unique_id_tag="PM25", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
AwairSensorEntityDescription(
key=API_PM10,
device_class=SensorDeviceClass.PM10,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
unique_id_tag="PM10", # matches legacy format
state_class=SensorStateClass.MEASUREMENT,
),
)

View File

@@ -48,5 +48,15 @@
"unreachable": "[%key:common::config_flow::error::cannot_connect%]"
},
"flow_title": "{model} ({device_id})"
},
"entity": {
"sensor": {
"score": {
"name": "Score"
},
"sound_level": {
"name": "Sound level"
}
}
}
}

View File

@@ -256,7 +256,7 @@ ENTITY_CONDITIONS = {
CONDITION_SCHEMA = cv.DEVICE_CONDITION_BASE_SCHEMA.extend(
{
vol.Required(CONF_ENTITY_ID): cv.entity_id,
vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
vol.Required(CONF_TYPE): vol.In(IS_OFF + IS_ON),
vol.Optional(CONF_FOR): cv.positive_time_period_dict,
}
@@ -287,7 +287,7 @@ async def async_get_conditions(
**template,
"condition": "device",
"device_id": device_id,
"entity_id": entry.entity_id,
"entity_id": entry.id,
"domain": DOMAIN,
}
for template in templates

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

@@ -302,7 +302,7 @@
}
},
"device_class": {
"co": "carbon_monoxide",
"co": "carbon monoxide",
"cold": "cold",
"gas": "gas",
"heat": "heat",

View File

@@ -41,6 +41,8 @@ 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."""
@@ -48,9 +50,10 @@ class BlinkSyncModule(AlarmControlPanelEntity):
self.sync = sync
self._name = name
self._attr_unique_id = sync.serial
self._attr_name = f"{DOMAIN} {name}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, sync.serial)}, name=name, manufacturer=DEFAULT_BRAND
identifiers={(DOMAIN, sync.serial)},
name=f"{DOMAIN} {name}",
manufacturer=DEFAULT_BRAND,
)
def update(self) -> None:

View File

@@ -27,17 +27,15 @@ _LOGGER = logging.getLogger(__name__)
BINARY_SENSORS_TYPES: tuple[BinarySensorEntityDescription, ...] = (
BinarySensorEntityDescription(
key=TYPE_BATTERY,
name="Battery",
device_class=BinarySensorDeviceClass.BATTERY,
entity_category=EntityCategory.DIAGNOSTIC,
),
BinarySensorEntityDescription(
key=TYPE_CAMERA_ARMED,
name="Camera Armed",
translation_key="camera_armed",
),
BinarySensorEntityDescription(
key=TYPE_MOTION_DETECTED,
name="Motion Detected",
device_class=BinarySensorDeviceClass.MOTION,
),
)
@@ -60,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,11 +38,13 @@ 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):
"""Initialize a camera."""
super().__init__()
self.data = data
self._attr_name = f"{DOMAIN} {name}"
self._camera = camera
self._attr_unique_id = f"{camera.serial}-camera"
self._attr_device_info = DeviceInfo(

View File

@@ -25,14 +25,13 @@ _LOGGER = logging.getLogger(__name__)
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=TYPE_TEMPERATURE,
name="Temperature",
native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
device_class=SensorDeviceClass.TEMPERATURE,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key=TYPE_WIFI_STRENGTH,
name="Wifi Signal",
translation_key="wifi_rssi",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -57,10 +56,11 @@ async def async_setup_entry(
class BlinkSensor(SensorEntity):
"""A Blink camera sensor."""
_attr_has_entity_name = True
def __init__(self, data, camera, description: SensorEntityDescription) -> None:
"""Initialize sensors from Blink camera."""
self.entity_description = description
self._attr_name = f"{DOMAIN} {camera} {description.name}"
self.data = data
self._camera = data.cameras[camera]
self._attr_unique_id = f"{self._camera.serial}-{description.key}"
@@ -71,7 +71,7 @@ class BlinkSensor(SensorEntity):
)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self._camera.serial)},
name=camera,
name=f"{DOMAIN} {camera}",
manufacturer=DEFAULT_BRAND,
model=self._camera.camera_type,
)

View File

@@ -34,5 +34,17 @@
"description": "Configure Blink integration"
}
}
},
"entity": {
"sensor": {
"wifi_rssi": {
"name": "Wi-Fi RSSI"
}
},
"binary_sensor": {
"camera_armed": {
"name": "Camera armed"
}
}
}
}

View File

@@ -1,6 +1,8 @@
"""Import logic for blueprint."""
from __future__ import annotations
from contextlib import suppress
from dataclasses import dataclass
import html
import re
@@ -28,6 +30,10 @@ GITHUB_FILE_PATTERN = re.compile(
r"^https://github.com/(?P<repository>.+)/blob/(?P<path>.+)$"
)
WEBSITE_PATTERN = re.compile(
r"^https://(?P<subdomain>[a-z0-9-]+)\.home-assistant\.io/(?P<path>.+).yaml$"
)
COMMUNITY_TOPIC_SCHEMA = vol.Schema(
{
"slug": str,
@@ -219,18 +225,37 @@ async def fetch_blueprint_from_github_gist_url(
)
async def fetch_blueprint_from_website_url(
hass: HomeAssistant, url: str
) -> ImportedBlueprint:
"""Get a blueprint from our website."""
if (WEBSITE_PATTERN.match(url)) is None:
raise UnsupportedUrl("Not a Home Assistant website URL")
session = aiohttp_client.async_get_clientsession(hass)
resp = await session.get(url, raise_for_status=True)
raw_yaml = await resp.text()
data = yaml.parse_yaml(raw_yaml)
assert isinstance(data, dict)
blueprint = Blueprint(data)
parsed_import_url = yarl.URL(url)
suggested_filename = f"homeassistant/{parsed_import_url.parts[-1][:-5]}"
return ImportedBlueprint(suggested_filename, raw_yaml, blueprint)
async def fetch_blueprint_from_url(hass: HomeAssistant, url: str) -> ImportedBlueprint:
"""Get a blueprint from a url."""
for func in (
fetch_blueprint_from_community_post,
fetch_blueprint_from_github_url,
fetch_blueprint_from_github_gist_url,
fetch_blueprint_from_website_url,
):
try:
with suppress(UnsupportedUrl):
imported_bp = await func(hass, url)
imported_bp.blueprint.update_metadata(source_url=url)
return imported_bp
except UnsupportedUrl:
pass
raise HomeAssistantError("Unsupported url")
raise HomeAssistantError("Unsupported URL")

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

@@ -123,7 +123,7 @@ class BMWBinarySensorEntityDescription(
SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
BMWBinarySensorEntityDescription(
key="lids",
name="Lids",
translation_key="lids",
device_class=BinarySensorDeviceClass.OPENING,
icon="mdi:car-door-lock",
# device class opening: On means open, Off means closed
@@ -134,7 +134,7 @@ SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
),
BMWBinarySensorEntityDescription(
key="windows",
name="Windows",
translation_key="windows",
device_class=BinarySensorDeviceClass.OPENING,
icon="mdi:car-door",
# device class opening: On means open, Off means closed
@@ -145,7 +145,7 @@ SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
),
BMWBinarySensorEntityDescription(
key="door_lock_state",
name="Door lock state",
translation_key="door_lock_state",
device_class=BinarySensorDeviceClass.LOCK,
icon="mdi:car-key",
# device class lock: On means unlocked, Off means locked
@@ -158,7 +158,7 @@ SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
),
BMWBinarySensorEntityDescription(
key="condition_based_services",
name="Condition based services",
translation_key="condition_based_services",
device_class=BinarySensorDeviceClass.PROBLEM,
icon="mdi:wrench",
# device class problem: On means problem detected, Off means no problem
@@ -167,7 +167,7 @@ SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
),
BMWBinarySensorEntityDescription(
key="check_control_messages",
name="Check control messages",
translation_key="check_control_messages",
device_class=BinarySensorDeviceClass.PROBLEM,
icon="mdi:car-tire-alert",
# device class problem: On means problem detected, Off means no problem
@@ -177,7 +177,7 @@ SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
# electric
BMWBinarySensorEntityDescription(
key="charging_status",
name="Charging status",
translation_key="charging_status",
device_class=BinarySensorDeviceClass.BATTERY_CHARGING,
icon="mdi:ev-station",
# device class power: On means power detected, Off means no power
@@ -185,14 +185,14 @@ SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
),
BMWBinarySensorEntityDescription(
key="connection_status",
name="Connection status",
translation_key="connection_status",
device_class=BinarySensorDeviceClass.PLUG,
icon="mdi:car-electric",
value_fn=lambda v: v.fuel_and_battery.is_charger_connected,
),
BMWBinarySensorEntityDescription(
key="is_pre_entry_climatization_enabled",
name="Pre entry climatization",
translation_key="is_pre_entry_climatization_enabled",
icon="mdi:car-seat-heater",
value_fn=lambda v: v.charging_profile.is_pre_entry_climatization_enabled
if v.charging_profile

View File

@@ -6,12 +6,14 @@ from dataclasses import dataclass
import logging
from typing import TYPE_CHECKING, Any
from bimmer_connected.models import MyBMWAPIError
from bimmer_connected.vehicle import MyBMWVehicle
from bimmer_connected.vehicle.remote_services import RemoteServiceStatus
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BMWBaseEntity
@@ -32,37 +34,45 @@ class BMWButtonEntityDescription(ButtonEntityDescription):
[MyBMWVehicle], Coroutine[Any, Any, RemoteServiceStatus]
] | None = None
account_function: Callable[[BMWDataUpdateCoordinator], Coroutine] | None = None
is_available: Callable[[MyBMWVehicle], bool] = lambda _: True
BUTTON_TYPES: tuple[BMWButtonEntityDescription, ...] = (
BMWButtonEntityDescription(
key="light_flash",
translation_key="light_flash",
icon="mdi:car-light-alert",
name="Flash lights",
remote_function=lambda vehicle: vehicle.remote_services.trigger_remote_light_flash(),
),
BMWButtonEntityDescription(
key="sound_horn",
translation_key="sound_horn",
icon="mdi:bullhorn",
name="Sound horn",
remote_function=lambda vehicle: vehicle.remote_services.trigger_remote_horn(),
),
BMWButtonEntityDescription(
key="activate_air_conditioning",
translation_key="activate_air_conditioning",
icon="mdi:hvac",
name="Activate air conditioning",
remote_function=lambda vehicle: vehicle.remote_services.trigger_remote_air_conditioning(),
),
BMWButtonEntityDescription(
key="deactivate_air_conditioning",
icon="mdi:hvac-off",
name="Deactivate air conditioning",
remote_function=lambda vehicle: vehicle.remote_services.trigger_remote_air_conditioning_stop(),
is_available=lambda vehicle: vehicle.is_remote_climate_stop_enabled,
),
BMWButtonEntityDescription(
key="find_vehicle",
translation_key="find_vehicle",
icon="mdi:crosshairs-question",
name="Find vehicle",
remote_function=lambda vehicle: vehicle.remote_services.trigger_remote_vehicle_finder(),
),
BMWButtonEntityDescription(
key="refresh",
translation_key="refresh",
icon="mdi:refresh",
name="Refresh from cloud",
account_function=lambda coordinator: coordinator.async_request_refresh(),
enabled_when_read_only=True,
),
@@ -84,7 +94,7 @@ async def async_setup_entry(
[
BMWButton(coordinator, vehicle, description)
for description in BUTTON_TYPES
if not coordinator.read_only
if (not coordinator.read_only and description.is_available(vehicle))
or (coordinator.read_only and description.enabled_when_read_only)
]
)
@@ -111,7 +121,10 @@ class BMWButton(BMWBaseEntity, ButtonEntity):
async def async_press(self) -> None:
"""Press the button."""
if self.entity_description.remote_function:
await self.entity_description.remote_function(self.vehicle)
try:
await self.entity_description.remote_function(self.vehicle)
except MyBMWAPIError as ex:
raise HomeAssistantError(ex) from ex
elif self.entity_description.account_function:
_LOGGER.warning(
"The 'Refresh from cloud' button is deprecated. Use the"
@@ -120,6 +133,9 @@ class BMWButton(BMWBaseEntity, ButtonEntity):
" https://www.home-assistant.io/integrations/bmw_connected_drive/#update-the-state--refresh-from-api"
" for details"
)
await self.entity_description.account_function(self.coordinator)
try:
await self.entity_description.account_function(self.coordinator)
except MyBMWAPIError as ex:
raise HomeAssistantError(ex) from ex
self.coordinator.async_update_listeners()

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

@@ -4,12 +4,14 @@ from __future__ import annotations
import logging
from typing import Any
from bimmer_connected.models import MyBMWAPIError
from bimmer_connected.vehicle import MyBMWVehicle
from bimmer_connected.vehicle.doors_windows import LockState
from homeassistant.components.lock import LockEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BMWBaseEntity
@@ -44,7 +46,7 @@ async def async_setup_entry(
class BMWLock(BMWBaseEntity, LockEntity):
"""Representation of a MyBMW vehicle lock."""
_attr_name = "Lock"
_attr_translation_key = "lock"
def __init__(
self,
@@ -66,7 +68,12 @@ class BMWLock(BMWBaseEntity, LockEntity):
# update callback response
self._attr_is_locked = True
self.async_write_ha_state()
await self.vehicle.remote_services.trigger_remote_door_lock()
try:
await self.vehicle.remote_services.trigger_remote_door_lock()
except MyBMWAPIError as ex:
self._attr_is_locked = False
self.async_write_ha_state()
raise HomeAssistantError(ex) from ex
self.coordinator.async_update_listeners()
@@ -79,7 +86,12 @@ class BMWLock(BMWBaseEntity, LockEntity):
# update callback response
self._attr_is_locked = False
self.async_write_ha_state()
await self.vehicle.remote_services.trigger_remote_door_unlock()
try:
await self.vehicle.remote_services.trigger_remote_door_unlock()
except MyBMWAPIError as ex:
self._attr_is_locked = True
self.async_write_ha_state()
raise HomeAssistantError(ex) from ex
self.coordinator.async_update_listeners()

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

@@ -4,6 +4,7 @@ from __future__ import annotations
import logging
from typing import Any, cast
from bimmer_connected.models import MyBMWAPIError
from bimmer_connected.vehicle import MyBMWVehicle
from homeassistant.components.notify import (
@@ -19,6 +20,7 @@ from homeassistant.const import (
CONF_ENTITY_ID,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import DOMAIN
@@ -87,7 +89,11 @@ class BMWNotificationService(BaseNotificationService):
if k in ATTR_LOCATION_ATTRIBUTES
}
)
await vehicle.remote_services.trigger_send_poi(location_dict)
try:
await vehicle.remote_services.trigger_send_poi(location_dict)
except TypeError as ex:
raise ValueError(str(ex)) from ex
except MyBMWAPIError as ex:
raise HomeAssistantError(ex) from ex
else:
raise ValueError(f"'data.{ATTR_LOCATION}' is required.")

View File

@@ -45,7 +45,7 @@ class BMWNumberEntityDescription(NumberEntityDescription, BMWRequiredKeysMixin):
NUMBER_TYPES: list[BMWNumberEntityDescription] = [
BMWNumberEntityDescription(
key="target_soc",
name="Target SoC",
translation_key="target_soc",
device_class=NumberDeviceClass.BATTERY,
is_available=lambda v: v.is_remote_set_target_soc_enabled,
native_max_value=100.0,

View File

@@ -4,6 +4,7 @@ from dataclasses import dataclass
import logging
from typing import Any
from bimmer_connected.models import MyBMWAPIError
from bimmer_connected.vehicle import MyBMWVehicle
from bimmer_connected.vehicle.charging_profile import ChargingMode
@@ -11,6 +12,7 @@ from homeassistant.components.select import SelectEntity, SelectEntityDescriptio
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfElectricCurrent
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BMWBaseEntity
@@ -39,7 +41,7 @@ class BMWSelectEntityDescription(SelectEntityDescription, BMWRequiredKeysMixin):
SELECT_TYPES: dict[str, BMWSelectEntityDescription] = {
"ac_limit": BMWSelectEntityDescription(
key="ac_limit",
name="AC Charging Limit",
translation_key="ac_limit",
is_available=lambda v: v.is_remote_set_ac_limit_enabled,
dynamic_options=lambda v: [
str(lim) for lim in v.charging_profile.ac_available_limits # type: ignore[union-attr]
@@ -53,7 +55,7 @@ SELECT_TYPES: dict[str, BMWSelectEntityDescription] = {
),
"charging_mode": BMWSelectEntityDescription(
key="charging_mode",
name="Charging Mode",
translation_key="charging_mode",
is_available=lambda v: v.is_charging_plan_supported,
options=[c.value for c in ChargingMode if c != ChargingMode.UNKNOWN],
current_option=lambda v: str(v.charging_profile.charging_mode.value), # type: ignore[union-attr]
@@ -123,6 +125,9 @@ class BMWSelect(BMWBaseEntity, SelectEntity):
self.vehicle.vin,
option,
)
await self.entity_description.remote_service(self.vehicle, option)
try:
await self.entity_description.remote_service(self.vehicle, option)
except MyBMWAPIError as ex:
raise HomeAssistantError(ex) from ex
self.coordinator.async_update_listeners()

View File

@@ -55,7 +55,7 @@ SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
# --- Generic ---
"ac_current_limit": BMWSensorEntityDescription(
key="ac_current_limit",
name="AC current limit",
translation_key="ac_current_limit",
key_class="charging_profile",
unit_type=UnitOfElectricCurrent.AMPERE,
icon="mdi:current-ac",
@@ -63,34 +63,34 @@ SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
),
"charging_start_time": BMWSensorEntityDescription(
key="charging_start_time",
name="Charging start time",
translation_key="charging_start_time",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.TIMESTAMP,
entity_registry_enabled_default=False,
),
"charging_end_time": BMWSensorEntityDescription(
key="charging_end_time",
name="Charging end time",
translation_key="charging_end_time",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.TIMESTAMP,
),
"charging_status": BMWSensorEntityDescription(
key="charging_status",
name="Charging status",
translation_key="charging_status",
key_class="fuel_and_battery",
icon="mdi:ev-station",
value=lambda x, y: x.value,
),
"charging_target": BMWSensorEntityDescription(
key="charging_target",
name="Charging target",
translation_key="charging_target",
key_class="fuel_and_battery",
icon="mdi:battery-charging-high",
unit_type=PERCENTAGE,
),
"remaining_battery_percent": BMWSensorEntityDescription(
key="remaining_battery_percent",
name="Remaining battery percent",
translation_key="remaining_battery_percent",
key_class="fuel_and_battery",
unit_type=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
@@ -98,14 +98,14 @@ SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
# --- Specific ---
"mileage": BMWSensorEntityDescription(
key="mileage",
name="Mileage",
translation_key="mileage",
icon="mdi:speedometer",
unit_type=LENGTH,
value=lambda x, hass: convert_and_round(x, hass.config.units.length, 2),
),
"remaining_range_total": BMWSensorEntityDescription(
key="remaining_range_total",
name="Remaining range total",
translation_key="remaining_range_total",
key_class="fuel_and_battery",
icon="mdi:map-marker-distance",
unit_type=LENGTH,
@@ -113,7 +113,7 @@ SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
),
"remaining_range_electric": BMWSensorEntityDescription(
key="remaining_range_electric",
name="Remaining range electric",
translation_key="remaining_range_electric",
key_class="fuel_and_battery",
icon="mdi:map-marker-distance",
unit_type=LENGTH,
@@ -121,7 +121,7 @@ SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
),
"remaining_range_fuel": BMWSensorEntityDescription(
key="remaining_range_fuel",
name="Remaining range fuel",
translation_key="remaining_range_fuel",
key_class="fuel_and_battery",
icon="mdi:map-marker-distance",
unit_type=LENGTH,
@@ -129,7 +129,7 @@ SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
),
"remaining_fuel": BMWSensorEntityDescription(
key="remaining_fuel",
name="Remaining fuel",
translation_key="remaining_fuel",
key_class="fuel_and_battery",
icon="mdi:gas-station",
unit_type=VOLUME,
@@ -137,7 +137,7 @@ SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
),
"remaining_fuel_percent": BMWSensorEntityDescription(
key="remaining_fuel_percent",
name="Remaining fuel percent",
translation_key="remaining_fuel_percent",
key_class="fuel_and_battery",
icon="mdi:gas-station",
unit_type=PERCENTAGE,

View File

@@ -26,5 +26,114 @@
}
}
}
},
"entity": {
"binary_sensor": {
"lids": {
"name": "Lids"
},
"windows": {
"name": "Windows"
},
"door_lock_state": {
"name": "Door lock state"
},
"condition_based_services": {
"name": "Condition based services"
},
"check_control_messages": {
"name": "Check control messages"
},
"charging_status": {
"name": "Charging status"
},
"connection_status": {
"name": "Connection status"
},
"is_pre_entry_climatization_enabled": {
"name": "Pre entry climatization"
}
},
"button": {
"light_flash": {
"name": "Flash lights"
},
"sound_horn": {
"name": "Sound horn"
},
"activate_air_conditioning": {
"name": "Activate air conditioning"
},
"find_vehicle": {
"name": "Find vehicle"
},
"refresh": {
"name": "Refresh from cloud"
}
},
"lock": {
"lock": {
"name": "[%key:component::lock::title%]"
}
},
"number": {
"target_soc": {
"name": "Target SoC"
}
},
"select": {
"ac_limit": {
"name": "AC Charging Limit"
},
"charging_mode": {
"name": "Charging Mode"
}
},
"sensor": {
"ac_current_limit": {
"name": "AC current limit"
},
"charging_start_time": {
"name": "Charging start time"
},
"charging_end_time": {
"name": "Charging end time"
},
"charging_status": {
"name": "Charging status"
},
"charging_target": {
"name": "Charging target"
},
"remaining_battery_percent": {
"name": "Remaining battery percent"
},
"mileage": {
"name": "Mileage"
},
"remaining_range_total": {
"name": "Remaining range total"
},
"remaining_range_electric": {
"name": "Remaining range electric"
},
"remaining_range_fuel": {
"name": "Remaining range fuel"
},
"remaining_fuel": {
"name": "Remaining fuel"
},
"remaining_fuel_percent": {
"name": "Remaining fuel percent"
}
},
"switch": {
"climate": {
"name": "Climate"
},
"charging": {
"name": "Charging"
}
}
}
}

View File

@@ -51,7 +51,7 @@ CHARGING_STATE_ON = {
NUMBER_TYPES: list[BMWSwitchEntityDescription] = [
BMWSwitchEntityDescription(
key="climate",
name="Climate",
translation_key="climate",
is_available=lambda v: v.is_remote_climate_stop_enabled,
value_fn=lambda v: v.climate.is_climate_on,
remote_service_on=lambda v: v.remote_services.trigger_remote_air_conditioning(),
@@ -60,7 +60,7 @@ NUMBER_TYPES: list[BMWSwitchEntityDescription] = [
),
BMWSwitchEntityDescription(
key="charging",
name="Charging",
translation_key="charging",
is_available=lambda v: v.is_remote_charge_stop_enabled,
value_fn=lambda v: v.fuel_and_battery.charging_status in CHARGING_STATE_ON,
remote_service_on=lambda v: v.remote_services.trigger_charge_start(),

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

@@ -92,7 +92,7 @@ class ButtonEntity(RestoreEntity):
def _default_to_device_class_name(self) -> bool:
"""Return True if an unnamed entity should be named by its device class.
For sensors this is True if the entity has a device class.
For buttons this is True if the entity has a device class.
"""
return self.device_class is not None

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
import voluptuous as vol
from homeassistant.components.device_automation import async_validate_entity_schema
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_DEVICE_ID,
@@ -19,14 +20,21 @@ from .const import DOMAIN, SERVICE_PRESS
ACTION_TYPES = {"press"}
ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
_ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
{
vol.Required(CONF_TYPE): vol.In(ACTION_TYPES),
vol.Required(CONF_ENTITY_ID): cv.entity_domain(DOMAIN),
vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
}
)
async def async_validate_action_config(
hass: HomeAssistant, config: ConfigType
) -> ConfigType:
"""Validate config."""
return async_validate_entity_schema(hass, config, _ACTION_SCHEMA)
async def async_get_actions(
hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
@@ -36,7 +44,7 @@ async def async_get_actions(
{
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,
CONF_ENTITY_ID: entry.id,
CONF_TYPE: "press",
}
for entry in er.async_entries_for_device(registry, device_id)

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

@@ -534,6 +534,14 @@ class ClimateEntity(Entity):
await self.hass.async_add_executor_job(self.turn_on)
return
# If there are only two HVAC modes, and one of those modes is OFF,
# then we can just turn on the other mode.
if len(self.hvac_modes) == 2 and HVACMode.OFF in self.hvac_modes:
for mode in self.hvac_modes:
if mode != HVACMode.OFF:
await self.async_set_hvac_mode(mode)
return
# Fake turn on
for mode in (HVACMode.HEAT_COOL, HVACMode.HEAT, HVACMode.COOL):
if mode not in self.hvac_modes:

View File

@@ -3,6 +3,10 @@ from __future__ import annotations
import voluptuous as vol
from homeassistant.components.device_automation import (
async_get_entity_registry_entry_or_raise,
async_validate_entity_schema,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_DEVICE_ID,
@@ -24,7 +28,7 @@ ACTION_TYPES = {"set_hvac_mode", "set_preset_mode"}
SET_HVAC_MODE_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
{
vol.Required(CONF_TYPE): "set_hvac_mode",
vol.Required(CONF_ENTITY_ID): cv.entity_domain(DOMAIN),
vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
vol.Required(const.ATTR_HVAC_MODE): vol.In(const.HVAC_MODES),
}
)
@@ -32,12 +36,19 @@ SET_HVAC_MODE_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
SET_PRESET_MODE_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
{
vol.Required(CONF_TYPE): "set_preset_mode",
vol.Required(CONF_ENTITY_ID): cv.entity_domain(DOMAIN),
vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
vol.Required(const.ATTR_PRESET_MODE): str,
}
)
ACTION_SCHEMA = vol.Any(SET_HVAC_MODE_SCHEMA, SET_PRESET_MODE_SCHEMA)
_ACTION_SCHEMA = vol.Any(SET_HVAC_MODE_SCHEMA, SET_PRESET_MODE_SCHEMA)
async def async_validate_action_config(
hass: HomeAssistant, config: ConfigType
) -> ConfigType:
"""Validate config."""
return async_validate_entity_schema(hass, config, _ACTION_SCHEMA)
async def async_get_actions(
@@ -57,7 +68,7 @@ async def async_get_actions(
base_action = {
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,
CONF_ENTITY_ID: entry.id,
}
actions.append({**base_action, CONF_TYPE: "set_hvac_mode"})
@@ -93,23 +104,24 @@ async def async_get_action_capabilities(
) -> dict[str, vol.Schema]:
"""List action capabilities."""
action_type = config[CONF_TYPE]
entity_id_or_uuid = config[CONF_ENTITY_ID]
fields = {}
if action_type == "set_hvac_mode":
try:
entry = async_get_entity_registry_entry_or_raise(hass, entity_id_or_uuid)
hvac_modes = (
get_capability(hass, config[ATTR_ENTITY_ID], const.ATTR_HVAC_MODES)
or []
get_capability(hass, entry.entity_id, const.ATTR_HVAC_MODES) or []
)
except HomeAssistantError:
hvac_modes = []
fields[vol.Required(const.ATTR_HVAC_MODE)] = vol.In(hvac_modes)
elif action_type == "set_preset_mode":
try:
entry = async_get_entity_registry_entry_or_raise(hass, entity_id_or_uuid)
preset_modes = (
get_capability(hass, config[ATTR_ENTITY_ID], const.ATTR_PRESET_MODES)
or []
get_capability(hass, entry.entity_id, const.ATTR_PRESET_MODES) or []
)
except HomeAssistantError:
preset_modes = []

View File

@@ -3,6 +3,9 @@ from __future__ import annotations
import voluptuous as vol
from homeassistant.components.device_automation import (
async_get_entity_registry_entry_or_raise,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_CONDITION,
@@ -28,7 +31,7 @@ CONDITION_TYPES = {"is_hvac_mode", "is_preset_mode"}
HVAC_MODE_CONDITION = DEVICE_CONDITION_BASE_SCHEMA.extend(
{
vol.Required(CONF_ENTITY_ID): cv.entity_id,
vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
vol.Required(CONF_TYPE): "is_hvac_mode",
vol.Required(const.ATTR_HVAC_MODE): vol.In(const.HVAC_MODES),
}
@@ -36,7 +39,7 @@ HVAC_MODE_CONDITION = DEVICE_CONDITION_BASE_SCHEMA.extend(
PRESET_MODE_CONDITION = DEVICE_CONDITION_BASE_SCHEMA.extend(
{
vol.Required(CONF_ENTITY_ID): cv.entity_id,
vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
vol.Required(CONF_TYPE): "is_preset_mode",
vol.Required(const.ATTR_PRESET_MODE): str,
}
@@ -63,7 +66,7 @@ async def async_get_conditions(
CONF_CONDITION: "device",
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,
CONF_ENTITY_ID: entry.id,
}
conditions.append({**base_condition, CONF_TYPE: "is_hvac_mode"})
@@ -80,9 +83,12 @@ def async_condition_from_config(
) -> condition.ConditionCheckerType:
"""Create a function to test a device condition."""
registry = er.async_get(hass)
entity_id = er.async_resolve_entity_id(registry, config[ATTR_ENTITY_ID])
def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
"""Test if an entity is a certain state."""
if (state := hass.states.get(config[ATTR_ENTITY_ID])) is None:
if not entity_id or (state := hass.states.get(entity_id)) is None:
return False
if config[CONF_TYPE] == "is_hvac_mode":
@@ -106,9 +112,11 @@ async def async_get_condition_capabilities(
if condition_type == "is_hvac_mode":
try:
entry = async_get_entity_registry_entry_or_raise(
hass, config[CONF_ENTITY_ID]
)
hvac_modes = (
get_capability(hass, config[ATTR_ENTITY_ID], const.ATTR_HVAC_MODES)
or []
get_capability(hass, entry.entity_id, const.ATTR_HVAC_MODES) or []
)
except HomeAssistantError:
hvac_modes = []
@@ -116,9 +124,11 @@ async def async_get_condition_capabilities(
elif condition_type == "is_preset_mode":
try:
entry = async_get_entity_registry_entry_or_raise(
hass, config[CONF_ENTITY_ID]
)
preset_modes = (
get_capability(hass, config[ATTR_ENTITY_ID], const.ATTR_PRESET_MODES)
or []
get_capability(hass, entry.entity_id, const.ATTR_PRESET_MODES) or []
)
except HomeAssistantError:
preset_modes = []

View File

@@ -142,7 +142,7 @@ async def async_attach_trigger(
numeric_state_config[
numeric_state_trigger.CONF_VALUE_TEMPLATE
] = "{{ state.attributes.current_temperature }}"
else:
else: # trigger_type == "current_humidity_changed"
numeric_state_config[
numeric_state_trigger.CONF_VALUE_TEMPLATE
] = "{{ state.attributes.current_humidity }}"

View File

@@ -17,6 +17,7 @@ from homeassistant.components.alexa import (
smart_home as alexa_smart_home,
)
from homeassistant.components.google_assistant import smart_home as ga
from homeassistant.const import __version__ as HA_VERSION
from homeassistant.core import Context, HassJob, HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_call_later
@@ -212,6 +213,19 @@ class CloudClient(Interface):
"""Process cloud remote message to client."""
await self._prefs.async_update(remote_enabled=connect)
async def async_cloud_connection_info(
self, payload: dict[str, Any]
) -> dict[str, Any]:
"""Process cloud connection info message to client."""
return {
"remote": {
"connected": self.cloud.remote.is_connected,
"enabled": self._prefs.remote_enabled,
"instance_domain": self.cloud.remote.instance_domain,
},
"version": HA_VERSION,
}
async def async_alexa_message(self, payload: dict[Any, Any]) -> dict[Any, Any]:
"""Process cloud alexa message to client."""
cloud_user = await self._prefs.get_cloud_user()

View File

@@ -8,5 +8,5 @@
"integration_type": "system",
"iot_class": "cloud_push",
"loggers": ["hass_nabucasa"],
"requirements": ["hass-nabucasa==0.68.0"]
"requirements": ["hass-nabucasa==0.69.0"]
}

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

@@ -1,5 +1,6 @@
"""The Compensation integration."""
import logging
from operator import itemgetter
import numpy as np
import voluptuous as vol
@@ -7,6 +8,8 @@ import voluptuous as vol
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.const import (
CONF_ATTRIBUTE,
CONF_MAXIMUM,
CONF_MINIMUM,
CONF_SOURCE,
CONF_UNIQUE_ID,
CONF_UNIT_OF_MEASUREMENT,
@@ -20,8 +23,10 @@ from .const import (
CONF_COMPENSATION,
CONF_DATAPOINTS,
CONF_DEGREE,
CONF_LOWER_LIMIT,
CONF_POLYNOMIAL,
CONF_PRECISION,
CONF_UPPER_LIMIT,
DATA_COMPENSATION,
DEFAULT_DEGREE,
DEFAULT_PRECISION,
@@ -50,6 +55,8 @@ COMPENSATION_SCHEMA = vol.Schema(
],
vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_ATTRIBUTE): cv.string,
vol.Optional(CONF_UPPER_LIMIT, default=False): cv.boolean,
vol.Optional(CONF_LOWER_LIMIT, default=False): cv.boolean,
vol.Optional(CONF_PRECISION, default=DEFAULT_PRECISION): cv.positive_int,
vol.Optional(CONF_DEGREE, default=DEFAULT_DEGREE): vol.All(
vol.Coerce(int),
@@ -78,8 +85,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
degree = conf[CONF_DEGREE]
initial_coefficients: list[tuple[float, float]] = conf[CONF_DATAPOINTS]
sorted_coefficients = sorted(initial_coefficients, key=itemgetter(0))
# get x values and y values from the x,y point pairs
x_values, y_values = zip(*conf[CONF_DATAPOINTS])
x_values, y_values = zip(*initial_coefficients)
# try to get valid coefficients for a polynomial
coefficients = None
@@ -99,6 +109,16 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
}
data[CONF_POLYNOMIAL] = np.poly1d(coefficients)
if data[CONF_LOWER_LIMIT]:
data[CONF_MINIMUM] = sorted_coefficients[0]
else:
data[CONF_MINIMUM] = None
if data[CONF_UPPER_LIMIT]:
data[CONF_MAXIMUM] = sorted_coefficients[-1]
else:
data[CONF_MAXIMUM] = None
hass.data[DATA_COMPENSATION][compensation] = data
hass.async_create_task(

View File

@@ -4,6 +4,8 @@ DOMAIN = "compensation"
SENSOR = "compensation"
CONF_COMPENSATION = "compensation"
CONF_LOWER_LIMIT = "lower_limit"
CONF_UPPER_LIMIT = "upper_limit"
CONF_DATAPOINTS = "data_points"
CONF_DEGREE = "degree"
CONF_PRECISION = "precision"

View File

@@ -10,6 +10,8 @@ from homeassistant.components.sensor import SensorEntity
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT,
CONF_ATTRIBUTE,
CONF_MAXIMUM,
CONF_MINIMUM,
CONF_SOURCE,
CONF_UNIQUE_ID,
CONF_UNIT_OF_MEASUREMENT,
@@ -64,6 +66,8 @@ async def async_setup_platform(
conf[CONF_PRECISION],
conf[CONF_POLYNOMIAL],
conf.get(CONF_UNIT_OF_MEASUREMENT),
conf[CONF_MINIMUM],
conf[CONF_MAXIMUM],
)
]
)
@@ -83,6 +87,8 @@ class CompensationSensor(SensorEntity):
precision: int,
polynomial: np.poly1d,
unit_of_measurement: str | None,
minimum: tuple[float, float] | None,
maximum: tuple[float, float] | None,
) -> None:
"""Initialize the Compensation sensor."""
self._source_entity_id = source
@@ -93,6 +99,8 @@ class CompensationSensor(SensorEntity):
self._coefficients = polynomial.coefficients.tolist()
self._attr_unique_id = unique_id
self._attr_name = name
self._minimum = minimum
self._maximum = maximum
async def async_added_to_hass(self) -> None:
"""Handle added to Hass."""
@@ -132,7 +140,14 @@ class CompensationSensor(SensorEntity):
else:
value = None if new_state.state == STATE_UNKNOWN else new_state.state
try:
self._attr_native_value = round(self._poly(float(value)), self._precision)
x_value = float(value)
if self._minimum is not None and x_value <= self._minimum[0]:
y_value = self._minimum[1]
elif self._maximum is not None and x_value >= self._maximum[0]:
y_value = self._maximum[1]
else:
y_value = self._poly(x_value)
self._attr_native_value = round(y_value, self._precision)
except (ValueError, TypeError):
self._attr_native_value = None

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."""
@@ -529,12 +577,8 @@ class AgentManager:
def async_set_agent(self, agent_id: str, agent: AbstractConversationAgent) -> None:
"""Set the agent."""
self._agents[agent_id] = agent
if self.default_agent == HOME_ASSISTANT_AGENT:
self.default_agent = agent_id
@core.callback
def async_unset_agent(self, agent_id: str) -> None:
"""Unset the agent."""
if self.default_agent == agent_id:
self.default_agent = HOME_ASSISTANT_AGENT
self._agents.pop(agent_id, None)

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