Compare commits

...

250 Commits

Author SHA1 Message Date
Franck Nijhof 267dfac737 2024.7.3 (#122194) 2024-07-19 19:38:08 +02:00
Franck Nijhof a08ffdc8d3 Bump version to 2024.7.3 2024-07-19 18:50:21 +02:00
Mr. Bubbles 1ef4332af6 Fix KeyError in config flow of Bring integration (#122136) 2024-07-19 18:49:45 +02:00
Marc Mueller d0d2fd7918 Update yt-dlp to 2024.07.16 (#122124) 2024-07-19 18:49:41 +02:00
Steven B. c518c4756b Bump tplink dependency python-kasa to 0.7.0.5 (#122119) 2024-07-19 18:49:38 +02:00
Shay Levy a3a99cc631 Prevent connecting to a Shelly device that is already connected (#122105) 2024-07-19 18:49:35 +02:00
Steven B. 977a55e3b8 Update tplink device config during reauth flow (#122089) 2024-07-19 18:49:31 +02:00
Harry Martland 002db3c3e9 Fix hive not updating when boosting (#122042)
* fixes issue where hive does not update when boosting

* formats files
2024-07-19 18:49:28 +02:00
Robert Svensson d9e44bab69 Mark UniFi power cycle button as unavailable if PoE is not enabled on port (#122035) 2024-07-19 18:49:25 +02:00
G Johansson 4b93fc61b5 Bump python-holidays to 0.53 (#122021) 2024-07-19 18:49:21 +02:00
J. Nick Koston 214b5efd72 Narrow sqlite database corruption check to ensure disk image is malformed (#121947)
* Narrow sqlite database corruption check to ensure disk image is malformed

The database corruption check would also replace the database when it
locked externally instead of only when its malformed.

This was discovered in https://github.com/home-assistant/core/issues/121909#issuecomment-2227409124
when a user did a manual index creation while HA was online

* tweak

* tweak

* fix

* fix
2024-07-19 18:49:16 +02:00
Maciej Bieniek 9bd822d693 Fix configuration_url for Shelly device using IPv6 (#121939)
Co-authored-by: Maciej Bieniek <478555+bieniu@users.noreply.github.com>
2024-07-19 18:48:32 +02:00
Tomasz Gorochowik bf89eaae25 Fix enigma2 mute (#121928) 2024-07-19 18:42:44 +02:00
Scott K Logan f9b359ae30 Fix rainforest_raven closing device due to timeout (#121905) 2024-07-19 18:42:41 +02:00
mvn23 24ed003471 Fix opentherm_gw availability (#121892) 2024-07-19 18:42:38 +02:00
J. Nick Koston a835750252 Log add/remove index complete at the same level as when it starts (#121852) 2024-07-19 18:42:35 +02:00
Avi Miller ad07bdb62b Bump aiolifx to 1.0.5 (#121824) 2024-07-19 18:42:32 +02:00
Avi Miller 41104324ec Bump aiolifx to 1.0.4 (#121267) 2024-07-19 18:42:28 +02:00
ollo69 e9344ae101 Bump PySwitchbot to 0.48.1 (#121804) 2024-07-19 18:40:25 +02:00
starkillerOG 56a9167ed2 Reolink media second lens (#121800)
DUO lens camera distinguish between lenses for media playback
2024-07-19 18:40:22 +02:00
Jan Bouwhuis e0b90c4b36 Fix alexa does to check current_position correctly when handling cover range changes (#121798) 2024-07-19 18:40:19 +02:00
Jan-Philipp Benecke 976902f22c Add missing translations to Roborock (#121796) 2024-07-19 18:40:16 +02:00
Steven B 0f69c58ba9 Bump python-kasa to 0.7.0.4 (#121791) 2024-07-19 18:40:13 +02:00
Glenn Waters 1e6c96c6eb Use async_connect in newly bumped 0.5.8 UPB library (#121789) 2024-07-19 18:40:09 +02:00
J. Nick Koston 63b14d14c1 Add some missing tplink ouis (#121785) 2024-07-19 18:40:06 +02:00
Josef Zweck 6aaaba6419 Bump pytedee_async to 0.2.20 (#121783) 2024-07-19 18:40:03 +02:00
Allen Porter 3b8e736fe3 Pin mashumaro version >= 3.13.1 for python 3.12.4 compatibility. (#121782)
Pin mashumaro version for python 3.12.4 compatibility.
2024-07-19 18:40:00 +02:00
tronikos 68841b3d8a Bump opower to 0.5.2 to fix 403 forbidden errors for users with multiple accounts (#121762) 2024-07-19 18:39:56 +02:00
Abílio Costa 3d8afe7cb8 Update Idasen Desk library to 2.6.2 (#121729) 2024-07-19 18:29:45 +02:00
Robert Svensson 8595242142 Fix bad access to UniFi runtime_data when not assigned (#121725)
* Fix bad access to runtime_data when not assigned

* Fix review comment

* Clean up if statements
2024-07-19 18:29:42 +02:00
Joost Lekkerkerker ebe7bc0686 Bump knocki to 0.3.1 (#121717) 2024-07-19 18:29:39 +02:00
J. Nick Koston 4ab180f016 Fix update happening too early in unifiprotect (#121714) 2024-07-19 18:29:36 +02:00
Mr. Bubbles 372649069e Bump pyloadapi to v1.3.2 (#121709) 2024-07-19 18:29:33 +02:00
Joost Lekkerkerker 98df46f3ea Bump knocki to 0.3.0 (#121704) 2024-07-19 18:29:30 +02:00
Steven B 269fb23527 Fix tplink bug changing color temp on bulbs with light effects (#121696) 2024-07-19 18:29:27 +02:00
Sid ad5cbf0da6 Allow enigma2 devices to use different source bouquets (#121686) 2024-07-19 18:29:24 +02:00
Lucas Mindêllo de Andrade 10cdf64f90 Bump sunweg 3.0.2 (#121684) 2024-07-19 18:29:21 +02:00
Tomek Porozynski ec8e639804 Update Supla async_set_cover_position to use "REVEAL_PARTIALLY" (#121663) 2024-07-19 18:29:17 +02:00
Jan Stienstra 37f37f7287 Retain Jellyfin config flow input on connection issue (#121618) 2024-07-19 18:29:13 +02:00
Mr. Bubbles ef7d68bfd6 Fix reauth error and exception in ista EcoTrend integration (#121482) 2024-07-19 18:29:08 +02:00
Franck Nijhof 058b012e6c 2024.7.2 (#121671) 2024-07-10 13:18:48 +02:00
Franck Nijhof 71370758a8 Bump version to 2024.7.2 2024-07-10 12:06:02 +02:00
Franck Nijhof 38a44676eb Block variable <=3.4.4 custom integration from breaking the recorder (#121670) 2024-07-10 12:01:11 +02:00
Marcel van der Veldt 05ce3d35b3 Matter lock state follow-up (#121669) 2024-07-10 12:01:08 +02:00
Marcel van der Veldt 2151086b0a Fix state for Matter Locks (including optional door sensor) (#121665) 2024-07-10 12:01:05 +02:00
Franck Nijhof 9c83af3789 Block places <=2.7.0 custom integration from breaking the recorder (#121662) 2024-07-10 12:01:01 +02:00
tronikos ac3eecc879 Handle errors in Fully Kiosk camera (#121659) 2024-07-10 12:00:58 +02:00
Franck Nijhof ec0910e3da Block icloud3 custom integration from breaking the recorder (#121658) 2024-07-10 12:00:55 +02:00
Maikel Punie fd0c26cd56 Small fix in velbus cover for the assumed states (#121656) 2024-07-10 12:00:52 +02:00
Paul Bottein a4c5dee082 Update frontend to 20240710.0 (#121651) 2024-07-10 12:00:48 +02:00
Joakim Plate 37c09dbdb6 Allow ambilight when we have connection (philips_js) (#121620) 2024-07-10 12:00:45 +02:00
Arie Catsman 73d1973625 Bump pyenphase to 1.20.6 (#121583)
bump pyenphase to 1.20.6
2024-07-10 12:00:42 +02:00
Glenn Waters 5a04a886cf Fix upb config flow connect (#121571) 2024-07-10 12:00:39 +02:00
Franck Nijhof 50802f84f0 Update tailscale to 0.6.1 (#121557) 2024-07-10 12:00:36 +02:00
Franck Nijhof 138b68ecc0 Update vehicle to 2.2.2 (#121556) 2024-07-10 12:00:33 +02:00
Christoph e0b01ee94e Remove homematic state_class from GAS_POWER sensor (#121533) 2024-07-10 12:00:30 +02:00
J. Nick Koston 4f2c3df518 Fix person tracking in unifiprotect (#121528) 2024-07-10 12:00:26 +02:00
Paulus Schoutsen 51a6bb1c22 Include hass device ID in mobile app get_config webhook (#121496) 2024-07-10 12:00:23 +02:00
Ovidiu D. Nițan 6bf9ec69f3 Bump xiaomi-ble to 0.30.2 (#121471) 2024-07-10 12:00:19 +02:00
Joost Lekkerkerker 21309eeb5d Bump xiaomi-ble to 0.30.1 (#120743) 2024-07-10 12:00:14 +02:00
J. Nick Koston 0a1b46c52f Bump yalexs to 6.4.2 (#121467) 2024-07-10 11:52:56 +02:00
Jason R. Coombs 9512f9eec3 Bump jaraco.abode to 5.2.1 (#121446)
Bump dependency on jaraco.abode to 5.2.1.

Closes #121300
2024-07-10 11:52:53 +02:00
jan iversen ab94422c18 Bump pymodbus to 3.6.9 (#121445)
Bump pymodbus 3.6.9.
2024-07-10 11:52:50 +02:00
Joost Lekkerkerker ec105e5265 Fix Mealie URL field (#121434) 2024-07-10 11:52:47 +02:00
Joost Lekkerkerker cadd8521ae Sort mealie mealplans (#121433) 2024-07-10 11:52:43 +02:00
Joost Lekkerkerker 8825c50671 Fix MPD config flow (#121431) 2024-07-10 11:52:40 +02:00
Michael a72cc3c248 Allow current empty feeds to be configured in Feedreader (#121421) 2024-07-10 11:52:37 +02:00
G Johansson 780f7254c1 Fix feature flag in climate (#121398) 2024-07-10 11:52:34 +02:00
G Johansson 37621e77ae Fix timezone issue in smhi weather (#121389) 2024-07-10 11:52:31 +02:00
G Johansson 8017386c73 Fix unnecessary logging of turn on/off feature flags in Climate (#121387) 2024-07-10 11:52:28 +02:00
G Johansson a5f4c25a2c Bump psutil to 6.0.0 (#121385) 2024-07-10 11:52:25 +02:00
Brett Adams 1d7bddf449 Fix initial Wall Connector values in Tessie (#121353) 2024-07-10 11:52:21 +02:00
Luke Lashley 711bdaf373 Bump anova-wifi to 0.17.0 (#121337)
* Bump anova-wifi to 0.16.0

* Bump to .17
2024-07-10 11:52:18 +02:00
Jan Temešinko 803d9c5a8e Fix ombi configuration validation (#121314) 2024-07-10 11:52:15 +02:00
Rasmus Lundsgaard 1133c41fa8 Fix empty list in kodi media_player (#121250)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2024-07-10 11:52:12 +02:00
Alan a06af7ee93 LLM to handle int attributes (#121037) 2024-07-10 11:52:08 +02:00
Robert C. Maehl c54717707e Direct Users to App-Specific Passwords for iCloud integration to prevent MFA spam (#120945)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2024-07-10 11:52:05 +02:00
J. Nick Koston 440d83d754 Remove legacy foreign key constraint from sqlite states table (#120779) 2024-07-10 11:51:59 +02:00
Franck Nijhof 1cf62916a7 2024.7.1 (#121289) 2024-07-05 17:25:40 +02:00
Bram Kragten e3958d4adb Update frontend to 20240705.0 (#121295) 2024-07-05 15:04:01 +02:00
Franck Nijhof dfccd4abf9 Bump version to 2024.7.1 2024-07-05 11:21:36 +02:00
Steven B 994d6f552c Fix tplink light effect behaviour when activating a scene (#121288) 2024-07-05 11:21:07 +02:00
G Johansson b015611a2a Bump python-holidays to 0.52 (#121283) 2024-07-05 11:21:04 +02:00
Shay Levy f4e362c5d0 Bump aiowebostv to 0.4.2 (#121258) 2024-07-05 11:21:00 +02:00
Jordi a542236614 Bump aioaquacell to 0.1.8 (#121253) 2024-07-05 11:20:57 +02:00
Shay Levy 651439ea06 Fix WebOS TV media player status when OFF after IDLE (#121251) 2024-07-05 11:20:54 +02:00
Robert Resch eda450838e Bump deebot-client to 8.1.1 (#121241) 2024-07-05 11:20:50 +02:00
hahn-th b906daa493 Revert Homematic IP Cloud unique ID changes (#121231) 2024-07-05 11:20:47 +02:00
Thomas55555 ac668dce7d Fix work area sensor in Husqvarna Automower (#121228) 2024-07-05 11:20:44 +02:00
Luke Lashley 1bb4d62a3e Bump anova-wifi to 0.15.0 (#121222) 2024-07-05 11:20:40 +02:00
Marcel van der Veldt 0b970f9a85 Listen for attribute changes of OnOff cluster in appliances (#121198) 2024-07-05 11:20:37 +02:00
Marcel van der Veldt d2b695e7b5 Fix Matter light discovery schema for DimmerSwitch (#121185) 2024-07-05 11:20:34 +02:00
Steven B b2f23c1a5e Bump python-kasa to 0.7.0.3 (#121183) 2024-07-05 11:20:31 +02:00
Gerben Jongerius f403afb012 Bump youless library version 2.1.2 (#121181) 2024-07-05 11:20:27 +02:00
Maciej Bieniek ee276aff44 Fix pulse counter frequency sensors for Shelly Plus Uni (#121178)
Co-authored-by: Maciej Bieniek <478555+bieniu@users.noreply.github.com>
2024-07-05 11:20:23 +02:00
Maikel Punie 0acd1dc5d1 Bump velbusaio to 2024.7.5 (#121156)
* Bump velbusaio to 2024.7.4

* bump to 2024.7.5 to remove print functions
2024-07-05 11:20:20 +02:00
Martin Weinelt 21815e1621 Fix broken pathlib import in august integration (#121135) 2024-07-05 11:20:17 +02:00
J. Nick Koston 15933bb16f Bump inkbird-ble to 0.5.8 (#121134) 2024-07-05 11:20:13 +02:00
Pavel Skuratovich 930cd0dc50 Starline: Fix "Error updating SLNet token" message in Log (#121122)
Fixes https://github.com/home-assistant/core/issues/116715
2024-07-05 11:20:10 +02:00
Christoph fc4af48179 Fix HmIP-ESI GAS sensor DeviceClass (#121106)
should be SensorDeviceClass:GAS instead of SensorDeviceClass:VOLUME to be supported in the Energy Dashboard
2024-07-05 11:20:07 +02:00
Marcel van der Veldt ba1cf84ea5 Fix locking/unlocking transition state in Matter lock platform (#121099) 2024-07-05 11:20:04 +02:00
dougiteixeira 59cf01e252 Add device class translations in Random (#120890) 2024-07-05 11:20:00 +02:00
Allen Porter 46e681f4fc Improve redaction for stream error messages (#120867) 2024-07-05 11:19:56 +02:00
Franck Nijhof 2b64f6f2ab 2024.7.0 (#120579) 2024-07-03 18:52:01 +02:00
Franck Nijhof 1080a4ef1e Bump version to 2024.7.0 2024-07-03 17:55:58 +02:00
Franck Nijhof d94b36cfbb Bump version to 2024.7.0b11 2024-07-03 17:29:08 +02:00
Marcel van der Veldt 85168239cd Matter fix Energy sensor discovery schemas (#121080) 2024-07-03 17:28:59 +02:00
Robert Resch 547b24ce58 Bump deebot-client to 8.1.0 (#121078) 2024-07-03 17:28:56 +02:00
Michael Hansen e8bcb3e11e Bump intents to 2024.7.3 (#121076) 2024-07-03 17:28:53 +02:00
Marcel van der Veldt c89a9b5ce0 Bump python-matter-server to 6.2.2 (#121072) 2024-07-03 17:28:49 +02:00
Robert Svensson 13631250b4 Bump axis to v62 (#121070) 2024-07-03 17:28:46 +02:00
Bram Kragten 6621cf475a Update frontend to 20240703.0 (#121063) 2024-07-03 17:28:43 +02:00
Anton Tolchanov 36e74cd9a6 Generate Prometheus metrics in an executor job (#121058) 2024-07-03 17:28:38 +02:00
Kevin Stillhammer 16827ea09e Bump here-transit to 1.2.1 (#120900) 2024-07-03 17:27:10 +02:00
Kevin Stillhammer c4956b66b0 Bump here-routing to 1.0.1 (#120877) 2024-07-03 17:27:06 +02:00
Franck Nijhof 84204c38be Bump version to 2024.7.0b10 2024-07-03 08:59:52 +02:00
J. Nick Koston febd1a3772 Bump inkbird-ble to 0.5.7 (#121039)
changelog: https://github.com/Bluetooth-Devices/inkbird-ble/compare/v0.5.6...v0.5.7
2024-07-03 08:59:45 +02:00
Allen Porter 1665cb40ac Bump gcal_sync to 6.1.4 (#120941) 2024-07-03 08:59:41 +02:00
Franck Nijhof 1b9f27fab7 Bump version to 2024.7.0b9 2024-07-02 22:15:17 +02:00
Bram Kragten d1e76d5c3c Update frontend to 20240702.0 (#121032) 2024-07-02 22:15:09 +02:00
Jan-Philipp Benecke 4377f4cbea Temporarily set apprise log level to debug in tests (#121029)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2024-07-02 22:15:05 +02:00
Franck Nijhof 6b045a7d7b Bump version to 2024.7.0b8 2024-07-02 21:09:55 +02:00
Marcel van der Veldt 1fa6972a66 Handle mains power for Matter appliances (#121023) 2024-07-02 21:09:39 +02:00
Marcel van der Veldt b3e833f677 Fix setting target temperature for single setpoint Matter thermostat (#121011) 2024-07-02 21:09:36 +02:00
starkillerOG 807ed0ce10 Do not hold core startup with reolink firmware check task (#120985) 2024-07-02 21:09:32 +02:00
starkillerOG 5cb41106b5 Reolink replace automatic removal of devices by manual removal (#120981)
Co-authored-by: Robert Resch <robert@resch.dev>
2024-07-02 21:09:28 +02:00
Joost Lekkerkerker 98a2e46d4a Remove Aladdin Connect integration (#120980) 2024-07-02 21:08:14 +02:00
Joost Lekkerkerker 24afbde79e Bump yt-dlp to 2024.07.01 (#120978) 2024-07-02 21:05:52 +02:00
starkillerOG 65d2ca53cb Bump reolink-aio to 0.9.4 (#120964) 2024-07-02 21:05:49 +02:00
Joost Lekkerkerker 23b905b422 Bump airgradient to 0.6.1 (#120962) 2024-07-02 21:05:46 +02:00
Joost Lekkerkerker de458493f8 Fix missing airgradient string (#120957) 2024-07-02 21:05:42 +02:00
Erik Montnemery efd3252849 Create log files in an executor thread (#120912) 2024-07-02 21:05:39 +02:00
Jesse Hills 3b6acd5380 [ESPHome] Disable dashboard based update entities by default (#120907)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2024-07-02 21:05:36 +02:00
Teemu R 1e6dc74812 Minor polishing for tplink (#120868) 2024-07-02 21:05:22 +02:00
Franck Nijhof 74687f3b60 Bump version to 2024.7.0b7 2024-07-01 19:44:51 +02:00
Markus Jacobsen 2f307d6a8a Fix Bang & Olufsen jumping volume bar (#120946) 2024-07-01 19:44:37 +02:00
J. Nick Koston d8f55763c5 Downgrade logging previously reported asyncio block to debug (#120942) 2024-07-01 19:44:34 +02:00
Steven B 4b2be448f0 Bump python-kasa to 0.7.0.2 (#120940) 2024-07-01 19:44:31 +02:00
Marcel van der Veldt 8a7e2c05a5 Mark dry/fan-only climate modes as supported for Panasonic room air conditioner (#120939) 2024-07-01 19:44:28 +02:00
Paulus Schoutsen 887ab1dc58 Bump openai to 1.35.1 (#120926)
Bump openai to 1.35.7
2024-07-01 19:44:25 +02:00
Jan Bouwhuis a787ce8633 Bump incomfort-client dependency to 0.6.3 (#120913) 2024-07-01 19:44:22 +02:00
Robert Resch 88ed43c779 Improve add user error messages (#120909) 2024-07-01 19:44:19 +02:00
dougiteixeira 16d7764f18 Add missing translations for device class in Template (#120893) 2024-07-01 19:44:15 +02:00
dougiteixeira a0f8012f48 Add missing translations for device class in SQL (#120892) 2024-07-01 19:44:12 +02:00
dougiteixeira 5a052feb87 Add missing translations for device class in Scrape (#120891) 2024-07-01 19:44:09 +02:00
Allen Porter 779a7ddaa2 Bump ical to 8.1.1 (#120888) 2024-07-01 19:44:06 +02:00
Shay Levy a9740faeda Fix Shelly device shutdown (#120881) 2024-07-01 19:44:03 +02:00
Thomas55555 3a0e85beb8 Bump aioautomower to 2024.6.4 (#120875) 2024-07-01 19:43:59 +02:00
Yuxin Wang c19fb35d02 Add handling for different STATFLAG formats in APCUPSD (#120870)
* Add handling for different STATFLAG formats

* Just use removesuffix
2024-07-01 19:43:56 +02:00
J. Nick Koston 6f716c1753 Fix publish cancellation handling in MQTT (#120826) 2024-07-01 19:43:53 +02:00
Jan Bouwhuis 40384b9acd Split mqtt client tests (#120636) 2024-07-01 19:43:50 +02:00
Jan Bouwhuis 3bbf8df6d6 Cleanup mqtt platform tests part 4 (init) (#120574) 2024-07-01 19:43:46 +02:00
Franck Nijhof 14af3661f3 Bump version to 2024.7.0b6 2024-06-30 20:42:10 +02:00
Michael af733425c2 Bump pyfritzhome to 0.6.12 (#120861) 2024-06-30 20:41:51 +02:00
Allen Porter 4fc89e8861 Rollback PyFlume to 0.6.5 (#120846) 2024-06-30 20:39:47 +02:00
Tsvi Mostovicz bcec268c04 Fix Jewish calendar unique id move to entity (#120842) 2024-06-30 20:39:44 +02:00
Shay Levy becf9fcce2 Bump aiowebostv to 0.4.1 (#120838) 2024-06-30 20:39:41 +02:00
Etienne Soufflet ad9e0ef8e4 Fix Tado fan mode (#120809) 2024-06-30 20:39:38 +02:00
Simon Lamon f58eafe8fc Fix routes with transfer in nmbs integration (#120808) 2024-06-30 20:39:35 +02:00
mkmer a7246400b3 Allow EM heat on from any mode in Honeywell (#120750) 2024-06-30 20:39:32 +02:00
Joost Lekkerkerker 38a30b343d Bump pizzapi to 0.0.6 (#120691) 2024-06-30 20:39:28 +02:00
Franck Nijhof 08a0eaf184 Bump version to 2024.7.0b5 2024-06-29 17:51:45 +02:00
Joost Lekkerkerker 3ee8f6edba Use meal note as fallback in Mealie (#120828) 2024-06-29 17:51:34 +02:00
Joost Lekkerkerker e866417c01 Add icons to Airgradient (#120820) 2024-06-29 17:51:31 +02:00
Joost Lekkerkerker 05c63eb884 Bump python-opensky to 1.0.1 (#120818) 2024-06-29 17:51:28 +02:00
Joost Lekkerkerker bb52bfd73d Add unique id to Mealie config entry (#120816) 2024-06-29 17:51:25 +02:00
Joost Lekkerkerker 7319492bf3 Bump aiomealie to 0.5.0 (#120815) 2024-06-29 17:51:21 +02:00
J. Nick Koston 66932e3d9a Fix unneeded dict values for MATCH_ALL recorder attrs exclude (#120804)
* Small cleanup to handling MATCH_ALL recorder attrs exclude

* Fix unneeded dict values for MATCH_ALL recorder attrs exclude

The exclude is a set so the dict values were not needed

* Fix unneeded dict values for MATCH_ALL recorder attrs exclude

The exclude is a set so the dict values were not needed

* Fix unneeded dict values for MATCH_ALL recorder attrs exclude

The exclude is a set so the dict values were not needed
2024-06-29 17:51:18 +02:00
J. Nick Koston 0ec07001bd Fix blocking I/O in xmpp notify to read uploaded files (#120801)
detected by ruff in https://github.com/home-assistant/core/pull/120799
2024-06-29 17:51:15 +02:00
J. Nick Koston 0dcfd38cdc Fix missing f-string in loop util (#120800) 2024-06-29 17:51:12 +02:00
Klaas Schoute b45eff9a2b Bump gridnet lib to v5.0.1 (#120793) 2024-06-29 17:51:09 +02:00
Klaas Schoute ec577c7bd3 Bump odp-amsterdam lib to v6.0.2 (#120788) 2024-06-29 17:51:06 +02:00
Paul Bottein 723c4a1eb5 Update frontend to 20240628.0 (#120785)
Co-authored-by: J. Nick Koston <nick@koston.org>
2024-06-29 17:51:02 +02:00
Klaas Schoute b30b4d5a3a Bump energyzero lib to v2.1.1 (#120783) 2024-06-29 17:50:59 +02:00
Matthew FitzGerald-Chamberlain 8165acddeb Bump pyaprilaire to 0.7.4 (#120782) 2024-06-29 17:50:56 +02:00
Joost Lekkerkerker 0f3ed3bb67 Bump aiowithings to 3.0.2 (#120765) 2024-06-29 17:50:53 +02:00
Maciej Bieniek d1a96ef362 Do not call async_delete_issue() if there is no issue to delete in Shelly integration (#120762)
Co-authored-by: Maciej Bieniek <478555+bieniu@users.noreply.github.com>
2024-06-29 17:50:50 +02:00
J. Nick Koston 917eeba984 Increase mqtt availablity timeout to 50s (#120760) 2024-06-29 17:50:46 +02:00
Clifford Roche 59bb8b360e Bump greeclimate to 1.4.6 (#120758) 2024-06-29 17:50:43 +02:00
Klaas Schoute 6028e5b77a Bump p1monitor lib to v3.0.1 (#120756) 2024-06-29 17:50:40 +02:00
Klaas Schoute 83df470307 Bump easyenergy lib to v2.1.2 (#120753) 2024-06-29 17:50:37 +02:00
Joost Lekkerkerker 20ac0aa7b1 Bump govee-local-api to 1.5.1 (#120747) 2024-06-29 17:50:34 +02:00
Joost Lekkerkerker f57c942901 Bump sense-energy to 0.12.4 (#120744)
* Bump sense-energy to 0.12.4

* Fix
2024-06-29 17:50:31 +02:00
Alexey ALERT Rubashёff 8994ab1686 Add warm water remaining volume sensor to Overkiz (#120718)
* warm water remaining volume sensor

* Update homeassistant/components/overkiz/sensor.py

Co-authored-by: Dave T <17680170+davet2001@users.noreply.github.com>

---------

Co-authored-by: Dave T <17680170+davet2001@users.noreply.github.com>
2024-06-29 17:50:28 +02:00
Alexey ALERT Rubashёff b350ba9657 Add electrical consumption sensor to Overkiz (#120717)
electrical consumption sensor
2024-06-29 17:50:25 +02:00
wittypluck 5fd589053a Reject small uptime updates for Unifi clients (#120398)
Extend logic to reject small uptime updates to Unifi clients + add unit tests
2024-06-29 17:50:22 +02:00
Allen Porter 2d5961fa4f Bump gcal_sync to 6.1.3 (#120278) 2024-06-29 17:50:18 +02:00
Franck Nijhof d7a59748cf Bump version to 2024.7.0b4 2024-06-28 13:38:24 +02:00
tronikos cada78496b Fix Google Generative AI: 400 Request contains an invalid argument (#120741) 2024-06-28 13:31:00 +02:00
Illia c5fa9ad272 Bump asyncarve to 0.1.1 (#120740) 2024-06-28 13:30:51 +02:00
epenet fe8b5656dd Separate renault strings (#120737) 2024-06-28 13:30:48 +02:00
epenet 0ae11b0335 Bump renault-api to 0.2.4 (#120727) 2024-06-28 13:30:45 +02:00
Dave Leaver 76780ca04e Bump airtouch5py to 1.2.0 (#120715)
* Bump airtouch5py to fix console 1.2.0

* Bump airtouch5py again
2024-06-28 13:30:38 +02:00
Brett Adams 3932ce57b9 Check Tessie scopes to fix startup bug (#120710)
* Add scope check

* Add tests

* Bump Teslemetry
2024-06-28 13:30:35 +02:00
dougiteixeira 35d145d3bc Link the Statistics helper entity to the source entity device (#120705) 2024-06-28 13:30:30 +02:00
Maciej Bieniek 1227d56aa2 Bump nextdns to version 3.1.0 (#120703)
Co-authored-by: Maciej Bieniek <478555+bieniu@users.noreply.github.com>
2024-06-28 13:30:27 +02:00
Joost Lekkerkerker ef3ecb6183 Bump apsystems-ez1 to 1.3.3 (#120702) 2024-06-28 13:30:18 +02:00
Joost Lekkerkerker ca515f740e Bump panasonic_viera to 0.4.2 (#120692)
* Bump panasonic_viera to 0.4.2

* Bump panasonic_viera to 0.4.2

* Bump panasonic_viera to 0.4.2

* Fix Keys
2024-06-28 13:30:15 +02:00
Erik Montnemery 876fb234ce Bump hatasmota to 0.9.2 (#120670) 2024-06-28 13:30:10 +02:00
Erik Montnemery f28cbf1909 Set stateclass on unknown numeric Tasmota sensors (#120650) 2024-06-28 13:30:06 +02:00
Franck Nijhof 9b5d0f72dc Bump version to 2024.7.0b3 2024-06-27 22:20:25 +02:00
Steven B 23056f839b Update tplink unlink identifiers to deal with ids from other domains (#120596) 2024-06-27 22:20:02 +02:00
Joost Lekkerkerker 0b8dd738f1 Bump ttls to 1.8.3 (#120700) 2024-06-27 22:19:25 +02:00
Glenn Waters 411633d3b3 Bump Environment Canada to 0.7.1 (#120699) 2024-06-27 22:19:22 +02:00
Thomas55555 f3ab3bd5cb Bump aioautomower to 2024.6.3 (#120697) 2024-06-27 22:19:19 +02:00
Bram Kragten 476b9909ac Update frontend to 20240627.0 (#120693) 2024-06-27 22:19:16 +02:00
Glenn Waters e756328d52 Bump upb-lib to 0.5.7 (#120689) 2024-06-27 22:19:13 +02:00
J. Nick Koston b9c9921847 Add newer models to unifi integrations discovery (#120688) 2024-06-27 22:19:10 +02:00
MatthewFlamm 09dbd8e7eb Use more observations in NWS (#120687)
Use more observations
2024-06-27 22:19:07 +02:00
Glenn Waters 07dd832c58 Bump Environment Canada to 0.7.0 (#120686) 2024-06-27 22:19:04 +02:00
J. Nick Koston f9c5661c66 Bump unifi-discovery to 1.2.0 (#120684) 2024-06-27 22:19:01 +02:00
J. Nick Koston 94f8f8281f Bump uiprotect to 4.2.0 (#120669) 2024-06-27 22:18:58 +02:00
Erik Montnemery f6aa25c717 Fix docstring for EventStateEventData (#120662) 2024-06-27 22:18:55 +02:00
Jesse Hills f9ca85735d [esphome] Add more tests to bring integration to 100% coverage (#120661) 2024-06-27 22:18:52 +02:00
Joost Lekkerkerker be086c581c Fix Airgradient ABC days name (#120659) 2024-06-27 22:18:49 +02:00
Joost Lekkerkerker 03d198dd64 Fix unknown attribute in MPD (#120657) 2024-06-27 22:18:47 +02:00
Joost Lekkerkerker a8d6866f9f Disable polling for Knocki (#120656) 2024-06-27 22:18:44 +02:00
Brett Adams 0e1dc9878f Fix values at startup for Tessie (#120652) 2024-06-27 22:18:41 +02:00
Erik Montnemery 6849597764 Bump hatasmota to 0.9.1 (#120649) 2024-06-27 22:18:38 +02:00
Josef Zweck 3022d3bfa0 Move Auto On/off switches to Config EntityCategory (#120648) 2024-06-27 22:18:35 +02:00
Erik Montnemery 4836d6620b Add snapshots to tasmota sensor test (#120647) 2024-06-27 22:18:32 +02:00
Erik Montnemery b290e95350 Improve typing of state event helpers (#120639) 2024-06-27 22:18:29 +02:00
Josef Zweck 89ac3ce832 Fix the version that raises the issue (#120638) 2024-06-27 22:18:26 +02:00
Erik Montnemery 1933454b76 Rename async_track_state_reported_event to async_track_state_report_event (#120637)
* Rename async_track_state_reported_event to async_track_state_report_event

* Update tests
2024-06-27 22:18:23 +02:00
J. Nick Koston 38601d48ff Add async_track_state_reported_event to fix integration performance regression (#120622)
split from https://github.com/home-assistant/core/pull/120621
2024-06-27 22:18:20 +02:00
J. Nick Koston 7256f23376 Fix performance regression in integration from state_reported (#120621)
* Fix performance regression in integration from state_reported

Because the callbacks were no longer indexed by entity id, users
saw upwards of 1M calls/min

https://github.com/home-assistant/core/pull/113869/files#r1655580523

* Update homeassistant/helpers/event.py

* coverage

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2024-06-27 22:18:17 +02:00
J. Nick Koston 7519603bf5 Bump uiprotect to 4.0.0 (#120617) 2024-06-27 22:18:14 +02:00
Luke Lashley ef47daad9d Bump anova_wifi to 0.14.0 (#120616) 2024-06-27 22:18:11 +02:00
Erik Montnemery 18d283bed6 Don't allow updating a device to have no connections or identifiers (#120603)
* Don't allow updating a device to have no connections or identifiers

* Move check to the top of the function
2024-06-27 22:18:08 +02:00
Steven B 210e906a4d Store tplink credentials_hash outside of device_config (#120597) 2024-06-27 22:17:51 +02:00
J. Nick Koston dcffd6bd7a Remove unused fields from unifiprotect event sensors (#120568) 2024-06-27 22:14:15 +02:00
Alexey ALERT Rubashёff 2c2261254b Improve AtlanticDomesticHotWaterProductionMBLComponent support in Overkiz (#114178)
* add overkiz AtlanticDHW support

Adds support of Overkiz water heater entity selection based on device controllable_name
Adds support of Atlantic water heater based on Atlantic Steatite Cube WI-FI VM 150 S4CS 2400W
Adds more Overkiz water heater binary_sensors, numbers, and sensors

* Changed class annotation

* min_temp and max_temp as properties

* reverted binary_sensors, number, sensor to make separate PRs

* Update homeassistant/components/overkiz/water_heater_entities/atlantic_dhw.py

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>

* Update homeassistant/components/overkiz/water_heater_entities/atlantic_dhw.py

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>

* Update homeassistant/components/overkiz/water_heater_entities/atlantic_dhw.py

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>

* Update homeassistant/components/overkiz/water_heater.py

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>

* Update homeassistant/components/overkiz/water_heater_entities/atlantic_dhw.py

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>

* Update homeassistant/components/overkiz/water_heater_entities/atlantic_dhw.py

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>

* review fixes, typos, and pylint

* review fix

* review fix

* ruff

* temperature properties changed to constructor attributes

* logger removed

* constants usage consistency

* redundant mapping removed

* Update homeassistant/components/overkiz/water_heater_entities/atlantic_dhw.py

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>

* boost mode method annotation typo

* removed away mode for atlantic dwh

* absence and boost mode attributes now support 'prog' state

* heating status bugfix

* electrical consumption sensor

* warm water remaining volume sensor

* away mode reintroduced

* mypy check

* boost plus state support

* Update homeassistant/components/overkiz/sensor.py

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>

* sensors reverted to separate them into their own PR

* check away and boost modes on before switching them off

* atlantic_dhw renamed to atlantic_domestic_hot_water_production

* annotation changed

* AtlanticDomesticHotWaterProductionMBLComponent file renamed, annotation change reverted

---------

Co-authored-by: Mick Vleeshouwer <mick@imick.nl>
2024-06-27 22:14:13 +02:00
Jesse Hills 53e49861a1 Mark esphome integration as platinum (#112565)
Co-authored-by: J. Nick Koston <nick@koston.org>
2024-06-27 22:14:08 +02:00
Franck Nijhof 3da8d0a741 Bump version to 2024.7.0b2 2024-06-26 23:55:20 +02:00
Paul Bottein 0701b0daa9 Update frontend to 20240626.2 (#120614) 2024-06-26 23:55:11 +02:00
Luca Angemi bea6fe30b8 Fix telegram bot thread_id key error (#120613) 2024-06-26 23:55:08 +02:00
Franck Nijhof 7d5d81b229 Bump version to 2024.7.0b1 2024-06-26 22:51:27 +02:00
Franck Nijhof 242b3fa609 Update adguardhome to 0.7.0 (#120605) 2024-06-26 22:48:39 +02:00
Marc Mueller 74204e2ee6 Fix mqtt test fixture usage (#120602) 2024-06-26 22:47:52 +02:00
Jan Bouwhuis da01635a07 Prevent changes to mutable bmw_connected_drive fixture data (#120600) 2024-06-26 22:47:32 +02:00
Shay Levy b5c34808e6 Add last_error reporting to Shelly diagnostics (#120595) 2024-06-26 22:47:09 +02:00
Erik Montnemery 80e70993c8 Remove deprecated run_immediately flag from integration sensor (#120593) 2024-06-26 22:46:50 +02:00
Max 2e01e169ef Correct deprecation warning async_register_static_paths (#120592) 2024-06-26 22:46:30 +02:00
Markus Jacobsen b35442ed2d Improve Bang & Olufsen error messages (#120587)
* Convert logger messages to raised errors where applicable

* Modify exception types

* Improve deezer / tidal error message

* Update homeassistant/components/bang_olufsen/strings.json

Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>

* Update homeassistant/components/bang_olufsen/media_player.py

Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>

---------

Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>
2024-06-26 22:46:27 +02:00
Michael Hansen 1b45069620 Bump intents to 2024.6.26 (#120584)
Bump intents
2024-06-26 22:46:23 +02:00
Shay Levy d3d0e05817 Change Shelly connect task log message level to error (#120582) 2024-06-26 22:46:20 +02:00
TheJulianJES 3d164c6721 Bump ZHA dependencies (#120581) 2024-06-26 22:46:17 +02:00
Florian 6dd1e09354 Don't allow switch toggle when device in locked in AVM FRITZ!SmartHome (#120132)
* fix: set state of the FritzBox-Switch to disabled if the option for manuel switching in the userinterface is disabled

* feat: raise an error instead of disabling switch

* feat: rename method signature

* fix: tests

* fix: wrong import

* feat: Update homeassistant/components/fritzbox/strings.json

Update error message

Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>

* Update tests/components/fritzbox/test_switch.py

feat: update test

Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>

* make ruff happy

* fix expected error message check

---------

Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>
2024-06-26 22:46:13 +02:00
Shay Levy ba456f2564 Align Shelly sleeping devices timeout with non-sleeping (#118969) 2024-06-26 22:46:06 +02:00
Franck Nijhof 3492171ff8 Bump version to 2024.7.0b0 2024-06-26 16:17:57 +02:00
351 changed files with 9219 additions and 4621 deletions
-5
View File
@@ -58,11 +58,6 @@ omit =
homeassistant/components/airvisual/sensor.py
homeassistant/components/airvisual_pro/__init__.py
homeassistant/components/airvisual_pro/sensor.py
homeassistant/components/aladdin_connect/__init__.py
homeassistant/components/aladdin_connect/api.py
homeassistant/components/aladdin_connect/application_credentials.py
homeassistant/components/aladdin_connect/cover.py
homeassistant/components/aladdin_connect/sensor.py
homeassistant/components/alarmdecoder/__init__.py
homeassistant/components/alarmdecoder/alarm_control_panel.py
homeassistant/components/alarmdecoder/binary_sensor.py
+2 -2
View File
@@ -80,8 +80,6 @@ build.json @home-assistant/supervisor
/tests/components/airzone/ @Noltari
/homeassistant/components/airzone_cloud/ @Noltari
/tests/components/airzone_cloud/ @Noltari
/homeassistant/components/aladdin_connect/ @swcloudgenie
/tests/components/aladdin_connect/ @swcloudgenie
/homeassistant/components/alarm_control_panel/ @home-assistant/core
/tests/components/alarm_control_panel/ @home-assistant/core
/homeassistant/components/alert/ @home-assistant/core @frenck
@@ -779,6 +777,8 @@ build.json @home-assistant/supervisor
/tests/components/lg_netcast/ @Drafteed @splinter98
/homeassistant/components/lidarr/ @tkdrob
/tests/components/lidarr/ @tkdrob
/homeassistant/components/lifx/ @Djelibeybi
/tests/components/lifx/ @Djelibeybi
/homeassistant/components/light/ @home-assistant/core
/tests/components/light/ @home-assistant/core
/homeassistant/components/linear_garage_door/ @IceBotYT
+10 -10
View File
@@ -55,13 +55,6 @@ class InvalidUser(HomeAssistantError):
Will not be raised when validating authentication.
"""
class InvalidUsername(InvalidUser):
"""Raised when invalid username is specified.
Will not be raised when validating authentication.
"""
def __init__(
self,
*args: object,
@@ -77,6 +70,13 @@ class InvalidUsername(InvalidUser):
)
class InvalidUsername(InvalidUser):
"""Raised when invalid username is specified.
Will not be raised when validating authentication.
"""
class Data:
"""Hold the user data."""
@@ -216,7 +216,7 @@ class Data:
break
if index is None:
raise InvalidUser
raise InvalidUser(translation_key="user_not_found")
self.users.pop(index)
@@ -232,7 +232,7 @@ class Data:
user["password"] = self.hash_password(new_password, True).decode()
break
else:
raise InvalidUser
raise InvalidUser(translation_key="user_not_found")
@callback
def _validate_new_username(self, new_username: str) -> None:
@@ -275,7 +275,7 @@ class Data:
self._async_check_for_not_normalized_usernames(self._data)
break
else:
raise InvalidUser
raise InvalidUser(translation_key="user_not_found")
async def async_save(self) -> None:
"""Save data."""
+33 -26
View File
@@ -8,7 +8,7 @@ import contextlib
from functools import partial
from itertools import chain
import logging
import logging.handlers
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
import mimetypes
from operator import contains, itemgetter
import os
@@ -257,12 +257,12 @@ async def async_setup_hass(
) -> core.HomeAssistant | None:
"""Set up Home Assistant."""
def create_hass() -> core.HomeAssistant:
async def create_hass() -> core.HomeAssistant:
"""Create the hass object and do basic setup."""
hass = core.HomeAssistant(runtime_config.config_dir)
loader.async_setup(hass)
async_enable_logging(
await async_enable_logging(
hass,
runtime_config.verbose,
runtime_config.log_rotate_days,
@@ -287,7 +287,7 @@ async def async_setup_hass(
async with hass.timeout.async_timeout(10):
await hass.async_stop()
hass = create_hass()
hass = await create_hass()
if runtime_config.skip_pip or runtime_config.skip_pip_packages:
_LOGGER.warning(
@@ -326,13 +326,13 @@ async def async_setup_hass(
if config_dict is None:
recovery_mode = True
await stop_hass(hass)
hass = create_hass()
hass = await create_hass()
elif not basic_setup_success:
_LOGGER.warning("Unable to set up core integrations. Activating recovery mode")
recovery_mode = True
await stop_hass(hass)
hass = create_hass()
hass = await create_hass()
elif any(domain not in hass.config.components for domain in CRITICAL_INTEGRATIONS):
_LOGGER.warning(
@@ -345,7 +345,7 @@ async def async_setup_hass(
recovery_mode = True
await stop_hass(hass)
hass = create_hass()
hass = await create_hass()
if old_logging:
hass.data[DATA_LOGGING] = old_logging
@@ -523,8 +523,7 @@ async def async_from_config_dict(
return hass
@core.callback
def async_enable_logging(
async def async_enable_logging(
hass: core.HomeAssistant,
verbose: bool = False,
log_rotate_days: int | None = None,
@@ -607,23 +606,9 @@ def async_enable_logging(
if (err_path_exists and os.access(err_log_path, os.W_OK)) or (
not err_path_exists and os.access(err_dir, os.W_OK)
):
err_handler: (
logging.handlers.RotatingFileHandler
| logging.handlers.TimedRotatingFileHandler
err_handler = await hass.async_add_executor_job(
_create_log_file, err_log_path, log_rotate_days
)
if log_rotate_days:
err_handler = logging.handlers.TimedRotatingFileHandler(
err_log_path, when="midnight", backupCount=log_rotate_days
)
else:
err_handler = _RotatingFileHandlerWithoutShouldRollOver(
err_log_path, backupCount=1
)
try:
err_handler.doRollover()
except OSError as err:
_LOGGER.error("Error rolling over log file: %s", err)
err_handler.setLevel(logging.INFO if verbose else logging.WARNING)
err_handler.setFormatter(logging.Formatter(fmt, datefmt=FORMAT_DATETIME))
@@ -640,7 +625,29 @@ def async_enable_logging(
async_activate_log_queue_handler(hass)
class _RotatingFileHandlerWithoutShouldRollOver(logging.handlers.RotatingFileHandler):
def _create_log_file(
err_log_path: str, log_rotate_days: int | None
) -> RotatingFileHandler | TimedRotatingFileHandler:
"""Create log file and do roll over."""
err_handler: RotatingFileHandler | TimedRotatingFileHandler
if log_rotate_days:
err_handler = TimedRotatingFileHandler(
err_log_path, when="midnight", backupCount=log_rotate_days
)
else:
err_handler = _RotatingFileHandlerWithoutShouldRollOver(
err_log_path, backupCount=1
)
try:
err_handler.doRollover()
except OSError as err:
_LOGGER.error("Error rolling over log file: %s", err)
return err_handler
class _RotatingFileHandlerWithoutShouldRollOver(RotatingFileHandler):
"""RotatingFileHandler that does not check if it should roll over on every log."""
def shouldRollover(self, record: logging.LogRecord) -> bool:
+1 -1
View File
@@ -9,5 +9,5 @@
},
"iot_class": "cloud_push",
"loggers": ["jaraco.abode", "lomond"],
"requirements": ["jaraco.abode==5.1.2"]
"requirements": ["jaraco.abode==5.2.1"]
}
@@ -7,5 +7,5 @@
"integration_type": "service",
"iot_class": "local_polling",
"loggers": ["adguardhome"],
"requirements": ["adguardhome==0.6.3"]
"requirements": ["adguardhome==0.7.0"]
}
@@ -8,6 +8,34 @@
"default": "mdi:lightbulb-on-outline"
}
},
"number": {
"led_bar_brightness": {
"default": "mdi:brightness-percent"
},
"display_brightness": {
"default": "mdi:brightness-percent"
}
},
"select": {
"configuration_control": {
"default": "mdi:cloud-cog"
},
"display_temperature_unit": {
"default": "mdi:thermometer-lines"
},
"led_bar_mode": {
"default": "mdi:led-strip"
},
"nox_index_learning_time_offset": {
"default": "mdi:clock-outline"
},
"voc_index_learning_time_offset": {
"default": "mdi:clock-outline"
},
"co2_automatic_baseline_calibration": {
"default": "mdi:molecule-co2"
}
},
"sensor": {
"total_volatile_organic_component_index": {
"default": "mdi:molecule"
@@ -17,6 +45,32 @@
},
"pm003_count": {
"default": "mdi:blur"
},
"led_bar_brightness": {
"default": "mdi:brightness-percent"
},
"display_brightness": {
"default": "mdi:brightness-percent"
},
"display_temperature_unit": {
"default": "mdi:thermometer-lines"
},
"led_bar_mode": {
"default": "mdi:led-strip"
},
"nox_index_learning_time_offset": {
"default": "mdi:clock-outline"
},
"voc_index_learning_time_offset": {
"default": "mdi:clock-outline"
},
"co2_automatic_baseline_calibration": {
"default": "mdi:molecule-co2"
}
},
"switch": {
"post_data_to_airgradient": {
"default": "mdi:cogs"
}
}
}
@@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/airgradient",
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["airgradient==0.6.0"],
"requirements": ["airgradient==0.6.1"],
"zeroconf": ["_airgradient._tcp.local."]
}
@@ -88,6 +88,7 @@ LEARNING_TIME_OFFSET_OPTIONS = [
]
ABC_DAYS = [
"1",
"8",
"30",
"90",
@@ -16,6 +16,7 @@
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
"invalid_version": "This firmware version is unsupported. Please upgrade the firmware of the device to at least version 3.1.1."
},
"error": {
@@ -91,8 +92,9 @@
}
},
"co2_automatic_baseline_calibration": {
"name": "CO2 automatic baseline calibration",
"name": "CO2 automatic baseline duration",
"state": {
"1": "1 day",
"8": "8 days",
"30": "30 days",
"90": "90 days",
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/airtouch5",
"iot_class": "local_push",
"loggers": ["airtouch5py"],
"requirements": ["airtouch5py==0.2.8"]
"requirements": ["airtouch5py==0.2.10"]
}
@@ -1,94 +1,38 @@
"""The Aladdin Connect Genie integration."""
# mypy: ignore-errors
from __future__ import annotations
# from genie_partner_sdk.client import AladdinConnectClient
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.config_entry_oauth2_flow import (
OAuth2Session,
async_get_config_entry_implementation,
)
from homeassistant.helpers import issue_registry as ir
from .api import AsyncConfigEntryAuth
from .const import DOMAIN
from .coordinator import AladdinConnectCoordinator
PLATFORMS: list[Platform] = [Platform.COVER, Platform.SENSOR]
type AladdinConnectConfigEntry = ConfigEntry[AladdinConnectCoordinator]
DOMAIN = "aladdin_connect"
async def async_setup_entry(
hass: HomeAssistant, entry: AladdinConnectConfigEntry
) -> bool:
"""Set up Aladdin Connect Genie from a config entry."""
implementation = await async_get_config_entry_implementation(hass, entry)
session = OAuth2Session(hass, entry, implementation)
auth = AsyncConfigEntryAuth(async_get_clientsession(hass), session)
coordinator = AladdinConnectCoordinator(hass, AladdinConnectClient(auth))
await coordinator.async_setup()
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
async_remove_stale_devices(hass, entry)
return True
async def async_unload_entry(
hass: HomeAssistant, entry: AladdinConnectConfigEntry
) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
async def async_migrate_entry(
hass: HomeAssistant, config_entry: AladdinConnectConfigEntry
) -> bool:
"""Migrate old config."""
if config_entry.version < 2:
config_entry.async_start_reauth(hass)
hass.config_entries.async_update_entry(
config_entry,
version=2,
minor_version=1,
)
return True
def async_remove_stale_devices(
hass: HomeAssistant, config_entry: AladdinConnectConfigEntry
) -> None:
"""Remove stale devices from device registry."""
device_registry = dr.async_get(hass)
device_entries = dr.async_entries_for_config_entry(
device_registry, config_entry.entry_id
async def async_setup_entry(hass: HomeAssistant, _: ConfigEntry) -> bool:
"""Set up Aladdin Connect from a config entry."""
ir.async_create_issue(
hass,
DOMAIN,
DOMAIN,
is_fixable=False,
severity=ir.IssueSeverity.ERROR,
translation_key="integration_removed",
translation_placeholders={
"entries": "/config/integrations/integration/aladdin_connect",
},
)
all_device_ids = {door.unique_id for door in config_entry.runtime_data.doors}
for device_entry in device_entries:
device_id: str | None = None
return True
for identifier in device_entry.identifiers:
if identifier[0] == DOMAIN:
device_id = identifier[1]
break
if device_id is None or device_id not in all_device_ids:
# If device_id is None an invalid device entry was found for this config entry.
# If the device_id is not in existing device ids it's a stale device entry.
# Remove config entry from this device entry in either case.
device_registry.async_update_device(
device_entry.id, remove_config_entry_id=config_entry.entry_id
)
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
if all(
config_entry.state is ConfigEntryState.NOT_LOADED
for config_entry in hass.config_entries.async_entries(DOMAIN)
if config_entry.entry_id != entry.entry_id
):
ir.async_delete_issue(hass, DOMAIN, DOMAIN)
return True
@@ -1,33 +0,0 @@
"""API for Aladdin Connect Genie bound to Home Assistant OAuth."""
# mypy: ignore-errors
from typing import cast
from aiohttp import ClientSession
# from genie_partner_sdk.auth import Auth
from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
API_URL = "https://twdvzuefzh.execute-api.us-east-2.amazonaws.com/v1"
API_KEY = "k6QaiQmcTm2zfaNns5L1Z8duBtJmhDOW8JawlCC3"
class AsyncConfigEntryAuth(Auth): # type: ignore[misc]
"""Provide Aladdin Connect Genie authentication tied to an OAuth2 based config entry."""
def __init__(
self,
websession: ClientSession,
oauth_session: OAuth2Session,
) -> None:
"""Initialize Aladdin Connect Genie auth."""
super().__init__(
websession, API_URL, oauth_session.token["access_token"], API_KEY
)
self._oauth_session = oauth_session
async def async_get_access_token(self) -> str:
"""Return a valid access token."""
await self._oauth_session.async_ensure_token_valid()
return cast(str, self._oauth_session.token["access_token"])
@@ -1,14 +0,0 @@
"""application_credentials platform the Aladdin Connect Genie integration."""
from homeassistant.components.application_credentials import AuthorizationServer
from homeassistant.core import HomeAssistant
from .const import OAUTH2_AUTHORIZE, OAUTH2_TOKEN
async def async_get_authorization_server(hass: HomeAssistant) -> AuthorizationServer:
"""Return authorization server."""
return AuthorizationServer(
authorize_url=OAUTH2_AUTHORIZE,
token_url=OAUTH2_TOKEN,
)
@@ -1,70 +1,11 @@
"""Config flow for Aladdin Connect Genie."""
"""Config flow for Aladdin Connect integration."""
from collections.abc import Mapping
import logging
from typing import Any
from homeassistant.config_entries import ConfigFlow
import jwt
from homeassistant.config_entries import ConfigEntry, ConfigFlowResult
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_TOKEN
from homeassistant.helpers.config_entry_oauth2_flow import AbstractOAuth2FlowHandler
from .const import DOMAIN
from . import DOMAIN
class AladdinConnectOAuth2FlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN):
"""Config flow to handle Aladdin Connect Genie OAuth2 authentication."""
class AladdinConnectConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Aladdin Connect."""
DOMAIN = DOMAIN
VERSION = 2
MINOR_VERSION = 1
reauth_entry: ConfigEntry | None = None
async def async_step_reauth(
self, user_input: Mapping[str, Any]
) -> ConfigFlowResult:
"""Perform reauth upon API auth error or upgrade from v1 to v2."""
self.reauth_entry = self.hass.config_entries.async_get_entry(
self.context["entry_id"]
)
return await self.async_step_reauth_confirm()
async def async_step_reauth_confirm(
self, user_input: Mapping[str, Any] | None = None
) -> ConfigFlowResult:
"""Dialog that informs the user that reauth is required."""
if user_input is None:
return self.async_show_form(step_id="reauth_confirm")
return await self.async_step_user()
async def async_oauth_create_entry(self, data: dict[str, Any]) -> ConfigFlowResult:
"""Create an oauth config entry or update existing entry for reauth."""
token_payload = jwt.decode(
data[CONF_TOKEN][CONF_ACCESS_TOKEN], options={"verify_signature": False}
)
if not self.reauth_entry:
await self.async_set_unique_id(token_payload["sub"])
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=token_payload["username"],
data=data,
)
if self.reauth_entry.unique_id == token_payload["username"]:
return self.async_update_reload_and_abort(
self.reauth_entry,
data=data,
unique_id=token_payload["sub"],
)
if self.reauth_entry.unique_id == token_payload["sub"]:
return self.async_update_reload_and_abort(self.reauth_entry, data=data)
return self.async_abort(reason="wrong_account")
@property
def logger(self) -> logging.Logger:
"""Return logger."""
return logging.getLogger(__name__)
VERSION = 1
@@ -1,6 +0,0 @@
"""Constants for the Aladdin Connect Genie integration."""
DOMAIN = "aladdin_connect"
OAUTH2_AUTHORIZE = "https://app.aladdinconnect.net/login.html"
OAUTH2_TOKEN = "https://twdvzuefzh.execute-api.us-east-2.amazonaws.com/v1/oauth2/token"
@@ -1,38 +0,0 @@
"""Define an object to coordinate fetching Aladdin Connect data."""
# mypy: ignore-errors
from datetime import timedelta
import logging
# from genie_partner_sdk.client import AladdinConnectClient
# from genie_partner_sdk.model import GarageDoor
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
class AladdinConnectCoordinator(DataUpdateCoordinator[None]):
"""Aladdin Connect Data Update Coordinator."""
def __init__(self, hass: HomeAssistant, acc: AladdinConnectClient) -> None:
"""Initialize."""
super().__init__(
hass,
logger=_LOGGER,
name=DOMAIN,
update_interval=timedelta(seconds=15),
)
self.acc = acc
self.doors: list[GarageDoor] = []
async def async_setup(self) -> None:
"""Fetch initial data."""
self.doors = await self.acc.get_doors()
async def _async_update_data(self) -> None:
"""Fetch data from API endpoint."""
for door in self.doors:
await self.acc.update_door(door.device_id, door.door_number)
@@ -1,84 +0,0 @@
"""Cover Entity for Genie Garage Door."""
# mypy: ignore-errors
from typing import Any
# from genie_partner_sdk.model import GarageDoor
from homeassistant.components.cover import (
CoverDeviceClass,
CoverEntity,
CoverEntityFeature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AladdinConnectConfigEntry, AladdinConnectCoordinator
from .entity import AladdinConnectEntity
async def async_setup_entry(
hass: HomeAssistant,
config_entry: AladdinConnectConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Aladdin Connect platform."""
coordinator = config_entry.runtime_data
async_add_entities(AladdinDevice(coordinator, door) for door in coordinator.doors)
class AladdinDevice(AladdinConnectEntity, CoverEntity):
"""Representation of Aladdin Connect cover."""
_attr_device_class = CoverDeviceClass.GARAGE
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
_attr_name = None
def __init__(
self, coordinator: AladdinConnectCoordinator, device: GarageDoor
) -> None:
"""Initialize the Aladdin Connect cover."""
super().__init__(coordinator, device)
self._attr_unique_id = device.unique_id
async def async_open_cover(self, **kwargs: Any) -> None:
"""Issue open command to cover."""
await self.coordinator.acc.open_door(
self._device.device_id, self._device.door_number
)
async def async_close_cover(self, **kwargs: Any) -> None:
"""Issue close command to cover."""
await self.coordinator.acc.close_door(
self._device.device_id, self._device.door_number
)
@property
def is_closed(self) -> bool | None:
"""Update is closed attribute."""
value = self.coordinator.acc.get_door_status(
self._device.device_id, self._device.door_number
)
if value is None:
return None
return bool(value == "closed")
@property
def is_closing(self) -> bool | None:
"""Update is closing attribute."""
value = self.coordinator.acc.get_door_status(
self._device.device_id, self._device.door_number
)
if value is None:
return None
return bool(value == "closing")
@property
def is_opening(self) -> bool | None:
"""Update is opening attribute."""
value = self.coordinator.acc.get_door_status(
self._device.device_id, self._device.door_number
)
if value is None:
return None
return bool(value == "opening")
@@ -1,27 +0,0 @@
"""Defines a base Aladdin Connect entity."""
# mypy: ignore-errors
# from genie_partner_sdk.model import GarageDoor
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import AladdinConnectCoordinator
class AladdinConnectEntity(CoordinatorEntity[AladdinConnectCoordinator]):
"""Defines a base Aladdin Connect entity."""
_attr_has_entity_name = True
def __init__(
self, coordinator: AladdinConnectCoordinator, device: GarageDoor
) -> None:
"""Initialize the entity."""
super().__init__(coordinator)
self._device = device
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, device.unique_id)},
name=device.name,
manufacturer="Overhead Door",
)
@@ -1,11 +1,9 @@
{
"domain": "aladdin_connect",
"name": "Aladdin Connect",
"codeowners": ["@swcloudgenie"],
"config_flow": true,
"dependencies": ["application_credentials"],
"disabled": "This integration is disabled because it uses non-open source code to operate.",
"codeowners": [],
"documentation": "https://www.home-assistant.io/integrations/aladdin_connect",
"integration_type": "system",
"iot_class": "cloud_polling",
"requirements": ["genie-partner-sdk==1.0.2"]
"requirements": []
}
@@ -1,5 +0,0 @@
extend = "../../../pyproject.toml"
lint.extend-ignore = [
"F821"
]
@@ -1,80 +0,0 @@
"""Support for Aladdin Connect Garage Door sensors."""
# mypy: ignore-errors
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
# from genie_partner_sdk.client import AladdinConnectClient
# from genie_partner_sdk.model import GarageDoor
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import PERCENTAGE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AladdinConnectConfigEntry, AladdinConnectCoordinator
from .entity import AladdinConnectEntity
@dataclass(frozen=True, kw_only=True)
class AccSensorEntityDescription(SensorEntityDescription):
"""Describes AladdinConnect sensor entity."""
value_fn: Callable[[AladdinConnectClient, str, int], float | None]
SENSORS: tuple[AccSensorEntityDescription, ...] = (
AccSensorEntityDescription(
key="battery_level",
device_class=SensorDeviceClass.BATTERY,
entity_registry_enabled_default=False,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value_fn=AladdinConnectClient.get_battery_status,
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: AladdinConnectConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Aladdin Connect sensor devices."""
coordinator = entry.runtime_data
async_add_entities(
AladdinConnectSensor(coordinator, door, description)
for description in SENSORS
for door in coordinator.doors
)
class AladdinConnectSensor(AladdinConnectEntity, SensorEntity):
"""A sensor implementation for Aladdin Connect devices."""
entity_description: AccSensorEntityDescription
def __init__(
self,
coordinator: AladdinConnectCoordinator,
device: GarageDoor,
description: AccSensorEntityDescription,
) -> None:
"""Initialize a sensor for an Aladdin Connect device."""
super().__init__(coordinator, device)
self.entity_description = description
self._attr_unique_id = f"{device.unique_id}-{description.key}"
@property
def native_value(self) -> float | None:
"""Return the state of the sensor."""
return self.entity_description.value_fn(
self.coordinator.acc, self._device.device_id, self._device.door_number
)
@@ -1,29 +1,8 @@
{
"config": {
"step": {
"pick_implementation": {
"title": "[%key:common::config_flow::title::oauth2_pick_implementation%]"
},
"reauth_confirm": {
"title": "[%key:common::config_flow::title::reauth%]",
"description": "Aladdin Connect needs to re-authenticate your account"
}
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
"oauth_error": "[%key:common::config_flow::abort::oauth2_error%]",
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]",
"oauth_timeout": "[%key:common::config_flow::abort::oauth2_timeout%]",
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
"missing_configuration": "[%key:common::config_flow::abort::oauth2_missing_configuration%]",
"authorize_url_timeout": "[%key:common::config_flow::abort::oauth2_authorize_url_timeout%]",
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]",
"user_rejected_authorize": "[%key:common::config_flow::abort::oauth2_user_rejected_authorize%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
},
"create_entry": {
"default": "[%key:common::config_flow::create_entry::authenticated%]"
"issues": {
"integration_removed": {
"title": "The Aladdin Connect integration has been removed",
"description": "The Aladdin Connect integration has been removed from Home Assistant.\n\nTo resolve this issue, please remove the (now defunct) integration entries from your Home Assistant setup. [Click here to see your existing Aladdin Connect integration entries]({entries})."
}
}
}
+1 -1
View File
@@ -1497,7 +1497,7 @@ async def async_api_adjust_range(
if instance == f"{cover.DOMAIN}.{cover.ATTR_POSITION}":
range_delta = int(range_delta * 20) if range_delta_default else int(range_delta)
service = SERVICE_SET_COVER_POSITION
if not (current := entity.attributes.get(cover.ATTR_POSITION)):
if not (current := entity.attributes.get(cover.ATTR_CURRENT_POSITION)):
msg = f"Unable to determine {entity.entity_id} current position"
raise AlexaInvalidValueError(msg)
position = response_value = min(100, max(0, range_delta + current))
+1 -1
View File
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/anova",
"iot_class": "cloud_push",
"loggers": ["anova_wifi"],
"requirements": ["anova-wifi==0.12.0"]
"requirements": ["anova-wifi==0.17.0"]
}
@@ -68,4 +68,8 @@ class OnlineStatus(CoordinatorEntity[APCUPSdCoordinator], BinarySensorEntity):
"""Returns true if the UPS is online."""
# Check if ONLINE bit is set in STATFLAG.
key = self.entity_description.key.upper()
return int(self.coordinator.data[key], 16) & _VALUE_ONLINE_MASK != 0
# The daemon could either report just a hex ("0x05000008"), or a hex with a "Status Flag"
# suffix ("0x05000008 Status Flag") in older versions.
# Here we trim the suffix if it exists to support both.
flag = self.coordinator.data[key].removesuffix(" Status Flag")
return int(flag, 16) & _VALUE_ONLINE_MASK != 0
@@ -7,5 +7,5 @@
"integration_type": "device",
"iot_class": "local_push",
"loggers": ["pyaprilaire"],
"requirements": ["pyaprilaire==0.7.0"]
"requirements": ["pyaprilaire==0.7.4"]
}
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/apsystems",
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["apsystems-ez1==1.3.1"]
"requirements": ["apsystems-ez1==1.3.3"]
}
@@ -8,5 +8,5 @@
"integration_type": "device",
"iot_class": "cloud_polling",
"loggers": ["aioaquacell"],
"requirements": ["aioaquacell==0.1.7"]
"requirements": ["aioaquacell==0.1.8"]
}
+1 -1
View File
@@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/arve",
"iot_class": "cloud_polling",
"requirements": ["asyncarve==0.0.9"]
"requirements": ["asyncarve==0.1.1"]
}
+1 -1
View File
@@ -2,10 +2,10 @@
from __future__ import annotations
from pathlib import Path
from typing import cast
from aiohttp import ClientResponseError
from path import Path
from yalexs.exceptions import AugustApiAIOHTTPError
from yalexs.manager.exceptions import CannotConnect, InvalidAuth, RequireValidation
from yalexs.manager.gateway import Config as YaleXSConfig
@@ -28,5 +28,5 @@
"documentation": "https://www.home-assistant.io/integrations/august",
"iot_class": "cloud_push",
"loggers": ["pubnub", "yalexs"],
"requirements": ["yalexs==6.4.1", "yalexs-ble==2.4.3"]
"requirements": ["yalexs==6.4.2", "yalexs-ble==2.4.3"]
}
+4 -1
View File
@@ -37,7 +37,10 @@
"message": "Username \"{username}\" already exists"
},
"username_not_normalized": {
"message": "Username \"{new_username}\" is not normalized"
"message": "Username \"{new_username}\" is not normalized. Please make sure the username is lowercase and does not contain any whitespace."
},
"user_not_found": {
"message": "User not found"
}
},
"issues": {
+1 -1
View File
@@ -30,7 +30,7 @@
"iot_class": "local_push",
"loggers": ["axis"],
"quality_scale": "platinum",
"requirements": ["axis==61"],
"requirements": ["axis==62"],
"ssdp": [
{
"manufacturer": "AXIS"
@@ -45,7 +45,7 @@ from homeassistant.components.media_player import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_MODEL
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@@ -316,7 +316,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
@callback
def _async_update_playback_error(self, data: PlaybackError) -> None:
"""Show playback error."""
_LOGGER.error(data.error)
raise HomeAssistantError(data.error)
@callback
def _async_update_playback_progress(self, data: PlaybackProgress) -> None:
@@ -366,7 +366,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
@property
def volume_level(self) -> float | None:
"""Volume level of the media player (0..1)."""
if self._volume.level and self._volume.level.level:
if self._volume.level and self._volume.level.level is not None:
return float(self._volume.level.level / 100)
return None
@@ -516,7 +516,9 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
self.async_write_ha_state()
else:
_LOGGER.error("Seeking is currently only supported when using Deezer")
raise HomeAssistantError(
translation_domain=DOMAIN, translation_key="non_deezer_seeking"
)
async def async_media_previous_track(self) -> None:
"""Send the previous track command."""
@@ -529,12 +531,14 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
async def async_select_source(self, source: str) -> None:
"""Select an input source."""
if source not in self._sources.values():
_LOGGER.error(
"Invalid source: %s. Valid sources are: %s",
source,
list(self._sources.values()),
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="invalid_source",
translation_placeholders={
"invalid_source": source,
"valid_sources": ",".join(list(self._sources.values())),
},
)
return
key = [x for x in self._sources if self._sources[x] == source][0]
@@ -559,12 +563,14 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
media_type = MediaType.MUSIC
if media_type not in VALID_MEDIA_TYPES:
_LOGGER.error(
"%s is an invalid type. Valid values are: %s",
media_type,
VALID_MEDIA_TYPES,
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="invalid_media_type",
translation_placeholders={
"invalid_media_type": media_type,
"valid_media_types": ",".join(VALID_MEDIA_TYPES),
},
)
return
if media_source.is_media_source_id(media_id):
sourced_media = await media_source.async_resolve_media(
@@ -681,7 +687,14 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
)
except ApiException as error:
_LOGGER.error(json.loads(error.body)["message"])
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="play_media_error",
translation_placeholders={
"media_type": media_type,
"error_message": json.loads(error.body)["message"],
},
) from error
async def async_browse_media(
self,
@@ -28,6 +28,18 @@
"exceptions": {
"m3u_invalid_format": {
"message": "Media sources with the .m3u extension are not supported."
},
"non_deezer_seeking": {
"message": "Seeking is currently only supported when using Deezer"
},
"invalid_source": {
"message": "Invalid source: {invalid_source}. Valid sources are: {valid_sources}"
},
"invalid_media_type": {
"message": "{invalid_media_type} is an invalid type. Valid values are: {valid_media_types}."
},
"play_media_error": {
"message": "An error occurred while attempting to play {media_type}: {error_message}."
}
}
}
@@ -58,7 +58,7 @@ class BringConfigFlow(ConfigFlow, domain=DOMAIN):
):
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=self.info["name"] or user_input[CONF_EMAIL], data=user_input
title=self.info.get("name") or user_input[CONF_EMAIL], data=user_input
)
return self.async_show_form(
@@ -377,6 +377,14 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
# Return if integration has migrated already
return
supported_features = self.supported_features
if supported_features & (
ClimateEntityFeature.TURN_ON | ClimateEntityFeature.TURN_OFF
):
# The entity supports both turn_on and turn_off, the backwards compatibility
# checks are not needed
return
supported_features = self.supported_features
if not supported_features & ClimateEntityFeature.TURN_OFF and (
type(self).async_turn_off is not ClimateEntity.async_turn_off
@@ -53,11 +53,7 @@ async def websocket_create(
)
return
try:
await provider.async_add_auth(msg["username"], msg["password"])
except auth_ha.InvalidUser:
connection.send_error(msg["id"], "username_exists", "Username already exists")
return
await provider.async_add_auth(msg["username"], msg["password"])
credentials = await provider.async_get_or_create_credentials(
{"username": msg["username"]}
@@ -94,13 +90,7 @@ async def websocket_delete(
connection.send_result(msg["id"])
return
try:
await provider.async_remove_auth(msg["username"])
except auth_ha.InvalidUser:
connection.send_error(
msg["id"], "auth_not_found", "Given username was not found."
)
return
await provider.async_remove_auth(msg["username"])
connection.send_result(msg["id"])
@@ -187,14 +177,8 @@ async def websocket_admin_change_password(
)
return
try:
await provider.async_change_password(username, msg["password"])
connection.send_result(msg["id"])
except auth_ha.InvalidUser:
connection.send_error(
msg["id"], "credentials_not_found", "Credentials not found"
)
return
await provider.async_change_password(username, msg["password"])
connection.send_result(msg["id"])
@websocket_api.websocket_command(
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/conversation",
"integration_type": "system",
"quality_scale": "internal",
"requirements": ["hassil==1.7.1", "home-assistant-intents==2024.6.21"]
"requirements": ["hassil==1.7.1", "home-assistant-intents==2024.7.3"]
}
+7 -7
View File
@@ -4,11 +4,11 @@ from datetime import timedelta
import logging
from pizzapi import Address, Customer, Order
from pizzapi.address import StoreException
import voluptuous as vol
from homeassistant.components import http
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
@@ -118,7 +118,7 @@ class Dominos:
self.country = conf.get(ATTR_COUNTRY)
try:
self.closest_store = self.address.closest_store()
except StoreException:
except Exception: # noqa: BLE001
self.closest_store = None
def handle_order(self, call: ServiceCall) -> None:
@@ -139,7 +139,7 @@ class Dominos:
"""Update the shared closest store (if open)."""
try:
self.closest_store = self.address.closest_store()
except StoreException:
except Exception: # noqa: BLE001
self.closest_store = None
return False
return True
@@ -219,7 +219,7 @@ class DominosOrder(Entity):
"""Update the order state and refreshes the store."""
try:
self.dominos.update_closest_store()
except StoreException:
except Exception: # noqa: BLE001
self._orderable = False
return
@@ -227,13 +227,13 @@ class DominosOrder(Entity):
order = self.order()
order.pay_with()
self._orderable = True
except StoreException:
except Exception: # noqa: BLE001
self._orderable = False
def order(self):
"""Create the order object."""
if self.dominos.closest_store is None:
raise StoreException
raise HomeAssistantError("No store available")
order = Order(
self.dominos.closest_store,
@@ -252,7 +252,7 @@ class DominosOrder(Entity):
try:
order = self.order()
order.place()
except StoreException:
except Exception: # noqa: BLE001
self._orderable = False
_LOGGER.warning(
"Attempted to order Dominos - Order invalid or store closed"
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/dominos",
"iot_class": "cloud_polling",
"loggers": ["pizzapi"],
"requirements": ["pizzapi==0.0.3"]
"requirements": ["pizzapi==0.0.6"]
}
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/easyenergy",
"iot_class": "cloud_polling",
"quality_scale": "platinum",
"requirements": ["easyenergy==2.1.1"]
"requirements": ["easyenergy==2.1.2"]
}
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/ecovacs",
"iot_class": "cloud_push",
"loggers": ["sleekxmppfs", "sucks", "deebot_client"],
"requirements": ["py-sucks==0.9.10", "deebot-client==8.0.0"]
"requirements": ["py-sucks==0.9.10", "deebot-client==8.1.1"]
}
@@ -6,5 +6,5 @@
"iot_class": "local_push",
"loggers": ["sense_energy"],
"quality_scale": "internal",
"requirements": ["sense-energy==0.12.2"]
"requirements": ["sense-energy==0.12.4"]
}
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/energyzero",
"iot_class": "cloud_polling",
"quality_scale": "platinum",
"requirements": ["energyzero==2.1.0"]
"requirements": ["energyzero==2.1.1"]
}
+5 -1
View File
@@ -16,6 +16,8 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from .const import CONF_SOURCE_BOUQUET
type Enigma2ConfigEntry = ConfigEntry[OpenWebIfDevice]
PLATFORMS = [Platform.MEDIA_PLAYER]
@@ -35,7 +37,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: Enigma2ConfigEntry) -> b
hass, verify_ssl=entry.data[CONF_VERIFY_SSL], base_url=base_url
)
entry.runtime_data = OpenWebIfDevice(session)
entry.runtime_data = OpenWebIfDevice(
session, source_bouquet=entry.options.get(CONF_SOURCE_BOUQUET)
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
@@ -7,5 +7,5 @@
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["openwebif"],
"requirements": ["openwebifpy==4.2.4"]
"requirements": ["openwebifpy==4.2.5"]
}
@@ -199,7 +199,8 @@ class Enigma2Device(MediaPlayerEntity):
async def async_mute_volume(self, mute: bool) -> None:
"""Mute or unmute."""
await self._device.toggle_mute()
if mute != self._device.status.muted:
await self._device.toggle_mute()
async def async_select_source(self, source: str) -> None:
"""Select input source."""
@@ -6,7 +6,7 @@
"documentation": "https://www.home-assistant.io/integrations/enphase_envoy",
"iot_class": "local_polling",
"loggers": ["pyenphase"],
"requirements": ["pyenphase==1.20.3"],
"requirements": ["pyenphase==1.20.6"],
"zeroconf": [
{
"type": "_enphase-envoy._tcp.local."
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
"iot_class": "cloud_polling",
"loggers": ["env_canada"],
"requirements": ["env-canada==0.6.3"]
"requirements": ["env-canada==0.7.1"]
}
@@ -19,7 +19,6 @@ from homeassistant.const import (
PERCENTAGE,
UV_INDEX,
UnitOfLength,
UnitOfPrecipitationDepth,
UnitOfPressure,
UnitOfSpeed,
UnitOfTemperature,
@@ -114,14 +113,6 @@ SENSOR_TYPES: tuple[ECSensorEntityDescription, ...] = (
native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data: data.conditions.get("pop", {}).get("value"),
),
ECSensorEntityDescription(
key="precip_yesterday",
translation_key="precip_yesterday",
device_class=SensorDeviceClass.PRECIPITATION,
native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.conditions.get("precip_yesterday", {}).get("value"),
),
ECSensorEntityDescription(
key="pressure",
translation_key="pressure",
@@ -52,9 +52,6 @@
"pop": {
"name": "Chance of precipitation"
},
"precip_yesterday": {
"name": "Precipitation yesterday"
},
"pressure": {
"name": "Barometric pressure"
},
@@ -15,6 +15,7 @@
"iot_class": "local_push",
"loggers": ["aioesphomeapi", "noiseprotocol", "bleak_esphome"],
"mqtt": ["esphome/discover/#"],
"quality_scale": "platinum",
"requirements": [
"aioesphomeapi==24.6.1",
"esphome-dashboard-api==1.2.3",
@@ -97,6 +97,7 @@ class ESPHomeDashboardUpdateEntity(
_attr_title = "ESPHome"
_attr_name = "Firmware"
_attr_release_url = "https://esphome.io/changelog/"
_attr_entity_registry_enabled_default = False
def __init__(
self, entry_data: RuntimeEntryData, coordinator: ESPHomeDashboardCoordinator
@@ -107,13 +107,6 @@ class FeedReaderConfigFlow(ConfigFlow, domain=DOMAIN):
return self.abort_on_import_error(user_input[CONF_URL], "url_error")
return self.show_user_form(user_input, {"base": "url_error"})
if not feed.entries:
if self.context["source"] == SOURCE_IMPORT:
return self.abort_on_import_error(
user_input[CONF_URL], "no_feed_entries"
)
return self.show_user_form(user_input, {"base": "no_feed_entries"})
feed_title = feed["feed"]["title"]
return self.async_create_entry(
@@ -161,13 +154,6 @@ class FeedReaderConfigFlow(ConfigFlow, domain=DOMAIN):
step_id="reconfigure_confirm",
errors={"base": "url_error"},
)
if not feed.entries:
return self.show_user_form(
user_input=user_input,
description_placeholders={"name": self._config_entry.title},
step_id="reconfigure_confirm",
errors={"base": "no_feed_entries"},
)
self.hass.config_entries.async_update_entry(self._config_entry, data=user_input)
return self.async_abort(reason="reconfigure_successful")
@@ -18,8 +18,7 @@
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]"
},
"error": {
"url_error": "The URL could not be opened.",
"no_feed_entries": "The URL seems not to serve any feed entries."
"url_error": "The URL could not be opened."
}
},
"options": {
@@ -38,10 +37,6 @@
"import_yaml_error_url_error": {
"title": "The Feedreader YAML configuration import failed",
"description": "Configuring the Feedreader using YAML is being removed but there was a connection error when trying to import the YAML configuration for `{url}`.\n\nPlease verify that url is reachable and accessable for Home Assistant and restart Home Assistant to try again or remove the Feedreader YAML configuration from your configuration.yaml file and continue to set up the integration manually."
},
"import_yaml_error_no_feed_entries": {
"title": "[%key:component::feedreader::issues::import_yaml_error_url_error::title%]",
"description": "Configuring the Feedreader using YAML is being removed but when trying to import the YAML configuration for `{url}` no feed entries were found.\n\nPlease verify that url serves any feed entries and restart Home Assistant to try again or remove the Feedreader YAML configuration from your configuration.yaml file and continue to set up the integration manually."
}
}
}
@@ -98,7 +98,7 @@ class FlumeNotificationDataUpdateCoordinator(DataUpdateCoordinator[None]):
# The related binary sensors (leak detected, high flow, low battery)
# will be active until the notification is deleted in the Flume app.
self.notifications = pyflume.FlumeNotificationList(
self.auth, read=None, sort_direction="DESC"
self.auth, read=None
).notification_list
_LOGGER.debug("Notifications %s", self.notifications)
+1 -1
View File
@@ -11,5 +11,5 @@
"documentation": "https://www.home-assistant.io/integrations/flume",
"iot_class": "cloud_polling",
"loggers": ["pyflume"],
"requirements": ["PyFlume==0.8.7"]
"requirements": ["PyFlume==0.6.5"]
}
@@ -8,7 +8,7 @@
"iot_class": "local_polling",
"loggers": ["pyfritzhome"],
"quality_scale": "gold",
"requirements": ["pyfritzhome==0.6.11"],
"requirements": ["pyfritzhome==0.6.12"],
"ssdp": [
{
"st": "urn:schemas-upnp-org:device:fritzbox:1"
@@ -81,6 +81,9 @@
}
},
"exceptions": {
"manual_switching_disabled": {
"message": "Can't toggle switch while manual switching is disabled for the device."
},
"change_preset_while_active_mode": {
"message": "Can't change preset while holiday or summer mode is active on the device."
},
@@ -6,9 +6,11 @@ from typing import Any
from homeassistant.components.switch import SwitchEntity
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import FritzBoxDeviceEntity
from .const import DOMAIN
from .coordinator import FritzboxConfigEntry
@@ -48,10 +50,20 @@ class FritzboxSwitch(FritzBoxDeviceEntity, SwitchEntity):
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
self.check_lock_state()
await self.hass.async_add_executor_job(self.data.set_switch_state_on)
await self.coordinator.async_refresh()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
self.check_lock_state()
await self.hass.async_add_executor_job(self.data.set_switch_state_off)
await self.coordinator.async_refresh()
def check_lock_state(self) -> None:
"""Raise an Error if manual switching via FRITZ!Box user interface is disabled."""
if self.data.lock:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="manual_switching_disabled",
)
@@ -20,5 +20,5 @@
"documentation": "https://www.home-assistant.io/integrations/frontend",
"integration_type": "system",
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20240626.0"]
"requirements": ["home-assistant-frontend==20240710.0"]
}
@@ -2,9 +2,12 @@
from __future__ import annotations
from fullykiosk import FullyKioskError
from homeassistant.components.camera import Camera, CameraEntityFeature
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 .const import DOMAIN
@@ -36,8 +39,12 @@ class FullyCameraEntity(FullyKioskEntity, Camera):
self, width: int | None = None, height: int | None = None
) -> bytes | None:
"""Return bytes of camera image."""
image_bytes: bytes = await self.coordinator.fully.getCamshot()
return image_bytes
try:
image_bytes: bytes = await self.coordinator.fully.getCamshot()
except FullyKioskError as err:
raise HomeAssistantError(err) from err
else:
return image_bytes
async def async_turn_on(self) -> None:
"""Turn on camera."""
@@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/garages_amsterdam",
"iot_class": "cloud_polling",
"requirements": ["odp-amsterdam==6.0.1"]
"requirements": ["odp-amsterdam==6.0.2"]
}
@@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/calendar.google",
"iot_class": "cloud_polling",
"loggers": ["googleapiclient"],
"requirements": ["gcal-sync==6.0.4", "oauth2client==4.1.3", "ical==8.0.1"]
"requirements": ["gcal-sync==6.1.4", "oauth2client==4.1.3", "ical==8.1.1"]
}
@@ -95,9 +95,12 @@ def _format_tool(
) -> dict[str, Any]:
"""Format tool specification."""
parameters = _format_schema(
convert(tool.parameters, custom_serializer=custom_serializer)
)
if tool.parameters.schema:
parameters = _format_schema(
convert(tool.parameters, custom_serializer=custom_serializer)
)
else:
parameters = None
return protos.Tool(
{
@@ -6,5 +6,5 @@
"dependencies": ["network"],
"documentation": "https://www.home-assistant.io/integrations/govee_light_local",
"iot_class": "local_push",
"requirements": ["govee-local-api==1.5.0"]
"requirements": ["govee-local-api==1.5.1"]
}
+1 -1
View File
@@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/gree",
"iot_class": "local_polling",
"loggers": ["greeclimate"],
"requirements": ["greeclimate==1.4.1"]
"requirements": ["greeclimate==1.4.6"]
}
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/here_travel_time",
"iot_class": "cloud_polling",
"loggers": ["here_routing", "here_transit", "homeassistant.helpers.location"],
"requirements": ["here-routing==0.2.0", "here-transit==1.2.0"]
"requirements": ["here-routing==1.0.1", "here-transit==1.2.1"]
}
+4 -3
View File
@@ -142,10 +142,10 @@ class HiveClimateEntity(HiveEntity, ClimateEntity):
self.device = await self.hive.heating.getClimate(self.device)
self._attr_available = self.device["deviceData"].get("online")
if self._attr_available:
self._attr_hvac_mode = HIVE_TO_HASS_STATE[self.device["status"]["mode"]]
self._attr_hvac_action = HIVE_TO_HASS_HVAC_ACTION[
self._attr_hvac_mode = HIVE_TO_HASS_STATE.get(self.device["status"]["mode"])
self._attr_hvac_action = HIVE_TO_HASS_HVAC_ACTION.get(
self.device["status"]["action"]
]
)
self._attr_current_temperature = self.device["status"][
"current_temperature"
]
@@ -154,5 +154,6 @@ class HiveClimateEntity(HiveEntity, ClimateEntity):
self._attr_max_temp = self.device["max_temp"]
if self.device["status"]["boost"] == "ON":
self._attr_preset_mode = PRESET_BOOST
self._attr_hvac_mode = HVACMode.HEAT
else:
self._attr_preset_mode = PRESET_NONE
@@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/holiday",
"iot_class": "local_polling",
"requirements": ["holidays==0.51", "babel==2.15.0"]
"requirements": ["holidays==0.53", "babel==2.15.0"]
}
@@ -156,7 +156,6 @@ SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
key="GAS_POWER",
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
device_class=SensorDeviceClass.GAS,
state_class=SensorStateClass.MEASUREMENT,
),
"GAS_ENERGY_COUNTER": SensorEntityDescription(
key="GAS_ENERGY_COUNTER",
@@ -216,14 +216,13 @@ class HomematicipGenericEntity(Entity):
@property
def unique_id(self) -> str:
"""Return a unique ID."""
suffix = ""
if self._post is not None:
suffix = f"_{self._post}"
unique_id = f"{self.__class__.__name__}_{self._device.id}"
if self._is_multi_channel:
return f"{self.__class__.__name__}_Channel{self._channel}_{self._device.id}{suffix}"
unique_id = (
f"{self.__class__.__name__}_Channel{self._channel}_{self._device.id}"
)
return f"{self.__class__.__name__}_{self._device.id}{suffix}"
return unique_id
@property
def icon(self) -> str | None:
@@ -3,7 +3,6 @@
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from homematicip.aio.device import (
@@ -36,7 +35,6 @@ from homematicip.base.functionalChannels import FunctionalChannel
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
@@ -163,19 +161,28 @@ async def async_setup_entry(
for ch in get_channels_from_device(
device, FunctionalChannelType.ENERGY_SENSORS_INTERFACE_CHANNEL
):
if ch.connectedEnergySensorType not in SENSORS_ESI:
continue
if ch.connectedEnergySensorType == ESI_CONNECTED_SENSOR_TYPE_IEC:
if ch.currentPowerConsumption is not None:
entities.append(HmipEsiIecPowerConsumption(hap, device))
if ch.energyCounterOneType != ESI_TYPE_UNKNOWN:
entities.append(HmipEsiIecEnergyCounterHighTariff(hap, device))
if ch.energyCounterTwoType != ESI_TYPE_UNKNOWN:
entities.append(HmipEsiIecEnergyCounterLowTariff(hap, device))
if ch.energyCounterThreeType != ESI_TYPE_UNKNOWN:
entities.append(
HmipEsiIecEnergyCounterInputSingleTariff(hap, device)
)
new_entities = [
HmipEsiSensorEntity(hap, device, ch.index, description)
for description in SENSORS_ESI[ch.connectedEnergySensorType]
]
if ch.connectedEnergySensorType == ESI_CONNECTED_SENSOR_TYPE_GAS:
if ch.currentGasFlow is not None:
entities.append(HmipEsiGasCurrentGasFlow(hap, device))
if ch.gasVolume is not None:
entities.append(HmipEsiGasGasVolume(hap, device))
entities.extend(
entity
for entity in new_entities
if entity.entity_description.exists_fn(ch)
)
if ch.connectedEnergySensorType == ESI_CONNECTED_SENSOR_TYPE_LED:
if ch.currentPowerConsumption is not None:
entities.append(HmipEsiLedCurrentPowerConsumption(hap, device))
entities.append(HmipEsiLedEnergyCounterHighTariff(hap, device))
async_add_entities(entities)
@@ -434,132 +441,185 @@ class HomematicpTemperatureExternalSensorDelta(HomematicipGenericEntity, SensorE
return self._device.temperatureExternalDelta
@dataclass(kw_only=True, frozen=True)
class HmipEsiSensorEntityDescription(SensorEntityDescription):
"""SensorEntityDescription for HmIP Sensors."""
value_fn: Callable[[AsyncEnergySensorsInterface], StateType]
exists_fn: Callable[[FunctionalChannel], bool]
type_fn: Callable[[AsyncEnergySensorsInterface], str]
SENSORS_ESI = {
ESI_CONNECTED_SENSOR_TYPE_IEC: [
HmipEsiSensorEntityDescription(
key=ESI_TYPE_CURRENT_POWER_CONSUMPTION,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda device: device.functional_channel.currentPowerConsumption,
exists_fn=lambda channel: channel.currentPowerConsumption is not None,
type_fn=lambda device: "CurrentPowerConsumption",
),
HmipEsiSensorEntityDescription(
key=ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda device: device.functional_channel.energyCounterOne,
exists_fn=lambda channel: channel.energyCounterOneType != ESI_TYPE_UNKNOWN,
type_fn=lambda device: device.functional_channel.energyCounterOneType,
),
HmipEsiSensorEntityDescription(
key=ESI_TYPE_ENERGY_COUNTER_USAGE_LOW_TARIFF,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda device: device.functional_channel.energyCounterTwo,
exists_fn=lambda channel: channel.energyCounterTwoType != ESI_TYPE_UNKNOWN,
type_fn=lambda device: device.functional_channel.energyCounterTwoType,
),
HmipEsiSensorEntityDescription(
key=ESI_TYPE_ENERGY_COUNTER_INPUT_SINGLE_TARIFF,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda device: device.functional_channel.energyCounterThree,
exists_fn=lambda channel: channel.energyCounterThreeType
!= ESI_TYPE_UNKNOWN,
type_fn=lambda device: device.functional_channel.energyCounterThreeType,
),
],
ESI_CONNECTED_SENSOR_TYPE_LED: [
HmipEsiSensorEntityDescription(
key=ESI_TYPE_CURRENT_POWER_CONSUMPTION,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda device: device.functional_channel.currentPowerConsumption,
exists_fn=lambda channel: channel.currentPowerConsumption is not None,
type_fn=lambda device: "CurrentPowerConsumption",
),
HmipEsiSensorEntityDescription(
key=ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda device: device.functional_channel.energyCounterOne,
exists_fn=lambda channel: channel.energyCounterOne is not None,
type_fn=lambda device: ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF,
),
],
ESI_CONNECTED_SENSOR_TYPE_GAS: [
HmipEsiSensorEntityDescription(
key=ESI_TYPE_CURRENT_GAS_FLOW,
native_unit_of_measurement=UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR,
device_class=SensorDeviceClass.VOLUME_FLOW_RATE,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda device: device.functional_channel.currentGasFlow,
exists_fn=lambda channel: channel.currentGasFlow is not None,
type_fn=lambda device: "CurrentGasFlow",
),
HmipEsiSensorEntityDescription(
key=ESI_TYPE_CURRENT_GAS_VOLUME,
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
device_class=SensorDeviceClass.VOLUME,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda device: device.functional_channel.gasVolume,
exists_fn=lambda channel: channel.gasVolume is not None,
type_fn=lambda device: "GasVolume",
),
],
}
class HmipEsiSensorEntity(HomematicipGenericEntity, SensorEntity):
"""EntityDescription for HmIP-ESI Sensors."""
entity_description: HmipEsiSensorEntityDescription
def __init__(
self,
hap: HomematicipHAP,
device: HomematicipGenericEntity,
channel_index: int,
entity_description: HmipEsiSensorEntityDescription,
key: str,
value_fn: Callable[[FunctionalChannel], StateType],
type_fn: Callable[[FunctionalChannel], str],
) -> None:
"""Initialize Sensor Entity."""
super().__init__(
hap=hap,
device=device,
channel=channel_index,
post=entity_description.key,
channel=1,
post=key,
is_multi_channel=False,
)
self.entity_description = entity_description
self._value_fn = value_fn
self._type_fn = type_fn
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes of the esi sensor."""
state_attr = super().extra_state_attributes
state_attr[ATTR_ESI_TYPE] = self.entity_description.type_fn(self)
state_attr[ATTR_ESI_TYPE] = self._type_fn(self.functional_channel)
return state_attr
@property
def native_value(self) -> str | None:
"""Return the state of the sensor."""
return str(self.entity_description.value_fn(self))
return str(self._value_fn(self.functional_channel))
class HmipEsiIecPowerConsumption(HmipEsiSensorEntity):
"""Representation of the Hmip-ESI IEC currentPowerConsumption sensor."""
_attr_device_class = SensorDeviceClass.POWER
_attr_native_unit_of_measurement = UnitOfPower.WATT
_attr_state_class = SensorStateClass.MEASUREMENT
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(
hap,
device,
key="CurrentPowerConsumption",
value_fn=lambda channel: channel.currentPowerConsumption,
type_fn=lambda channel: "CurrentPowerConsumption",
)
class HmipEsiIecEnergyCounterHighTariff(HmipEsiSensorEntity):
"""Representation of the Hmip-ESI IEC energyCounterOne sensor."""
_attr_device_class = SensorDeviceClass.ENERGY
_attr_native_unit_of_measurement = UnitOfEnergy.KILO_WATT_HOUR
_attr_state_class = SensorStateClass.TOTAL_INCREASING
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(
hap,
device,
key=ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF,
value_fn=lambda channel: channel.energyCounterOne,
type_fn=lambda channel: channel.energyCounterOneType,
)
class HmipEsiIecEnergyCounterLowTariff(HmipEsiSensorEntity):
"""Representation of the Hmip-ESI IEC energyCounterTwo sensor."""
_attr_device_class = SensorDeviceClass.ENERGY
_attr_native_unit_of_measurement = UnitOfEnergy.KILO_WATT_HOUR
_attr_state_class = SensorStateClass.TOTAL_INCREASING
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(
hap,
device,
key=ESI_TYPE_ENERGY_COUNTER_USAGE_LOW_TARIFF,
value_fn=lambda channel: channel.energyCounterTwo,
type_fn=lambda channel: channel.energyCounterTwoType,
)
class HmipEsiIecEnergyCounterInputSingleTariff(HmipEsiSensorEntity):
"""Representation of the Hmip-ESI IEC energyCounterThree sensor."""
_attr_device_class = SensorDeviceClass.ENERGY
_attr_native_unit_of_measurement = UnitOfEnergy.KILO_WATT_HOUR
_attr_state_class = SensorStateClass.TOTAL_INCREASING
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(
hap,
device,
key=ESI_TYPE_ENERGY_COUNTER_INPUT_SINGLE_TARIFF,
value_fn=lambda channel: channel.energyCounterThree,
type_fn=lambda channel: channel.energyCounterThreeType,
)
class HmipEsiGasCurrentGasFlow(HmipEsiSensorEntity):
"""Representation of the Hmip-ESI Gas currentGasFlow sensor."""
_attr_device_class = SensorDeviceClass.VOLUME_FLOW_RATE
_attr_native_unit_of_measurement = UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR
_attr_state_class = SensorStateClass.MEASUREMENT
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(
hap,
device,
key="CurrentGasFlow",
value_fn=lambda channel: channel.currentGasFlow,
type_fn=lambda channel: "CurrentGasFlow",
)
class HmipEsiGasGasVolume(HmipEsiSensorEntity):
"""Representation of the Hmip-ESI Gas gasVolume sensor."""
_attr_device_class = SensorDeviceClass.GAS
_attr_native_unit_of_measurement = UnitOfVolume.CUBIC_METERS
_attr_state_class = SensorStateClass.TOTAL_INCREASING
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(
hap,
device,
key="GasVolume",
value_fn=lambda channel: channel.gasVolume,
type_fn=lambda channel: "GasVolume",
)
class HmipEsiLedCurrentPowerConsumption(HmipEsiSensorEntity):
"""Representation of the Hmip-ESI LED currentPowerConsumption sensor."""
_attr_device_class = SensorDeviceClass.POWER
_attr_native_unit_of_measurement = UnitOfPower.WATT
_attr_state_class = SensorStateClass.MEASUREMENT
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(
hap,
device,
key="CurrentPowerConsumption",
value_fn=lambda channel: channel.currentPowerConsumption,
type_fn=lambda channel: "CurrentPowerConsumption",
)
class HmipEsiLedEnergyCounterHighTariff(HmipEsiSensorEntity):
"""Representation of the Hmip-ESI LED energyCounterOne sensor."""
_attr_device_class = SensorDeviceClass.ENERGY
_attr_native_unit_of_measurement = UnitOfEnergy.KILO_WATT_HOUR
_attr_state_class = SensorStateClass.TOTAL_INCREASING
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(
hap,
device,
key=ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF,
value_fn=lambda channel: channel.energyCounterOne,
type_fn=lambda channel: ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF,
)
class HomematicipPassageDetectorDeltaCounter(HomematicipGenericEntity, SensorEntity):
+6 -7
View File
@@ -71,13 +71,12 @@ class HoneywellSwitch(SwitchEntity):
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on if heat mode is enabled."""
if self._device.system_mode == "heat":
try:
await self._device.set_system_mode("emheat")
except SomeComfortError as err:
raise HomeAssistantError(
translation_domain=DOMAIN, translation_key="switch_failed_on"
) from err
try:
await self._device.set_system_mode("emheat")
except SomeComfortError as err:
raise HomeAssistantError(
translation_domain=DOMAIN, translation_key="switch_failed_on"
) from err
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off if on."""
+1 -1
View File
@@ -483,7 +483,7 @@ class HomeAssistantHTTP:
frame.report(
"calls hass.http.register_static_path which is deprecated because "
"it does blocking I/O in the event loop, instead "
"call `await hass.http.async_register_static_path("
"call `await hass.http.async_register_static_paths("
f'[StaticPathConfig("{url_path}", "{path}", {cache_headers})])`; '
"This function will be removed in 2025.7",
exclude_integrations={"http"},
@@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/husqvarna_automower",
"iot_class": "cloud_push",
"loggers": ["aioautomower"],
"requirements": ["aioautomower==2024.6.1"]
"requirements": ["aioautomower==2024.6.4"]
}
@@ -184,6 +184,8 @@ RESTRICTED_REASONS: list = [
RestrictedReasons.WEEK_SCHEDULE.lower(),
]
STATE_NO_WORK_AREA_ACTIVE = "no_work_area_active"
@callback
def _get_work_area_names(data: MowerAttributes) -> list[str]:
@@ -191,16 +193,21 @@ def _get_work_area_names(data: MowerAttributes) -> list[str]:
if TYPE_CHECKING:
# Sensor does not get created if it is None
assert data.work_areas is not None
return [data.work_areas[work_area_id].name for work_area_id in data.work_areas]
work_area_list = [
data.work_areas[work_area_id].name for work_area_id in data.work_areas
]
work_area_list.append(STATE_NO_WORK_AREA_ACTIVE)
return work_area_list
@callback
def _get_current_work_area_name(data: MowerAttributes) -> str:
"""Return the name of the current work area."""
if data.mower.work_area_id is None:
return STATE_NO_WORK_AREA_ACTIVE
if TYPE_CHECKING:
# Sensor does not get created if values are None
assert data.work_areas is not None
assert data.mower.work_area_id is not None
return data.work_areas[data.mower.work_area_id].name
@@ -252,7 +252,8 @@
"work_area": {
"name": "Work area",
"state": {
"my_lawn": "My lawn"
"my_lawn": "My lawn",
"no_work_area_active": "No work area active"
}
}
},
+2 -2
View File
@@ -6,7 +6,7 @@
"description": "Enter your credentials",
"data": {
"username": "[%key:common::config_flow::data::email%]",
"password": "[%key:common::config_flow::data::password%]",
"password": "App-specific password",
"with_family": "With family"
}
},
@@ -14,7 +14,7 @@
"title": "[%key:common::config_flow::title::reauth%]",
"description": "Your previously entered password for {username} is no longer working. Update your password to keep using this integration.",
"data": {
"password": "[%key:common::config_flow::data::password%]"
"password": "App-specific password"
}
},
"trusted_device": {
@@ -12,5 +12,5 @@
"documentation": "https://www.home-assistant.io/integrations/idasen_desk",
"iot_class": "local_push",
"quality_scale": "silver",
"requirements": ["idasen-ha==2.6.1"]
"requirements": ["idasen-ha==2.6.2"]
}
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/incomfort",
"iot_class": "local_polling",
"loggers": ["incomfortclient"],
"requirements": ["incomfort-client==0.6.2"]
"requirements": ["incomfort-client==0.6.3"]
}
@@ -28,5 +28,5 @@
"dependencies": ["bluetooth_adapters"],
"documentation": "https://www.home-assistant.io/integrations/inkbird",
"iot_class": "local_push",
"requirements": ["inkbird-ble==0.5.6"]
"requirements": ["inkbird-ble==0.5.8"]
}
+11 -15
View File
@@ -27,8 +27,6 @@ from homeassistant.const import (
CONF_METHOD,
CONF_NAME,
CONF_UNIQUE_ID,
EVENT_STATE_CHANGED,
EVENT_STATE_REPORTED,
STATE_UNAVAILABLE,
UnitOfTime,
)
@@ -45,7 +43,11 @@ from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.device import async_device_info_to_link_from_entity
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.event import (
async_call_later,
async_track_state_change_event,
async_track_state_report_event,
)
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import (
@@ -440,23 +442,17 @@ class IntegrationSensor(RestoreSensor):
self._derive_and_set_attributes_from_state(state)
self.async_on_remove(
self.hass.bus.async_listen(
EVENT_STATE_CHANGED,
async_track_state_change_event(
self.hass,
self._sensor_source_id,
handle_state_change,
event_filter=callback(
lambda event_data: event_data["entity_id"] == self._sensor_source_id
),
run_immediately=True,
)
)
self.async_on_remove(
self.hass.bus.async_listen(
EVENT_STATE_REPORTED,
async_track_state_report_event(
self.hass,
self._sensor_source_id,
handle_state_report,
event_filter=callback(
lambda event_data: event_data["entity_id"] == self._sensor_source_id
),
run_immediately=True,
)
)
@@ -8,6 +8,7 @@ from typing import Any
from pyecotrend_ista import KeycloakError, LoginError, PyEcotrendIsta, ServerError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
@@ -21,6 +22,8 @@ _LOGGER = logging.getLogger(__name__)
class IstaCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Ista EcoTrend data update coordinator."""
config_entry: ConfigEntry
def __init__(self, hass: HomeAssistant, ista: PyEcotrendIsta) -> None:
"""Initialize ista EcoTrend data update coordinator."""
super().__init__(
@@ -35,11 +38,14 @@ class IstaCoordinator(DataUpdateCoordinator[dict[str, Any]]):
async def _async_update_data(self):
"""Fetch ista EcoTrend data."""
if not self.details:
self.details = await self.async_get_details()
try:
await self.hass.async_add_executor_job(self.ista.login)
if not self.details:
self.details = await self.async_get_details()
return await self.hass.async_add_executor_job(self.get_consumption_data)
except ServerError as e:
raise UpdateFailed(
"Unable to connect and retrieve data from ista EcoTrend, try again later"
@@ -48,7 +54,9 @@ class IstaCoordinator(DataUpdateCoordinator[dict[str, Any]]):
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
translation_key="authentication_exception",
translation_placeholders={CONF_EMAIL: self.ista._email}, # noqa: SLF001
translation_placeholders={
CONF_EMAIL: self.config_entry.data[CONF_EMAIL]
},
) from e
def get_consumption_data(self) -> dict[str, Any]:
@@ -61,26 +69,16 @@ class IstaCoordinator(DataUpdateCoordinator[dict[str, Any]]):
async def async_get_details(self) -> dict[str, Any]:
"""Retrieve details of consumption units."""
try:
result = await self.hass.async_add_executor_job(
self.ista.get_consumption_unit_details
result = await self.hass.async_add_executor_job(
self.ista.get_consumption_unit_details
)
return {
consumption_unit: next(
details
for details in result["consumptionUnits"]
if details["id"] == consumption_unit
)
except ServerError as e:
raise UpdateFailed(
"Unable to connect and retrieve data from ista EcoTrend, try again later"
) from e
except (LoginError, KeycloakError) as e:
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
translation_key="authentication_exception",
translation_placeholders={CONF_EMAIL: self.ista._email}, # noqa: SLF001
) from e
else:
return {
consumption_unit: next(
details
for details in result["consumptionUnits"]
if details["id"] == consumption_unit
)
for consumption_unit in self.ista.get_uuids()
}
for consumption_unit in self.ista.get_uuids()
}
@@ -97,7 +97,11 @@ class JellyfinConfigFlow(ConfigFlow, domain=DOMAIN):
)
return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
step_id="user",
data_schema=self.add_suggested_values_to_schema(
STEP_USER_DATA_SCHEMA, user_input
),
errors=errors,
)
async def async_step_reauth(
@@ -28,7 +28,7 @@ class JewishCalendarEntity(Entity):
) -> None:
"""Initialize a Jewish Calendar entity."""
self.entity_description = description
self._attr_unique_id = f"{config_entry.entry_id}_{description.key}"
self._attr_unique_id = f"{config_entry.entry_id}-{description.key}"
self._attr_device_info = DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, config_entry.entry_id)},
@@ -4,7 +4,7 @@ from __future__ import annotations
from typing import Any
from knocki import KnockiClient, KnockiConnectionError
from knocki import KnockiClient, KnockiConnectionError, KnockiInvalidAuthError
import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
@@ -45,6 +45,8 @@ class KnockiConfigFlow(ConfigFlow, domain=DOMAIN):
raise
except KnockiConnectionError:
errors["base"] = "cannot_connect"
except KnockiInvalidAuthError:
errors["base"] = "invalid_auth"
except Exception: # noqa: BLE001
LOGGER.exception("Error logging into the Knocki API")
errors["base"] = "unknown"
+1
View File
@@ -48,6 +48,7 @@ class KnockiTrigger(EventEntity):
_attr_event_types = [EVENT_TRIGGERED]
_attr_has_entity_name = True
_attr_should_poll = False
_attr_translation_key = "knocki"
def __init__(self, trigger: Trigger, client: KnockiClient) -> None:
@@ -7,5 +7,5 @@
"integration_type": "device",
"iot_class": "cloud_push",
"loggers": ["knocki"],
"requirements": ["knocki==0.2.0"]
"requirements": ["knocki==0.3.1"]
}
@@ -641,12 +641,10 @@ class KodiEntity(MediaPlayerEntity):
if self.state == MediaPlayerState.OFF:
return state_attr
hdr_type = (
self._item.get("streamdetails", {}).get("video", [{}])[0].get("hdrtype")
)
if hdr_type == "":
state_attr["dynamic_range"] = "sdr"
else:
state_attr["dynamic_range"] = "sdr"
if (video_details := self._item.get("streamdetails", {}).get("video")) and (
hdr_type := video_details[0].get("hdrtype")
):
state_attr["dynamic_range"] = hdr_type
return state_attr
@@ -112,7 +112,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: LaMarzoccoConfigEntry) -
entry.runtime_data = coordinator
gateway_version = coordinator.device.firmware[FirmwareType.GATEWAY].current_version
if version.parse(gateway_version) < version.parse("v3.5-rc5"):
if version.parse(gateway_version) < version.parse("v3.4-rc5"):
# incompatible gateway firmware, create an issue
ir.async_create_issue(
hass,
@@ -9,6 +9,7 @@ from lmcloud.lm_machine import LaMarzoccoMachine
from lmcloud.models import LaMarzoccoMachineConfig
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@@ -105,6 +106,7 @@ class LaMarzoccoAutoOnOffSwitchEntity(LaMarzoccoBaseEntity, SwitchEntity):
super().__init__(coordinator, f"auto_on_off_{identifier}")
self._identifier = identifier
self._attr_translation_placeholders = {"id": identifier}
self.entity_category = EntityCategory.CONFIG
async def _async_enable(self, state: bool) -> None:
"""Enable or disable the auto on/off schedule."""
+2 -2
View File
@@ -1,7 +1,7 @@
{
"domain": "lifx",
"name": "LIFX",
"codeowners": [],
"codeowners": ["@Djelibeybi"],
"config_flow": true,
"dependencies": ["network"],
"dhcp": [
@@ -48,7 +48,7 @@
"iot_class": "local_polling",
"loggers": ["aiolifx", "aiolifx_effects", "bitstring"],
"requirements": [
"aiolifx==1.0.2",
"aiolifx==1.0.5",
"aiolifx-effects==0.3.2",
"aiolifx-themes==0.4.15"
]
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/local_calendar",
"iot_class": "local_polling",
"loggers": ["ical"],
"requirements": ["ical==8.0.1"]
"requirements": ["ical==8.1.1"]
}
@@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/local_todo",
"iot_class": "local_polling",
"requirements": ["ical==8.0.1"]
"requirements": ["ical==8.1.1"]
}
@@ -145,4 +145,20 @@ DISCOVERY_SCHEMAS = [
required_attributes=(clusters.BooleanState.Attributes.StateValue,),
device_type=(device_types.RainSensor,),
),
MatterDiscoverySchema(
platform=Platform.BINARY_SENSOR,
entity_description=MatterBinarySensorEntityDescription(
key="LockDoorStateSensor",
device_class=BinarySensorDeviceClass.DOOR,
# pylint: disable=unnecessary-lambda
measurement_to_ha=lambda x: {
clusters.DoorLock.Enums.DoorStateEnum.kDoorOpen: True,
clusters.DoorLock.Enums.DoorStateEnum.kDoorJammed: True,
clusters.DoorLock.Enums.DoorStateEnum.kDoorForcedOpen: True,
clusters.DoorLock.Enums.DoorStateEnum.kDoorClosed: False,
}.get(x),
),
entity_class=MatterBinarySensor,
required_attributes=(clusters.DoorLock.Attributes.DoorState,),
),
]
+26 -12
View File
@@ -60,6 +60,7 @@ SUPPORT_DRY_MODE_DEVICES: set[tuple[int, int]] = {
# In the list below specify tuples of (vendorid, productid) of devices that
# support dry mode.
(0x0001, 0x0108),
(0x0001, 0x010A),
(0x1209, 0x8007),
}
@@ -68,6 +69,7 @@ SUPPORT_FAN_MODE_DEVICES: set[tuple[int, int]] = {
# In the list below specify tuples of (vendorid, productid) of devices that
# support fan-only mode.
(0x0001, 0x0108),
(0x0001, 0x010A),
(0x1209, 0x8007),
}
@@ -225,6 +227,13 @@ class MatterClimate(MatterEntity, ClimateEntity):
self._attr_current_temperature = self._get_temperature_in_degrees(
clusters.Thermostat.Attributes.LocalTemperature
)
if self.get_matter_attribute_value(clusters.OnOff.Attributes.OnOff) is False:
# special case: the appliance has a dedicated Power switch on the OnOff cluster
# if the mains power is off - treat it as if the HVAC mode is off
self._attr_hvac_mode = HVACMode.OFF
self._attr_hvac_action = None
return
# update hvac_mode from SystemMode
system_mode_value = int(
self.get_matter_attribute_value(clusters.Thermostat.Attributes.SystemMode)
@@ -265,19 +274,13 @@ class MatterClimate(MatterEntity, ClimateEntity):
self._attr_hvac_action = HVACAction.FAN
case _:
self._attr_hvac_action = HVACAction.OFF
# update target_temperature
if self._attr_hvac_mode == HVACMode.HEAT_COOL:
self._attr_target_temperature = None
elif self._attr_hvac_mode == HVACMode.COOL:
self._attr_target_temperature = self._get_temperature_in_degrees(
clusters.Thermostat.Attributes.OccupiedCoolingSetpoint
)
else:
self._attr_target_temperature = self._get_temperature_in_degrees(
clusters.Thermostat.Attributes.OccupiedHeatingSetpoint
)
# update target temperature high/low
if self._attr_hvac_mode == HVACMode.HEAT_COOL:
supports_range = (
self._attr_supported_features
& ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)
if supports_range and self._attr_hvac_mode == HVACMode.HEAT_COOL:
self._attr_target_temperature = None
self._attr_target_temperature_high = self._get_temperature_in_degrees(
clusters.Thermostat.Attributes.OccupiedCoolingSetpoint
)
@@ -287,6 +290,16 @@ class MatterClimate(MatterEntity, ClimateEntity):
else:
self._attr_target_temperature_high = None
self._attr_target_temperature_low = None
# update target_temperature
if self._attr_hvac_mode == HVACMode.COOL:
self._attr_target_temperature = self._get_temperature_in_degrees(
clusters.Thermostat.Attributes.OccupiedCoolingSetpoint
)
else:
self._attr_target_temperature = self._get_temperature_in_degrees(
clusters.Thermostat.Attributes.OccupiedHeatingSetpoint
)
# update min_temp
if self._attr_hvac_mode == HVACMode.COOL:
attribute = clusters.Thermostat.Attributes.AbsMinCoolSetpointLimit
@@ -337,6 +350,7 @@ DISCOVERY_SCHEMAS = [
clusters.Thermostat.Attributes.TemperatureSetpointHold,
clusters.Thermostat.Attributes.UnoccupiedCoolingSetpoint,
clusters.Thermostat.Attributes.UnoccupiedHeatingSetpoint,
clusters.OnOff.Attributes.OnOff,
),
device_type=(device_types.Thermostat, device_types.RoomAirConditioner),
),
+16 -1
View File
@@ -170,6 +170,14 @@ class MatterFan(MatterEntity, FanEntity):
"""Update from device."""
if not hasattr(self, "_attr_preset_modes"):
self._calculate_features()
if self.get_matter_attribute_value(clusters.OnOff.Attributes.OnOff) is False:
# special case: the appliance has a dedicated Power switch on the OnOff cluster
# if the mains power is off - treat it as if the fan mode is off
self._attr_preset_mode = None
self._attr_percentage = 0
return
if self._attr_supported_features & FanEntityFeature.DIRECTION:
direction_value = self.get_matter_attribute_value(
clusters.FanControl.Attributes.AirflowDirection
@@ -200,7 +208,13 @@ class MatterFan(MatterEntity, FanEntity):
wind_setting = self.get_matter_attribute_value(
clusters.FanControl.Attributes.WindSetting
)
if (
fan_mode = self.get_matter_attribute_value(
clusters.FanControl.Attributes.FanMode
)
if fan_mode == clusters.FanControl.Enums.FanModeEnum.kOff:
self._attr_preset_mode = None
self._attr_percentage = 0
elif (
self._attr_preset_modes
and PRESET_NATURAL_WIND in self._attr_preset_modes
and wind_setting & WindBitmap.kNaturalWind
@@ -299,6 +313,7 @@ DISCOVERY_SCHEMAS = [
clusters.FanControl.Attributes.RockSetting,
clusters.FanControl.Attributes.WindSetting,
clusters.FanControl.Attributes.AirflowDirection,
clusters.OnOff.Attributes.OnOff,
),
),
]

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