Compare commits

...

329 Commits

Author SHA1 Message Date
farmio 73967ec3b8 override decorator 2026-06-23 22:25:28 +02:00
farmio 7e7c846c78 Remove unused logger 2026-06-23 22:24:47 +02:00
farmio 7ff7c45b18 improve typing 2026-06-23 22:24:47 +02:00
farmio 4481e90ee6 fix flaky tests 2026-06-23 22:24:47 +02:00
farmio 7670dcb227 store raw payload as hex string
this helps FE work with payloads >7byte
2026-06-23 22:24:47 +02:00
farmio db0f9d1f54 tests 2026-06-23 22:24:47 +02:00
farmio f1535bf8a4 Schema fixes 2026-06-23 22:24:47 +02:00
farmio c460100fa1 Validation 2026-06-23 22:24:46 +02:00
farmio 53e2a9341f Fix loading raw value 2026-06-23 22:24:46 +02:00
farmio 0e713d549c Rely on store validation 2026-06-23 22:24:46 +02:00
farmio a068574fe2 Add KNX button to UI configured entities 2026-06-23 22:24:46 +02:00
J. Nick Koston f57418ed60 Bump govee-ble to 1.4.0 (#174553) 2026-06-23 20:27:33 +02:00
Abílio Costa 8d1bf68045 Enable mypy explicit-override check (#171853)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-06-23 18:20:08 +01:00
Raphael Hehl c5bfad9bfe Remove UniFi LED (unifiled) integration (#168232)
Co-authored-by: RaHehl <rahehl@users.noreply.github.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-06-23 17:45:31 +02:00
Abílio Costa 679b0ac2aa Add agent instruction to prevent divider comments (#174531) 2026-06-23 16:41:43 +01:00
epenet 22a583c83f Migrate climate entity attributes to StrEnum (#174528) 2026-06-23 16:48:38 +02:00
epenet d966f71832 Migrate select entity attributes to StrEnum (#174536) 2026-06-23 16:44:47 +02:00
Manu 08569420f6 Remove Eliqonline integration (#174538) 2026-06-23 17:10:21 +03:00
Ronald van der Meer c1bcbca520 Add filter remaining days sensor to Duco (#174316) 2026-06-23 15:16:42 +02:00
Simone Chemelli c73c647162 Improve docstring for async_get_entity_id() method (#174532) 2026-06-23 14:50:34 +02:00
Markus Tuominen b2f1c38b6f Bump ouman-eh-800-api to 1.0.0 (#174458) 2026-06-23 14:45:19 +02:00
Erik Montnemery e8824bedf5 Add additional sun triggers (#174485) 2026-06-23 14:23:29 +02:00
Ajinkya Gokhale 27b107f4a5 Update energieleser to silver quality scale (#174535) 2026-06-23 14:23:06 +02:00
Petro31 7536e8647f Fix entities listed in template blueprints (#171861)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-23 13:35:20 +02:00
Simone Chemelli 75c6058396 Add "Drop in" select to Alexa Devices (#174336) 2026-06-23 10:47:44 +02:00
Matthias Alphart 77533e5af5 Rename "Advanced options" in KNX strings (#174523) 2026-06-23 10:27:11 +02:00
LG-ThinQ-Integration 31a1e7c5e1 Bump thinqconnect 1.0.13 (#174510)
Co-authored-by: YunseonPark-LGE <yunseon.park@lge.com>
2026-06-23 09:55:33 +02:00
renovate[bot] 20f4e7306b Update pytest-unordered to 0.8.0 (#174515) 2026-06-23 09:15:35 +02:00
Mick Vleeshouwer 5c1ac08c92 Catch connection errors when executing Overkiz commands (#174453) 2026-06-23 08:51:36 +02:00
Franck Nijhof 5631c68069 Reword trigger descriptions for presence and detection entities (#174467) 2026-06-23 08:51:14 +02:00
Franck Nijhof 8648611278 Clarify the media player play media action name (#174480) 2026-06-23 08:49:04 +02:00
Franck Nijhof 971d15be1e Improve trigger wording for lawn mower and vacuum entities (#174477)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2026-06-23 08:48:45 +02:00
Åke Strandberg b6f2429ff3 Bump pyaqvify to 0.0.12 (#174516) 2026-06-23 08:35:13 +02:00
Jacob Hurwitz c676e2a806 Bump python-dropbox-api to 0.1.4 (#174512) 2026-06-23 07:22:21 +02:00
Robert Resch a27ea536db Enable aw check requirements on each deps PR (#174481) 2026-06-23 02:14:03 +02:00
Erwin Douna 22e25d9ce2 MELCloud Home exand sensor state behavior (#174495) 2026-06-23 00:44:14 +02:00
Nikhil Deepak 1cb5e31901 Pass keep_alive parameter to Ollama AI Task calls (#165410)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-23 00:16:56 +02:00
Thijs W. 4f414d0035 Fix duplicate-configuration edge-case in Frontier Silicon config flow (#172916) 2026-06-23 00:11:51 +02:00
Franck Nijhof 30b648ea6a Bump holidays to 0.99 (#174501) 2026-06-23 00:10:33 +02:00
fdebrus 18a259718f Vistapool: add reauthentication flow (#172825)
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-23 00:09:33 +02:00
fdebrus 45de0f4b4a Add select platform to Vistapool (#172547)
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-23 00:08:14 +02:00
Erwin Douna 940bf5bf09 Portainer fix type narrowing (#173040) 2026-06-23 00:07:34 +02:00
starkillerOG 07e78b6dbf Bump reolink-aio to 0.21.2 (#174497) 2026-06-23 00:06:47 +02:00
Franck Nijhof abcb677b57 Bump SQLAlchemy to 2.0.51 (#174499) 2026-06-22 23:59:00 +02:00
Ermanno Baschiera 7e638f9d0c Bump Helty Flow to silver quality scale (#173132)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 23:57:21 +02:00
Thomas D 8aca6115f4 Trigger location update on certain events for the Volvo integration (#172651)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 23:53:42 +02:00
Oscar Calvo dd688986f1 Add CCM15 swing control (#173793)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 23:51:53 +02:00
Branden Cash c519b7ba07 Populate hourly statistics in srp_energy (#167371)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Signed-off-by: Branden Cash <203336+ammmze@users.noreply.github.com>
2026-06-22 23:51:33 +02:00
Pete Sage 158595464a Cancel timers for Sonos on shutdown/reload (#172830) 2026-06-22 23:47:27 +02:00
Franck Nijhof f81aff0a69 Remove runtime_data dependency from SIA options flow (#174489) 2026-06-22 23:43:46 +02:00
Arie Catsman 9f90e6ec22 Bump pyenphase to v3.0.0 (#174496) 2026-06-23 00:41:23 +03:00
Simone Chemelli 31b311e17a Improve availability of notify enttities for Alexa Devices (#174220)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 23:37:27 +02:00
Manu 7e07f2ab87 Add notify entities to Notifications for Android TV / Fire TV (#169087) 2026-06-22 23:36:45 +02:00
Przemko92 312f4c8c35 Add new values for Compit climate (#174238)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 23:29:01 +02:00
Brett Adams ddeeba5f87 Bump Splunk to silver quality scale (#174236)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 23:20:16 +02:00
Przemko92 82a043bc47 Add new values for Compit sensor (#174240) 2026-06-22 23:17:32 +02:00
Alain 629b9a5f9b SwitchBot cloud fix webhook handling (#169141)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 23:16:22 +02:00
tacopiek 9400c2e40e Add energy_today sensor to LG ThinQ (#172983)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:16:07 +02:00
epenet 8a57bb0640 Refactor thermopro tests to avoid thermopro_sensor.async_setup_entry (#173880) 2026-06-22 23:14:39 +02:00
Chris ab8f1bf88e Add OpenEVSE button platform (#172964) 2026-06-22 23:14:27 +02:00
Erwin Douna b61ad539d9 MELCloud Home add frost and overheat protection (#174224) 2026-06-22 23:13:57 +02:00
Franck Nijhof 283dcee830 Fix Rachio calendar error when no events are scheduled (#173624) 2026-06-22 23:13:02 +02:00
Franck Nijhof e61a3ac684 Bump pyAtome to 0.1.2 (#173902) 2026-06-22 23:11:31 +02:00
Franck Nijhof 5595ba12fb Bump kiwiki-client to 0.1.2 (#173903)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-22 23:09:51 +02:00
Mick Vleeshouwer 1bfd4d1500 Handle ApplicationNotAllowedError in Overkiz cloud config flow (#174498) 2026-06-22 23:03:51 +02:00
Manu 249c3bb5dd Refactor sensor platform of Steam integration (#174415) 2026-06-22 22:59:42 +02:00
Ariel Ebersberger 982fe7a370 Use value comparison for value-based enums (#174494) 2026-06-22 22:44:26 +02:00
EnjoyingM 035e7e0a38 Wolflink Shared and multidevice hub support (#172795)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 22:40:14 +02:00
J. Nick Koston f6b0036ccc Bump zeroconf to 0.150.0 (#174484) 2026-06-22 22:29:17 +02:00
Denis Shulyaka b2a26afb14 Promote Anthropic IQS to Gold (#170268) 2026-06-22 22:20:39 +02:00
Mick Vleeshouwer 231470f4dc Configure RTS command duration on the Overkiz client (#174448) 2026-06-22 22:04:11 +02:00
Erwin Douna 8aeb5d63ab MELCloud Home add icon for holiday mode (#174459) 2026-06-22 22:02:10 +02:00
some-random-climber d613591463 Use service helper in Picnic (#174271) 2026-06-22 21:59:34 +02:00
Abílio Costa dc6269f52d Add override decorator to remaining homeassistant dir files (#174488) 2026-06-22 21:56:03 +02:00
some-random-climber 31690ac2d3 Use service helper in Volvo (#174267) 2026-06-22 21:54:54 +02:00
Tim Laing ffe008c6b2 Fix iCloud auth bug (#173816) 2026-06-22 21:52:47 +02:00
Raphael Hehl dc48c3e30f Fix UniFi Protect package detection via public events websocket (#173733) 2026-06-22 14:45:20 -05:00
Jonathan Swoboda 448fd04137 Convert epoch to datetime for ESPHome uptime sensor device class (#174223) 2026-06-22 21:30:31 +02:00
AlCalzone 41e7837bcf Set openSenseMap to bronze on the quality scale (#173864)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 21:29:59 +02:00
Mattie 951062fa82 Add SG Ready select entity to Qube heat pump (#170114)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 21:29:25 +02:00
Allen Porter f2ac5a4153 Support Roborock dynamic devices and simplify startup error handling (#173704) 2026-06-22 21:27:29 +02:00
Franck Nijhof 12832fe3cd Remove invalid state_class from System Monitor battery_empty sensor (#174487) 2026-06-22 21:09:46 +02:00
some-random-climber d35e58fdc7 Move service registration to async_setup in cloudflare (#174131) 2026-06-22 20:56:48 +02:00
smartcircuits 3570cd0ee3 Add reauthentication flow to WattWächter Plus (#174281)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:56:22 +02:00
Brett Adams 5a99cb4cca Fix Teslemetry rear seat heater entity availability (#174248)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-22 20:54:55 +02:00
Abílio Costa d49a9c4780 Add override decorator to components S to T (#174483) 2026-06-22 20:52:27 +02:00
Abílio Costa c330a983e4 Add override decorator to components U to Z (#174482) 2026-06-22 20:51:13 +02:00
Legendberg e47f58362a Add per-day sleep schedule entities for Litter-Robot 5 (#173569)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
2026-06-22 20:48:51 +02:00
Franck Nijhof 18f5998162 Improve trigger wording for button, event, and helper entities (#174472)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2026-06-22 20:46:09 +02:00
Paul Bottein e41d9d5447 Standardize constants across entity platforms (#174446) 2026-06-22 20:44:15 +02:00
Michael Hansen 9509bcb8e3 Forward intent response text to ESPHome voice satellite (#174452) 2026-06-22 20:43:04 +02:00
Erwin Douna eb50acfc26 MELCloud Home add icon state behavior (#174461) 2026-06-22 20:42:27 +02:00
Franck Nijhof 3a880644bc Fix Rainforest RAVEn sensor returning string None as state (#174295) 2026-06-22 20:38:27 +02:00
Franck Nijhof 0a39eb3f5d Improve trigger and condition wording for scene, select, and to-do list entities (#174473) 2026-06-22 19:37:46 +01:00
Erik Montnemery 91f4168439 Simplify sun entity (#174464)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2026-06-22 20:29:59 +02:00
Franck Nijhof e1c8f3da78 Improve trigger and condition wording for media player entities (#174474) 2026-06-22 19:27:32 +01:00
Franck Nijhof c868f760d5 Reword trigger descriptions for Assist, alarm, calendar, and update entities (#174475) 2026-06-22 19:23:26 +01:00
Abílio Costa 8965e2241e Add override decorator to components P to R (#174478) 2026-06-22 20:21:39 +02:00
Franck Nijhof b17e86d45c Improve zone trigger and condition wording (#174476) 2026-06-22 19:21:01 +01:00
Abílio Costa 91e70bcc1a Add override decorator to components N to O (#174479) 2026-06-22 20:20:21 +02:00
Franck Nijhof 11f86f30ac Reword trigger descriptions for air quality entities (#174471) 2026-06-22 19:19:39 +01:00
Franck Nijhof 75c490139d Reword trigger descriptions for climate entities (#174469) 2026-06-22 19:14:05 +01:00
Franck Nijhof 4ccd854225 Improve trigger and condition wording for numeric sensor entities (#174470) 2026-06-22 19:13:26 +01:00
galo2099 b7fbbf5a1f Handle stale Tesla Fleet energy sites (#170278)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-22 20:13:15 +02:00
Franck Nijhof 5e05f6f845 Reword trigger descriptions for lights, switches, and output entities (#174468) 2026-06-22 19:12:32 +01:00
Franck Nijhof 294d1cb726 Reword trigger descriptions for opening and closing entities (#174466) 2026-06-22 19:11:49 +01:00
Crocmagnon 7074c291a0 Bump data_grand_lyon_ha to v0.9.0 (#174286) 2026-06-22 20:02:47 +02:00
Franck Nijhof 8bf668186d Cast OpenTherm Gateway device info fields to string (#174290) 2026-06-22 20:02:13 +02:00
Yardian Support 1d02788001 Fix a standby binary sensor bug in yardian (#174341)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 20:01:45 +02:00
Axelwin 3cc975aae3 Add V2G charge states to Renault charge_state sensor (#173463)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-06-22 20:00:47 +02:00
some-random-climber 28294dfdfc Use service helper in Sonarr (#174273) 2026-06-22 19:37:28 +02:00
Abílio Costa b2aa1c1b8d Add override decorator to components J to M (#174465) 2026-06-22 19:35:53 +02:00
Abílio Costa fa13cedf83 Add override decorator to components H to I (#174462) 2026-06-22 19:21:49 +02:00
Abílio Costa 0b7e2fa28b Add override decorator to components F to G (#172136) 2026-06-22 19:21:29 +02:00
Franck Nijhof 7edcbff62c Rename entity trigger and condition keys for consistency (#174463) 2026-06-22 19:19:44 +02:00
Abílio Costa aeb020c60f Add override decorator to components C to E (#172085) 2026-06-22 19:17:40 +02:00
Moura 9c2914d03a nx584: update bypassed zone attribute from events (#174353)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 19:16:37 +02:00
Léon 980d3c28fd Add To-do list platform to Alexa Devices (#171136)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Simone Chemelli <simone.chemelli@gmail.com>
2026-06-22 18:22:41 +02:00
Michael a7fb69cf3e Add fan speed mode control to Synology DSM (#173051)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-06-22 18:06:45 +02:00
TheJulianJES b24791fa71 Remove unused hass.data[DOMAIN] from Thread integration (#168863) 2026-06-22 17:59:25 +02:00
Erik Montnemery b6b8391cbf Remove purpose-specific triggers and conditions from labs (#174450) 2026-06-22 16:58:51 +01:00
Erik Montnemery dad7da0e3b Remove sun helper cache (#174457) 2026-06-22 17:58:47 +02:00
Lukas 87cdf3a0e3 Virtual intgration BWT (SEKO pooldose) (#174311) 2026-06-22 17:47:46 +02:00
Willem-Jan van Rootselaar 634980b53f Bump python-bsblan to 6.1.3 (#172843) 2026-06-22 17:44:39 +02:00
Paul Bottein e244b7f2b6 Add config switches to Yoto (#173973)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-22 17:43:05 +02:00
Marc Hörsken 761f1f8a0e Use pytest fixture parametrization instead of duplicate fixtures (#174304)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-22 17:41:27 +02:00
MarkGodwin a51c653797 Allow multiple sites for same TP-Link Omada controller (#168535) 2026-06-22 17:41:18 +02:00
David Bayer af6ae63eeb Fix blink 2fa auth flow (#174356) 2026-06-22 17:29:18 +02:00
Tom 11b49607bd Add airOS (insecure ssl) support for legacy v6 devices (#172954) 2026-06-22 17:21:03 +02:00
Erwin Douna 956e26196a MELCloud Home add Holiday mode sensors (#174454) 2026-06-22 17:08:31 +02:00
Abílio Costa 3946162140 Add override decorator to components A to B (#172081) 2026-06-22 15:14:48 +01:00
Clément Notin c3f7a1d5b0 [Daikin] Specify time period for consumption sensors (#174395) 2026-06-22 15:34:35 +02:00
Åke Strandberg c9a6502c16 Add a coordinator for slow polling and add new sensors to aqvify (#174075) 2026-06-22 15:30:20 +02:00
Hai-Nam Nguyen 708d5b46e8 Add Nexen virtual integration (#173594) 2026-06-22 14:41:32 +02:00
Eduard Reñé Claramunt 49bd80541c Add @edurenye as SAJ codeowner (#174438) 2026-06-22 13:45:03 +02:00
tronikos a8c42222a3 Bump opower to 0.18.6 (#174430) 2026-06-22 13:30:00 +02:00
Eduard Reñé Claramunt 7e805f2f2a Allow SAJ Solar Inverter to be configured through the UI (#160052)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-06-22 12:40:28 +02:00
Erwin Douna 7e684dbcca Bump aiomelcloudhome to 0.1.9 (#174413) 2026-06-22 12:34:20 +02:00
Markus Tuominen cdd063083d Add entity-unique-id-redundant-domain pylint check (#173434)
Co-authored-by: Ariel Ebersberger <ariel@ebersberger.io>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-22 12:33:38 +02:00
Jordan Harvey 1e4e77465a Bump pyanglianwater to 3.2.2 (#174433) 2026-06-22 12:24:55 +02:00
Erik Montnemery 16671e29d8 Trigger add did not trigger callback (#174116) 2026-06-22 10:54:16 +02:00
Mick Vleeshouwer b8dc091a21 Normalize Overkiz RTS tilt command arguments (#174297) 2026-06-22 09:38:50 +02:00
Manu 66afd77a96 Improve config flow strings in Steam integration (#174418) 2026-06-22 09:28:45 +02:00
tronikos 134519e97f Add fan timer timeout timestamp sensor to Nest integration (#174330)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-22 09:22:04 +02:00
Fabian Munkes c1957f2f35 Bump music-assistant-client to 1.3.6 (#174345)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2026-06-22 08:43:14 +02:00
Peter Grauvogel 89e2b2b9fc Adjust Green Planet Energy service wording (#174406) 2026-06-22 08:05:09 +02:00
Mick Vleeshouwer 9a1f40280b Retry Overkiz setup on transient server unavailable errors (#174411) 2026-06-22 08:04:58 +02:00
Manu 1518aaa82d Bump steamodd to 5.0 (#174421) 2026-06-22 08:04:24 +02:00
Manu 6dd60a3723 Remove tikteck integration (#174423) 2026-06-22 08:03:31 +02:00
Matthias Alphart c6b4d5c7c3 Update xknx to 3.16.0 (#174312) 2026-06-22 06:10:59 +02:00
Paulus Schoutsen d782cd8289 Fix singleton leaving a dangling Event when wrapped coroutine raises (#174400)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 23:26:44 -04:00
Paulus Schoutsen 2f633193e9 Fix flaky KNX sensor validation test (#174396)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 23:24:50 -04:00
Raphael Hehl 5ada338f13 Source UniFi Protect UP-Sense battery from the public API (#174229)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-06-21 15:52:44 -05:00
Raphael Hehl 5e6085f961 Source UniFi Protect camera streams from the public API (#174369) 2026-06-21 15:44:26 -05:00
Paulus Schoutsen 8198aa263b Lazy load repairs platforms (#174374)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 15:08:30 -05:00
Paulus Schoutsen 2abe5d23f4 Lazily load cast integration platforms (#174373)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 15:07:48 -05:00
Paulus Schoutsen e8428ea639 Formalize deprecation of system_health.async_register_info (#174352)
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-21 14:53:25 -05:00
Paulus Schoutsen 81f7e53dfa Fix flaky test_thread_fails_raise (#174398)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 14:48:57 -05:00
RDFurman 151fd1409f Remove rdfurman from honeywell codeowners (#174401) 2026-06-21 14:15:15 -04:00
Mick Vleeshouwer 690fb22c11 Add tests for the Overkiz binary sensor platform (#174402) 2026-06-21 14:14:41 -04:00
Mick Vleeshouwer 395c02ddb4 Update pyoverkiz to 2.0.2 (#174403) 2026-06-21 14:13:18 -04:00
Chase 78f903d0f6 Migrate jsonpath to jsonpath-python dependencies (#174364)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-21 12:54:31 -04:00
renovate[bot] ea7ccae927 Update infrared-protocols to 6.3.0 (#174326) 2026-06-21 18:01:48 +02:00
Alistair Francis 2008551cc9 husqvarna_automower_ble: Update to use automower-ble 0.2.9 (#174384)
Signed-off-by: Alistair Francis <alistair@alistair23.me>
2026-06-21 11:20:27 -04:00
Bert 2b7cd9295a Bump pymodbus to 3.13.1 (#174332) 2026-06-21 11:17:54 -04:00
Franck Nijhof a4131e128c Merge branch 'master' into dev 2026-06-21 14:20:23 +00:00
Mick Vleeshouwer 05ec46906c Add fan platform to Overkiz (#174362) 2026-06-21 13:36:08 +02:00
Franck Nijhof 06aa380e09 Fix Tesla Fleet/Teslemetry cable lock showing unlocked when data unavailable (#174287) 2026-06-21 12:20:04 +02:00
Raphael Hehl 758c6c62b2 Bump uiprotect to 14.0.0 (#174381) 2026-06-21 12:10:53 +02:00
Fabian Munkes 27d229b161 Fix an incompatible type arg in config flow of Music Assistant (#174380) 2026-06-21 10:33:01 +02:00
Alistair Francis 010b789026 husqvarna_automower_ble: Improve error logging and handle TimeOuts (#174343) 2026-06-21 07:56:50 +02:00
Mick Vleeshouwer ee1d378574 Fix UndefinedType._singleton leaking into Overkiz sub-device entity names (#174360) 2026-06-21 07:49:47 +02:00
Mick Vleeshouwer 324f08d00f Add separate battery sensors for Overkiz smoke sensors (#174365) 2026-06-21 07:48:08 +02:00
Yardian Support 957c24fcd7 Bump pyyardian to 1.4.1 (#174347) 2026-06-20 19:36:14 -04:00
MarkGodwin 97dbd59750 Bump tplink-omada-client to 1.5.8 to fix #170082 (#174350) 2026-06-20 19:35:30 -04:00
Przemysław Szypowicz 16c7ec30b0 Bump pyatv to 0.18.0 (#174354)
Co-authored-by: Przemysław Szypowicz <2733699+pszypowicz@users.noreply.github.com>
2026-06-20 19:29:05 -04:00
Joost Lekkerkerker bd4cdeb510 Add new Withings MAC range (#174366) 2026-06-20 19:27:29 -04:00
Maciej Bieniek ac1f82d130 Bump brother to 6.1.1 (#174368) 2026-06-20 19:27:05 -04:00
Joost Lekkerkerker a9393d777e Add vacuum room support to Google Assistant (#164617)
Co-authored-by: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com>
2026-06-20 21:26:25 +02:00
Raphael Hehl d28827a4f2 Bump uiprotect to 13.5.1 (#174355) 2026-06-20 13:11:25 -05:00
Franck Nijhof 7e62ff35fd 2026.6.4 (#174308) 2026-06-19 22:57:25 +02:00
TheJulianJES 0a5c1ef8eb Bump dsmr-parser to 1.9.0 (#174307) 2026-06-19 18:59:16 +00:00
Michael a88093afd2 Bump aioimmich to 0.15.0 (#174305) 2026-06-19 18:55:13 +00:00
J. Nick Koston 9fd90283b3 Bump pyroute2 to 0.9.6 (#172521) 2026-06-19 18:55:11 +00:00
Franck Nijhof 3159242b68 Bump version to 2026.6.4 2026-06-19 18:26:51 +00:00
Simone Chemelli f5985b03e4 Remove event entities from virtual groups for Alexa Devices (#174303) 2026-06-19 18:25:53 +00:00
Franck Nijhof 040a3bcb10 Cast Xiaomi Gateway sub-device firmware version to string (#174294) 2026-06-19 18:25:52 +00:00
Bram Kragten 5aaf6704a9 Update frontend to 20260527.7 (#174285) 2026-06-19 18:25:50 +00:00
Franck Nijhof 2fcd00b301 Fix econet fan mode select returning int instead of str (#174274) 2026-06-19 18:25:48 +00:00
Franck Nijhof 0b439e6e4c Re-raise non-401 HTTP errors in Tank Utility setup (#174272) 2026-06-19 18:25:46 +00:00
Franck Nijhof d13a5b7eec Handle Weheat API errors during config flow entry creation (#174234) 2026-06-19 18:25:45 +00:00
Franck Nijhof de49716ec1 Skip fill sensor for Rituals diffusers without fill data (#174232) 2026-06-19 18:25:43 +00:00
Franck Nijhof 67c6921847 Include Sonos favorites in source list and gate SELECT_SOURCE dynamically (#174231) 2026-06-19 18:25:41 +00:00
Franck Nijhof 002b638013 Fix Elk-M1 reconfigure failing when entry has no unique_id (#174230) 2026-06-19 18:25:39 +00:00
Josef Zweck 4b60ed30c7 Update max prebrew numbers in lamarzocco (#174204) 2026-06-19 18:25:37 +00:00
Simone Chemelli 6f1deec507 Bump aiocomelit to 2.0.7 (#174183) 2026-06-19 18:25:35 +00:00
Franck Nijhof 227ba8032f Bump aiocomelit to 2.0.5 (#173800) 2026-06-19 18:25:34 +00:00
Bernát Gábor 7da3ecf033 Cast SwitchBot Cloud device sw_version to string (#174167) 2026-06-19 18:14:20 +00:00
Simone Chemelli 8b293a18d3 Bump aioamazondevices to 14.1.3 (#174158) 2026-06-19 18:14:18 +00:00
Simone Chemelli 3dc077f280 Fix stale routine entities removal for Alexa Devices (#174138) 2026-06-19 18:14:16 +00:00
Simone Chemelli d368a95323 Bump aioamazondevices to 14.1.2 (#174114)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2026-06-19 18:14:14 +00:00
Franck Nijhof 495f41a742 Filter out closed sites in Amber Electric config flow (#174084) 2026-06-19 18:12:01 +00:00
Franck Nijhof 9f7529706d Cast system version to string for simplisafe device model (#174081) 2026-06-19 18:11:59 +00:00
Franck Nijhof 8f6b1dff9c Bump opower to 0.18.5 (#174080) 2026-06-19 18:11:58 +00:00
Franck Nijhof f260a1bb7b Retry webdav setup on connection errors (#174077) 2026-06-19 18:11:56 +00:00
Franck Nijhof 157e137ea9 Cast numeric firmware to string for squeezebox hw_version (#174076) 2026-06-19 18:11:54 +00:00
Jan Bouwhuis b2e1a296d4 Fix MQTT discovery option unjustly added to entry data (#174073) 2026-06-19 18:11:52 +00:00
Franck Nijhof e78a2c9f01 Add missing subentry flow translations in scrape (#174006) 2026-06-19 18:11:50 +00:00
Franck Nijhof 9011225a42 Add missing flow form field translations in tractive (#174005) 2026-06-19 18:11:48 +00:00
Franck Nijhof 81ef9b99c2 Add missing flow form field translation in iskra (#174004) 2026-06-19 18:11:46 +00:00
Franck Nijhof fa0207698a Add missing flow form field translations in ecobee (#174002) 2026-06-19 18:11:44 +00:00
Franck Nijhof 275883a95a Add missing flow form field translation in airvisual (#174000) 2026-06-19 18:11:42 +00:00
Franck Nijhof ebd252a225 Fix flow form field translations in modem_callerid (#173999) 2026-06-19 18:11:40 +00:00
Franck Nijhof 2de6c0281d Fix flow form field translation key in sia (#173998) 2026-06-19 18:11:38 +00:00
Franck Nijhof f95671f0f4 Fix flow form field translations in local_calendar (#173997) 2026-06-19 18:11:36 +00:00
Franck Nijhof 5fcae9ecf7 Add missing flow form field translation in honeywell (#173996) 2026-06-19 18:11:35 +00:00
Franck Nijhof 0b86cfa496 Add missing flow form field translation in otp (#173994) 2026-06-19 18:11:33 +00:00
Franck Nijhof d45bdf37d5 Fix flow form field translations in hlk_sw16 (#173993) 2026-06-19 18:11:31 +00:00
Franck Nijhof a9205df4a3 Fix flow form field translation keys in here_travel_time (#173992) 2026-06-19 18:11:29 +00:00
John Pettitt c333744fd2 Add API_GEN_4 support to Subaru integration (#173956) 2026-06-19 18:11:27 +00:00
Assaf Inbal 2f64601990 Bump pyituran to 0.1.6 (#173833) 2026-06-19 18:11:25 +00:00
Franck Nijhof cbd35be271 Bump pyrainbird to 6.3.1 (#173786) 2026-06-19 18:07:34 +00:00
Franck Nijhof 92ac14f42a Bump aioamazondevices to 14.0.4 (#173761) 2026-06-19 18:07:32 +00:00
Franck Nijhof 45e568c73e Add missing flow form field translation in snooz (#173760) 2026-06-19 18:07:30 +00:00
Franck Nijhof a121b8d146 Add missing flow form field translation in motionblinds_ble (#173758) 2026-06-19 18:07:28 +00:00
Franck Nijhof a2bd7d5857 Add missing flow form field translation in blink (#173756) 2026-06-19 18:07:26 +00:00
Franck Nijhof a6e639377b Fix options flow form field translation key in plaato (#173755) 2026-06-19 18:07:24 +00:00
Franck Nijhof 2147a851c3 Fix flow form field translation key in meteoclimatic (#173754) 2026-06-19 18:07:22 +00:00
Franck Nijhof 9034afd29e Add missing flow form field translation in gogogate2 (#173753) 2026-06-19 18:07:20 +00:00
Franck Nijhof 5c5d259f63 Add missing flow form field translation in melnor (#173752) 2026-06-19 18:07:18 +00:00
Franck Nijhof cc16a9086f Fix flow form field translation key in lookin (#173751) 2026-06-19 18:07:16 +00:00
Franck Nijhof 5d1f8f770c Add missing flow form field translation in lacrosse_view (#173750) 2026-06-19 18:07:14 +00:00
Franck Nijhof cea6b9b0b7 Add missing flow form field translations in islamic_prayer_times (#173749) 2026-06-19 18:07:12 +00:00
G Johansson 77f7c26399 Bump lxml to 6.1.1 (#173748) 2026-06-19 18:07:10 +00:00
Franck Nijhof 8e0a5b258c Add missing flow form field translation in hue (#173747) 2026-06-19 18:07:08 +00:00
Franck Nijhof f8b942818c Add missing flow form field translation in flux_led (#173746) 2026-06-19 18:07:06 +00:00
Franck Nijhof 9660d12c77 Add missing flow form field translation in tuya (#173745) 2026-06-19 18:07:04 +00:00
Franck Nijhof 7f1533a6e1 Skip Miele fan set_percentage when already at the target step (#173725) 2026-06-19 18:07:02 +00:00
J. Nick Koston 336d9e9126 Bump aiodiscover to 3.3.2 (#173705) 2026-06-19 18:07:00 +00:00
J. Nick Koston 1dde2d918e Bump aiodiscover to 3.3.1 (#172882) 2026-06-19 18:06:58 +00:00
Åke Strandberg 34a6b0ca61 Add missing Miele dishwasher codes (#173662) 2026-06-19 17:50:28 +00:00
Raman Gupta e92286ecd6 Stop validating # of slots in zwave_js.set_credential action (#173644) 2026-06-19 17:50:26 +00:00
Franck Nijhof 82bb9748db Avoid leaking Immich API key in error logs (#173541) 2026-06-19 17:50:24 +00:00
Rob Bierbooms 68e5e58a1c Solve issue with double slash in url when writing data to InfluxDB (#173395) 2026-06-19 17:50:22 +00:00
johanzander f3e8403e9a Fix Growatt total_output_power 1000x too low with V1 API (#172474)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-19 17:50:20 +00:00
Franck Nijhof 28076bcad6 2026.6.3 (#173633) 2026-06-12 21:49:56 +02:00
Franck Nijhof ff25428e56 Fix undefined DOMAIN in image upload tests 2026-06-12 19:12:56 +00:00
Franck Nijhof 608acd422f Bump version to 2026.6.3 2026-06-12 18:33:03 +00:00
Franck Nijhof c860e83ec9 Disambiguate duplicate channel names in LG Netcast source list (#173560) 2026-06-12 18:32:03 +00:00
Franck Nijhof c9f3f4a265 Sort aliases in LLM prompts for stable prefix caching (#173558) 2026-06-12 18:32:01 +00:00
Franck Nijhof e346a801d1 Return enum values from config_entry_attr template function (#173554) 2026-06-12 18:31:59 +00:00
Franck Nijhof a5c193931f Fix Rituals Perfume Genie sw_version dict passed to device registry (#173552) 2026-06-12 18:31:57 +00:00
Franck Nijhof d273350db1 Suppress InsecureKeyLengthWarning in HTML5 push notifications (#173551) 2026-06-12 18:31:55 +00:00
Franck Nijhof 45f27b8b6e Fix Yale Smart Living panic button unique_id for multiple hubs (#173547) 2026-06-12 18:31:53 +00:00
Franck Nijhof d3208a420f Convert OpenGarage sw_version to string for device registry (#173546) 2026-06-12 18:31:51 +00:00
Franck Nijhof d0d35e380f Convert RainMachine hw_version to string for device registry (#173545) 2026-06-12 18:31:49 +00:00
Franck Nijhof 2735e58d7f Convert JPEG-incompatible image modes to RGB in image upload thumbnail generation (#173538) 2026-06-12 18:31:47 +00:00
Franck Nijhof ad3eab80c3 Fix iCloud RuntimeError on unload by running cancel in executor (#173537) 2026-06-12 18:31:45 +00:00
Franck Nijhof 18e5d284b4 Fix Hue grouped light icon by adding translation_key (#173536) 2026-06-12 18:31:43 +00:00
Franck Nijhof e5052eaf44 Fix Hue light level sensor crash on None value (#173532) 2026-06-12 18:31:41 +00:00
Ernst Klamer 62c2e8d2fd Bump bthome-ble to 3.23.4 (#173526) 2026-06-12 18:31:39 +00:00
Bram Kragten 1f505067dd Update frontend to 20260527.6 (#173522) 2026-06-12 18:31:37 +00:00
Stefan Agner 72875b3b5e Refresh preferred Thread border agent address on OTBR reconnect (#173508)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: puddly <32534428+puddly@users.noreply.github.com>
2026-06-12 18:31:35 +00:00
renovate[bot] 3be755e496 Update hassil to 3.7.0 (#173484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-12 18:31:33 +00:00
Michael Hansen 5285798052 Bump hassil to 3.6.0 (#173031) 2026-06-12 18:31:31 +00:00
Diogo Gomes da49e37946 Bump pytrydan to 1.0.2 (#173479) 2026-06-12 18:28:13 +00:00
Simone Chemelli 2f9de98f2d Bump aioamazondevices to 14.0.3 (#173478) 2026-06-12 18:28:09 +00:00
starkillerOG 383a6426fc Bump reolink_aio to 0.21.0 (#173477) 2026-06-12 18:28:06 +00:00
Robert Resch 5ed60cd057 Revert "Unify query token auth in http views" (#173466) 2026-06-12 18:28:04 +00:00
Tom Cassady a1250b7bfb Fix UniFi Protect ufp_set debug log printing UndefinedType for translation-key entities (#173460) 2026-06-12 18:28:02 +00:00
Simone Chemelli 240e5219ad Redact more fields in diagnostics for Alexa devices (#173446) 2026-06-12 18:28:00 +00:00
Simone Chemelli 418f352ce7 Change update interval for UptimeRobot (#173435) 2026-06-12 18:27:58 +00:00
Jan Bouwhuis 599967b1d8 Do not enable MQTT entities though discovery that were disabled by user (#173404) 2026-06-12 18:27:56 +00:00
Nikolai Rahimi ad82729357 Add debug logging for Mitsubishi Comfort polling failures (#173364) 2026-06-12 18:27:54 +00:00
Franck Nijhof 30d8bf4231 2026.6.2 (#173397) 2026-06-09 22:13:22 +02:00
Triggs 5436d8af9b Bump codecov/codecov-action from v6.0.1 to v7.0.0 (#173232)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2026-06-09 19:26:01 +00:00
epenet 88adf39ef3 Use explicit DOMAIN import in mqtt tests (#173093) 2026-06-09 19:20:12 +00:00
Franck Nijhof 14b14bddf1 Bump version to 2026.6.2 2026-06-09 18:41:21 +00:00
Michael Hansen 3c4a30be6b Only allow specific protocols with ffmpeg in Wyoming satellite announce (#173381)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-09 18:34:34 +00:00
Joost Lekkerkerker 2988eb4b19 Set Zinvolt max output to 2kW if unlocked (#173367) 2026-06-09 18:34:32 +00:00
Nikolai Rahimi 00eef14558 Bump mitsubishi-comfort to 0.3.1 (#173362) 2026-06-09 18:34:30 +00:00
Joost Lekkerkerker d02516dd09 Handle unavailable Zinvolt devices better (#173359) 2026-06-09 18:34:28 +00:00
Jan Bouwhuis aabb6b3d04 Fix reload fails when MQTT entry is not set up (#173335)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
2026-06-09 18:34:26 +00:00
tronikos 50c2c7c4bc Bump opower to 0.18.4 (#173323) 2026-06-09 18:34:24 +00:00
Joakim Plate e81dd426bb Ensure we provide strings to vol.In for philips js (#173313) 2026-06-09 18:34:22 +00:00
Michael Hansen c4c569c181 Mitigate TTS ResultStream leak in pipeline (#173290) 2026-06-09 18:34:20 +00:00
Simone Chemelli 6182426132 Bump renault-api to 0.5.12 (#173289) 2026-06-09 18:34:18 +00:00
Martin Hjelmare a073cc4f7d Fix homeassistant hardware unique id migration (#173258) 2026-06-09 18:34:16 +00:00
Mark Purcell 07ddc08d84 Bump pydaikin to 2.18.1 (#173249) 2026-06-09 18:34:14 +00:00
Bram Kragten 17673dcf55 Update frontend to 20260527.5 (#173236) 2026-06-09 18:34:12 +00:00
starkillerOG a864bc1c80 Adjust ONVIF event fallbacks for battery cameras (#173214)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-09 18:34:10 +00:00
Shay Levy a15d80daa2 Fix Shelly virtual component unit retrieval (#173183) 2026-06-09 18:34:08 +00:00
Joost Lekkerkerker e123b29258 Have Plugwise handle unavailable temperature measurements (#173173) 2026-06-09 18:34:06 +00:00
J. Nick Koston 5669a7b602 Wait for Shelly bluetooth proxy connection at startup (#173165) 2026-06-09 18:34:05 +00:00
J. Nick Koston fe358a4a1f Wait for ESPHome bluetooth proxy connection at startup (#173164) 2026-06-09 18:34:03 +00:00
mvn23 3a93d6370b Ensure opentherm_gw boiler and thermostat manufacturers are strings (#173162) 2026-06-09 18:34:01 +00:00
Bouwe Westerdijk 89576f01e6 Bump plugwise to v1.11.4 (#173147) 2026-06-09 18:33:59 +00:00
tronikos f51895b0c9 Bump opower to 0.18.3 (#173141) 2026-06-09 18:30:18 +00:00
Joakim Plate d0dcbfadaa Switch to active scanner for gardena (#173062) 2026-06-09 18:30:16 +00:00
Simone Chemelli 5e0d3627c2 Improve and complete exception handling for Alexa Devices (#173053) 2026-06-09 18:30:14 +00:00
Diogo Gomes 80c90732a3 Bump pytrydan to v1.0.1 (#173047) 2026-06-09 18:30:12 +00:00
Yardian Support 16eca3909a Bump pyyardian to 1.4.0 (#173020)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-09 18:30:10 +00:00
peteS-UK 1b471da31f Update PARALLEL_UPDATES to 0 for Squeezebox platforms (#172906) 2026-06-09 18:30:08 +00:00
Franck Nijhof 7391209f48 2026.6.1 (#173122) 2026-06-05 22:25:21 +02:00
Franck Nijhof 0683344079 Bump version to 2026.6.1 2026-06-05 18:02:28 +00:00
Joakim Plate 0b77cf9e4b Fix process advertisement for active scans (#173116) 2026-06-05 18:02:10 +00:00
Noah Husby e0a87d966d Bump aiostreammagic to 2.13.2 (#173114) 2026-06-05 18:02:08 +00:00
Paul Bottein af53d2d082 Bump yoto-api to 3.1.6 (#173104) 2026-06-05 18:02:06 +00:00
Joost Lekkerkerker da7fa80e75 Bump pySmartThings to 4.0.1 (#173092) 2026-06-05 18:02:04 +00:00
Robert Resch 6cf1e7fb48 Bump wheels to 2026.06.0 (#173089) 2026-06-05 18:02:02 +00:00
Jan Bouwhuis 18fa0ac47d Create certificate files before trying to migrate the MQTT config entry (#173087)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-05 18:01:59 +00:00
Robert Resch 4afced1a49 Unify query token auth in http views (#173082) 2026-06-05 18:01:57 +00:00
Ronald van der Meer 74a4471160 Fix Duco mode end time sensor name (#173045) 2026-06-05 18:01:55 +00:00
Franck Nijhof 857a3de066 Convert LinkPlay configuration_url to string for device registry (#173034) 2026-06-05 18:01:53 +00:00
Erwin Douna 06bf2ff6de Portainer extend timeout for disk space coordinator (#173032) 2026-06-05 18:01:51 +00:00
G Johansson 6a5dae9cc3 Bump holidays to 0.98 (#173029) 2026-06-05 18:01:49 +00:00
Erik Montnemery 475ebbc028 Fix person in_zones propagation from scanner in home zone (#173007) 2026-06-05 18:01:47 +00:00
Maciej Bieniek 6e7643e997 Bump imgw_pib to 2.2.2 (#172999) 2026-06-05 18:01:45 +00:00
Erik Montnemery 1f954cda0d Improve person tests (#172997) 2026-06-05 18:01:43 +00:00
Jan Bouwhuis 2961fca1b1 Fix value template in MQTT Fan and Siren subentry setup (#172980) 2026-06-05 18:01:41 +00:00
Abílio Costa 106b189206 Bump idasen-ha to 2.7.0 (#172962) 2026-06-05 18:01:39 +00:00
Nikolai Rahimi 0387034f4e Fix Mitsubishi Comfort devices skipped due to unresolved local address (#172959) 2026-06-05 18:01:37 +00:00
starkillerOG f81b6abca9 Add more Reolink diagnostic info (#172945) 2026-06-05 18:01:35 +00:00
Thomas55555 43f6e7977e Bump aioautomower to 2.7.6 (#172937) 2026-06-05 18:01:33 +00:00
Samuel Xiao 706fea4ec5 Switchbot Cloud: Fixed an issue where condition filtering for enabled Webhooks was abnormal (#172903) 2026-06-05 18:01:32 +00:00
Kurt Chrisford 74d23503e7 Bump actron-neo-api to 0.5.12 (#172902) 2026-06-05 18:01:30 +00:00
rjones-gentex 4ca5da2365 Upgrade HomeLink package, set integration type (#172371) 2026-06-05 17:50:58 +00:00
Eric Stern 53c77ae2ef Fix SleepIQ 401 storm by isolating client session cookies (#172276) 2026-06-05 17:50:56 +00:00
bk86a 14968f9d67 Fix Lyric sensor crash when next_period_time is None (#167831)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-05 17:50:54 +00:00
5813 changed files with 54370 additions and 15009 deletions
+1
View File
@@ -53,3 +53,4 @@ This repository contains the core of Home Assistant, a Python 3 based home autom
- When validation guarantees a dict key exists, prefer direct key access (`data["key"]`) instead of `.get("key")` so contract violations are surfaced instead of silently masked.
- Keep comments concise. Prefer one short line stating the non-obvious constraint, or no comment at all.
- Do not add comments that just restate the code on the following line(s) (e.g. `# Check if initialized` above `if self.initialized:`). Comments should only explain why (non-obvious constraints, surprising behavior, or workarounds), never what. Never add comments that justify a change by referencing what the code looked like before.
- Do not add section or divider comments (e.g. `# --- XYZ Triggers ---`) inside or outside of functions, since those can easily become stale and be misleading.
@@ -8,15 +8,11 @@ name: Check requirements (deterministic)
# yamllint disable-line rule:truthy
on:
# Auto-trigger on PRs that touch tracked requirement files is disabled
# for now while we iterate — testing the workflow_run handoff to the
# agentic stage is hard with an auto-trigger. Re-enable once the chain
# has been validated end-to-end.
# pull_request:
# types: [opened, synchronize, reopened]
# paths:
# - "**/requirements*.txt"
# - "homeassistant/package_constraints.txt"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "requirements*.txt"
- "homeassistant/package_constraints.txt"
workflow_dispatch:
inputs:
pull_request_number:
+1
View File
@@ -42,3 +42,4 @@ This repository contains the core of Home Assistant, a Python 3 based home autom
- When validation guarantees a dict key exists, prefer direct key access (`data["key"]`) instead of `.get("key")` so contract violations are surfaced instead of silently masked.
- Keep comments concise. Prefer one short line stating the non-obvious constraint, or no comment at all.
- Do not add comments that just restate the code on the following line(s) (e.g. `# Check if initialized` above `if self.initialized:`). Comments should only explain why (non-obvious constraints, surprising behavior, or workarounds), never what. Never add comments that justify a change by referencing what the code looked like before.
- Do not add section or divider comments (e.g. `# --- XYZ Triggers ---`) inside or outside of functions, since those can easily become stale and be misleading.
Generated
+6 -6
View File
@@ -781,8 +781,8 @@ CLAUDE.md @home-assistant/core
/tests/components/homevolt/ @danielhiversen @liudger
/homeassistant/components/homewizard/ @DCSBL
/tests/components/homewizard/ @DCSBL
/homeassistant/components/honeywell/ @rdfurman @mkmer
/tests/components/honeywell/ @rdfurman @mkmer
/homeassistant/components/honeywell/ @mkmer
/tests/components/honeywell/ @mkmer
/homeassistant/components/honeywell_string_lights/ @balloob
/tests/components/honeywell_string_lights/ @balloob
/homeassistant/components/hr_energy_qube/ @MattieGit
@@ -1558,7 +1558,8 @@ CLAUDE.md @home-assistant/core
/tests/components/rympro/ @OnFreund @elad-bar @maorcc
/homeassistant/components/sabnzbd/ @shaiu @jpbede
/tests/components/sabnzbd/ @shaiu @jpbede
/homeassistant/components/saj/ @fredericvl
/homeassistant/components/saj/ @fredericvl @edurenye
/tests/components/saj/ @fredericvl @edurenye
/homeassistant/components/samsung_infrared/ @lmaertin
/tests/components/samsung_infrared/ @lmaertin
/homeassistant/components/samsungtv/ @chemelli74
@@ -1711,8 +1712,8 @@ CLAUDE.md @home-assistant/core
/tests/components/sql/ @gjohansson-ST @dougiteixeira
/homeassistant/components/squeezebox/ @rajlaud @pssc @peteS-UK
/tests/components/squeezebox/ @rajlaud @pssc @peteS-UK
/homeassistant/components/srp_energy/ @briglx
/tests/components/srp_energy/ @briglx
/homeassistant/components/srp_energy/ @briglx @ammmze
/tests/components/srp_energy/ @briglx @ammmze
/homeassistant/components/starline/ @anonym-tsk
/tests/components/starline/ @anonym-tsk
/homeassistant/components/statistics/ @ThomDietrich @gjohansson-ST
@@ -1899,7 +1900,6 @@ CLAUDE.md @home-assistant/core
/tests/components/unifi_direct/ @tofuSCHNITZEL
/homeassistant/components/unifi_discovery/ @RaHehl
/tests/components/unifi_discovery/ @RaHehl
/homeassistant/components/unifiled/ @florisvdk
/homeassistant/components/unifiprotect/ @RaHehl
/tests/components/unifiprotect/ @RaHehl
/homeassistant/components/upb/ @gwww
+3 -1
View File
@@ -6,7 +6,7 @@ from collections.abc import Mapping
from datetime import datetime, timedelta
from functools import partial
import time
from typing import Any, cast
from typing import Any, cast, override
import jwt
@@ -109,6 +109,7 @@ class AuthManagerFlowManager(
super().__init__(hass)
self.auth_manager = auth_manager
@override
async def async_create_flow(
self,
handler_key: tuple[str, str],
@@ -122,6 +123,7 @@ class AuthManagerFlowManager(
raise KeyError(f"Unknown auth provider {handler_key}")
return await auth_provider.async_login_flow(context)
@override
async def async_finish_flow(
self,
flow: FlowHandler[AuthFlowContext, AuthFlowResult, tuple[str, str]],
+1
View File
@@ -39,6 +39,7 @@ class _PyJWSWithLoadCache(PyJWS):
# We only ever have a global instance of this class
# so we do not have to worry about the LRU growing
# each time we create a new instance.
@override
def _load(self, jwt: str | bytes) -> tuple[bytes, bytes, dict, bytes]:
"""Load a JWS."""
return super()._load(jwt)
@@ -1,6 +1,6 @@
"""Example auth module."""
from typing import Any
from typing import Any, override
import voluptuous as vol
@@ -35,6 +35,7 @@ class InsecureExampleModule(MultiFactorAuthModule):
self._data = config["data"]
@property
@override
def input_schema(self) -> vol.Schema:
"""Validate login flow input data."""
return vol.Schema({vol.Required("pin"): str})
@@ -44,6 +45,7 @@ class InsecureExampleModule(MultiFactorAuthModule):
"""Validate async_setup_user input data."""
return vol.Schema({vol.Required("pin"): str})
@override
async def async_setup_flow(self, user_id: str) -> SetupFlow:
"""Return a data entry flow handler for setup module.
@@ -51,6 +53,7 @@ class InsecureExampleModule(MultiFactorAuthModule):
"""
return SetupFlow(self, self.setup_schema, user_id)
@override
async def async_setup_user(self, user_id: str, setup_data: Any) -> Any:
"""Set up user to use mfa module."""
# data shall has been validate in caller
@@ -64,6 +67,7 @@ class InsecureExampleModule(MultiFactorAuthModule):
self._data.append({"user_id": user_id, "pin": pin})
@override
async def async_depose_user(self, user_id: str) -> None:
"""Remove user from mfa module."""
found = None
@@ -74,10 +78,12 @@ class InsecureExampleModule(MultiFactorAuthModule):
if found:
self._data.remove(found)
@override
async def async_is_user_setup(self, user_id: str) -> bool:
"""Return whether user is setup."""
return any(data["user_id"] == user_id for data in self._data)
@override
async def async_validate(self, user_id: str, user_input: dict[str, Any]) -> bool:
"""Return True if validation passed."""
return any(
+8 -1
View File
@@ -5,7 +5,7 @@ Sending HOTP through notify service
import asyncio
import logging
from typing import Any, cast
from typing import Any, cast, override
import attr
import voluptuous as vol
@@ -107,6 +107,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
self._init_lock = asyncio.Lock()
@property
@override
def input_schema(self) -> vol.Schema:
"""Validate login flow input data."""
return vol.Schema({vol.Required(INPUT_FIELD_CODE): str})
@@ -159,6 +160,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
return sorted(unordered_services)
@override
async def async_setup_flow(self, user_id: str) -> NotifySetupFlow:
"""Return a data entry flow handler for setup module.
@@ -168,6 +170,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
self, self.input_schema, user_id, self.aync_get_available_notify_services()
)
@override
async def async_setup_user(self, user_id: str, setup_data: Any) -> Any:
"""Set up auth module for user."""
if self._user_settings is None:
@@ -181,6 +184,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
await self._async_save()
@override
async def async_depose_user(self, user_id: str) -> None:
"""Depose auth module for user."""
if self._user_settings is None:
@@ -190,6 +194,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
if self._user_settings.pop(user_id, None):
await self._async_save()
@override
async def async_is_user_setup(self, user_id: str) -> bool:
"""Return whether user is setup."""
if self._user_settings is None:
@@ -198,6 +203,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
return user_id in self._user_settings
@override
async def async_validate(self, user_id: str, user_input: dict[str, Any]) -> bool:
"""Return True if validation passed."""
if self._user_settings is None:
@@ -283,6 +289,7 @@ class NotifySetupFlow(SetupFlow[NotifyAuthModule]):
self._notify_service: str | None = None
self._target: str | None = None
@override
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> FlowResult:
+8 -1
View File
@@ -2,7 +2,7 @@
import asyncio
from io import BytesIO
from typing import Any, cast
from typing import Any, cast, override
import voluptuous as vol
@@ -87,6 +87,7 @@ class TotpAuthModule(MultiFactorAuthModule):
self._init_lock = asyncio.Lock()
@property
@override
def input_schema(self) -> vol.Schema:
"""Validate login flow input data."""
return vol.Schema({vol.Required(INPUT_FIELD_CODE): str})
@@ -115,6 +116,7 @@ class TotpAuthModule(MultiFactorAuthModule):
self._users[user_id] = ota_secret # type: ignore[index]
return ota_secret
@override
async def async_setup_flow(self, user_id: str) -> TotpSetupFlow:
"""Return a data entry flow handler for setup module.
@@ -124,6 +126,7 @@ class TotpAuthModule(MultiFactorAuthModule):
assert user is not None
return TotpSetupFlow(self, self.input_schema, user)
@override
async def async_setup_user(self, user_id: str, setup_data: Any) -> str:
"""Set up auth module for user."""
if self._users is None:
@@ -136,6 +139,7 @@ class TotpAuthModule(MultiFactorAuthModule):
await self._async_save()
return result
@override
async def async_depose_user(self, user_id: str) -> None:
"""Depose auth module for user."""
if self._users is None:
@@ -144,6 +148,7 @@ class TotpAuthModule(MultiFactorAuthModule):
if self._users.pop(user_id, None): # type: ignore[union-attr]
await self._async_save()
@override
async def async_is_user_setup(self, user_id: str) -> bool:
"""Return whether user is setup."""
if self._users is None:
@@ -151,6 +156,7 @@ class TotpAuthModule(MultiFactorAuthModule):
return user_id in self._users # type: ignore[operator]
@override
async def async_validate(self, user_id: str, user_input: dict[str, Any]) -> bool:
"""Return True if validation passed."""
if self._users is None:
@@ -189,6 +195,7 @@ class TotpSetupFlow(SetupFlow[TotpAuthModule]):
super().__init__(auth_module, setup_schema, user.id)
self._user = user
@override
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> FlowResult:
+6 -1
View File
@@ -1,7 +1,7 @@
"""Permissions for Home Assistant."""
from collections.abc import Callable, Iterable
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, override
import voluptuous as vol
@@ -68,14 +68,17 @@ class PolicyPermissions(AbstractPermissions):
self._policy = policy
self._perm_lookup = perm_lookup
@override
def access_all_entities(self, key: str) -> bool:
"""Check if we have a certain access to all entities."""
return test_all(self._policy.get(CAT_ENTITIES), key)
@override
def _entity_func(self) -> Callable[[str, str], bool]:
"""Return a function that can test entity access."""
return compile_entities(self._policy.get(CAT_ENTITIES), self._perm_lookup)
@override
def __eq__(self, other: object) -> bool:
"""Equals check."""
return isinstance(other, PolicyPermissions) and other._policy == self._policy
@@ -84,10 +87,12 @@ class PolicyPermissions(AbstractPermissions):
class _OwnerPermissions(AbstractPermissions):
"""Owner permissions."""
@override
def access_all_entities(self, key: str) -> bool:
"""Check if we have a certain access to all entities."""
return True
@override
def _entity_func(self) -> Callable[[str, str], bool]:
"""Return a function that can test entity access."""
return lambda entity_id, key: True
+5 -1
View File
@@ -4,7 +4,7 @@ import asyncio
from collections.abc import Mapping
import logging
import os
from typing import Any
from typing import Any, override
import voluptuous as vol
@@ -57,6 +57,7 @@ class CommandLineAuthProvider(AuthProvider):
super().__init__(*args, **kwargs)
self._user_meta: dict[str, dict[str, Any]] = {}
@override
async def async_login_flow(
self, context: AuthFlowContext | None
) -> CommandLineLoginFlow:
@@ -105,6 +106,7 @@ class CommandLineAuthProvider(AuthProvider):
meta[key] = value
self._user_meta[username] = meta
@override
async def async_get_or_create_credentials(
self, flow_result: Mapping[str, str]
) -> Credentials:
@@ -117,6 +119,7 @@ class CommandLineAuthProvider(AuthProvider):
# Create new credentials.
return self.async_create_credentials({"username": username})
@override
async def async_user_meta_for_credentials(
self, credentials: Credentials
) -> UserMeta:
@@ -136,6 +139,7 @@ class CommandLineAuthProvider(AuthProvider):
class CommandLineLoginFlow(LoginFlow[CommandLineAuthProvider]):
"""Handler for the login flow."""
@override
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> AuthFlowResult:
@@ -4,7 +4,7 @@ import asyncio
import base64
from collections.abc import Mapping
import logging
from typing import Any, cast
from typing import Any, cast, override
import bcrypt
import voluptuous as vol
@@ -302,6 +302,7 @@ class HassAuthProvider(AuthProvider):
self.data: Data | None = None
self._init_lock = asyncio.Lock()
@override
async def async_initialize(self) -> None:
"""Initialize the auth provider."""
async with self._init_lock:
@@ -312,6 +313,7 @@ class HassAuthProvider(AuthProvider):
await data.async_load()
self.data = data
@override
async def async_login_flow(self, context: AuthFlowContext | None) -> HassLoginFlow:
"""Return a flow to login."""
return HassLoginFlow(self)
@@ -369,6 +371,7 @@ class HassAuthProvider(AuthProvider):
)
await self.data.async_save()
@override
async def async_get_or_create_credentials(
self, flow_result: Mapping[str, str]
) -> Credentials:
@@ -387,6 +390,7 @@ class HassAuthProvider(AuthProvider):
# Create new credentials.
return self.async_create_credentials({"username": username})
@override
async def async_user_meta_for_credentials(
self, credentials: Credentials
) -> UserMeta:
@@ -410,6 +414,7 @@ class HassAuthProvider(AuthProvider):
class HassLoginFlow(LoginFlow[HassAuthProvider]):
"""Handler for the login flow."""
@override
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> AuthFlowResult:
@@ -2,6 +2,7 @@
from collections.abc import Mapping
import hmac
from typing import override
import voluptuous as vol
@@ -33,6 +34,7 @@ class InvalidAuthError(HomeAssistantError):
class ExampleAuthProvider(AuthProvider):
"""Example auth provider based on hardcoded usernames and passwords."""
@override
async def async_login_flow(
self, context: AuthFlowContext | None
) -> ExampleLoginFlow:
@@ -61,6 +63,7 @@ class ExampleAuthProvider(AuthProvider):
):
raise InvalidAuthError
@override
async def async_get_or_create_credentials(
self, flow_result: Mapping[str, str]
) -> Credentials:
@@ -74,6 +77,7 @@ class ExampleAuthProvider(AuthProvider):
# Create new credentials.
return self.async_create_credentials({"username": username})
@override
async def async_user_meta_for_credentials(
self, credentials: Credentials
) -> UserMeta:
@@ -95,6 +99,7 @@ class ExampleAuthProvider(AuthProvider):
class ExampleLoginFlow(LoginFlow[ExampleAuthProvider]):
"""Handler for the login flow."""
@override
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> AuthFlowResult:
@@ -13,7 +13,7 @@ from ipaddress import (
ip_address,
ip_network,
)
from typing import Any, cast
from typing import Any, cast, override
import voluptuous as vol
@@ -98,10 +98,12 @@ class TrustedNetworksAuthProvider(AuthProvider):
]
@property
@override
def support_mfa(self) -> bool:
"""Trusted Networks auth provider does not support MFA."""
return False
@override
async def async_login_flow(
self, context: AuthFlowContext | None
) -> TrustedNetworksLoginFlow:
@@ -144,6 +146,7 @@ class TrustedNetworksAuthProvider(AuthProvider):
self.config[CONF_ALLOW_BYPASS_LOGIN],
)
@override
async def async_get_or_create_credentials(
self, flow_result: Mapping[str, str]
) -> Credentials:
@@ -172,6 +175,7 @@ class TrustedNetworksAuthProvider(AuthProvider):
# We only allow login as exist user
raise InvalidUserError
@override
async def async_user_meta_for_credentials(
self, credentials: Credentials
) -> UserMeta:
@@ -203,6 +207,7 @@ class TrustedNetworksAuthProvider(AuthProvider):
raise InvalidAuthError("Can't allow access from Home Assistant Cloud")
@callback
@override
def async_validate_refresh_token(
self, refresh_token: RefreshToken, remote_ip: str | None = None
) -> None:
@@ -230,6 +235,7 @@ class TrustedNetworksLoginFlow(LoginFlow[TrustedNetworksAuthProvider]):
self._ip_address = ip_addr
self._allow_bypass_login = allow_bypass_login
@override
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> AuthFlowResult:
+2 -1
View File
@@ -14,7 +14,7 @@ import platform
import sys
import threading
from time import monotonic
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
# Import cryptography early since import openssl is not thread-safe
# _frozen_importlib._DeadlockError: deadlock detected by
@@ -697,6 +697,7 @@ def _create_log_file(
class _RotatingFileHandlerWithoutShouldRollOver(RotatingFileHandler):
"""RotatingFileHandler that does not check if it should roll over on every log."""
@override
def shouldRollover(self, record: logging.LogRecord) -> bool:
"""Never roll over.
-1
View File
@@ -7,7 +7,6 @@
"unifi_access",
"unifi_direct",
"unifi_discovery",
"unifiled",
"unifiprotect"
]
}
@@ -1,5 +1,7 @@
"""Support for Abode Security System alarm control panels."""
from typing import override
from jaraco.abode.devices.alarm import Alarm
from homeassistant.components.alarm_control_panel import (
@@ -38,6 +40,7 @@ class AbodeAlarm(AbodeDevice, AlarmControlPanelEntity):
_device: Alarm
@property
@override
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
if self._device.is_standby:
@@ -48,19 +51,23 @@ class AbodeAlarm(AbodeDevice, AlarmControlPanelEntity):
return AlarmControlPanelState.ARMED_HOME
return None
@override
def alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
self._device.set_standby()
@override
def alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
self._device.set_home()
@override
def alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
self._device.set_away()
@property
@override
def extra_state_attributes(self) -> dict[str, str]:
"""Return the state attributes."""
return {
@@ -1,6 +1,6 @@
"""Support for Abode Security System binary sensors."""
from typing import cast
from typing import cast, override
from jaraco.abode.devices.binary_sensor import BinarySensor
@@ -45,11 +45,13 @@ class AbodeBinarySensor(AbodeDevice, BinarySensorEntity):
_device: BinarySensor
@property
@override
def is_on(self) -> bool:
"""Return True if the binary sensor is on."""
return cast(bool, self._device.is_on)
@property
@override
def device_class(self) -> BinarySensorDeviceClass | None:
"""Return the class of the binary sensor."""
if self._device.get_value("is_window") == "1":
+6 -1
View File
@@ -1,7 +1,7 @@
"""Support for Abode Security System cameras."""
from datetime import timedelta
from typing import Any, cast
from typing import Any, cast, override
from jaraco.abode.devices.base import Device
from jaraco.abode.devices.camera import Camera as AbodeCam
@@ -49,6 +49,7 @@ class AbodeCamera(AbodeDevice, Camera):
self._event = event
self._response: Response | None = None
@override
async def async_added_to_hass(self) -> None:
"""Subscribe Abode events."""
await super().async_added_to_hass()
@@ -87,6 +88,7 @@ class AbodeCamera(AbodeDevice, Camera):
else:
self._response = None
@override
def camera_image(
self, width: int | None = None, height: int | None = None
) -> bytes | None:
@@ -98,10 +100,12 @@ class AbodeCamera(AbodeDevice, Camera):
return None
@override
def turn_on(self) -> None:
"""Turn on camera."""
self._device.privacy_mode(False)
@override
def turn_off(self) -> None:
"""Turn off camera."""
self._device.privacy_mode(True)
@@ -113,6 +117,7 @@ class AbodeCamera(AbodeDevice, Camera):
self.schedule_update_ha_state()
@property
@override
def is_on(self) -> bool:
"""Return true if on."""
return cast(bool, self._device.is_on)
@@ -2,7 +2,7 @@
from collections.abc import Mapping
from http import HTTPStatus
from typing import Any, cast
from typing import Any, cast, override
from jaraco.abode.client import Client as Abode
from jaraco.abode.exceptions import (
@@ -106,6 +106,7 @@ class AbodeFlowHandler(ConfigFlow, domain=DOMAIN):
title=cast(str, self._username), data=config_data
)
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
+4 -1
View File
@@ -1,6 +1,6 @@
"""Support for Abode Security System covers."""
from typing import Any
from typing import Any, override
from jaraco.abode.devices.cover import Cover
@@ -33,14 +33,17 @@ class AbodeCover(AbodeDevice, CoverEntity):
_attr_name = None
@property
@override
def is_closed(self) -> bool:
"""Return true if cover is closed, else False."""
return not self._device.is_open
@override
def close_cover(self, **kwargs: Any) -> None:
"""Issue close command to cover."""
self._device.close_cover()
@override
def open_cover(self, **kwargs: Any) -> None:
"""Issue open command to cover."""
self._device.open_cover()
+8
View File
@@ -1,5 +1,7 @@
"""Support for Abode Security System entities."""
from typing import override
from jaraco.abode.automation import Automation as AbodeAuto
from jaraco.abode.devices.base import Device as AbodeDev
@@ -21,6 +23,7 @@ class AbodeEntity(Entity):
self._data = data
self._attr_should_poll = data.polling
@override
async def async_added_to_hass(self) -> None:
"""Subscribe to Abode connection status updates."""
await self.hass.async_add_executor_job(
@@ -31,6 +34,7 @@ class AbodeEntity(Entity):
self._data.entity_ids.add(self.entity_id)
@override
async def async_will_remove_from_hass(self) -> None:
"""Unsubscribe from Abode connection status updates."""
await self.hass.async_add_executor_job(
@@ -52,6 +56,7 @@ class AbodeDevice(AbodeEntity):
self._device = device
self._attr_unique_id = device.uuid
@override
async def async_added_to_hass(self) -> None:
"""Subscribe to device events."""
await super().async_added_to_hass()
@@ -61,6 +66,7 @@ class AbodeDevice(AbodeEntity):
self._update_callback,
)
@override
async def async_will_remove_from_hass(self) -> None:
"""Unsubscribe from device events."""
await super().async_will_remove_from_hass()
@@ -73,6 +79,7 @@ class AbodeDevice(AbodeEntity):
self._device.refresh()
@property
@override
def extra_state_attributes(self) -> dict[str, str]:
"""Return the state attributes."""
return {
@@ -83,6 +90,7 @@ class AbodeDevice(AbodeEntity):
}
@property
@override
def device_info(self) -> DeviceInfo:
"""Return device registry information for this entity."""
return DeviceInfo(
+9 -1
View File
@@ -1,7 +1,7 @@
"""Support for Abode Security System lights."""
from math import ceil
from typing import Any
from typing import Any, override
from jaraco.abode.devices.light import Light
@@ -43,6 +43,7 @@ class AbodeLight(AbodeDevice, LightEntity):
_attr_max_color_temp_kelvin = DEFAULT_MAX_KELVIN
_attr_min_color_temp_kelvin = DEFAULT_MIN_KELVIN
@override
def turn_on(self, **kwargs: Any) -> None:
"""Turn on the light."""
if ATTR_COLOR_TEMP_KELVIN in kwargs and self._device.is_color_capable:
@@ -61,16 +62,19 @@ class AbodeLight(AbodeDevice, LightEntity):
self._device.switch_on()
@override
def turn_off(self, **kwargs: Any) -> None:
"""Turn off the light."""
self._device.switch_off()
@property
@override
def is_on(self) -> bool:
"""Return true if device is on."""
return bool(self._device.is_on)
@property
@override
def brightness(self) -> int | None:
"""Return the brightness of the light."""
if self._device.is_dimmable and self._device.has_brightness:
@@ -81,6 +85,7 @@ class AbodeLight(AbodeDevice, LightEntity):
return None
@property
@override
def color_temp_kelvin(self) -> int | None:
"""Return the color temp of the light."""
if self._device.has_color:
@@ -88,6 +93,7 @@ class AbodeLight(AbodeDevice, LightEntity):
return None
@property
@override
def hs_color(self) -> tuple[float, float] | None:
"""Return the color of the light."""
_hs = None
@@ -96,6 +102,7 @@ class AbodeLight(AbodeDevice, LightEntity):
return _hs
@property
@override
def color_mode(self) -> ColorMode:
"""Return the color mode of the light."""
if self._device.is_dimmable and self._device.is_color_capable:
@@ -107,6 +114,7 @@ class AbodeLight(AbodeDevice, LightEntity):
return ColorMode.ONOFF
@property
@override
def supported_color_modes(self) -> set[ColorMode]:
"""Flag supported color modes."""
if self._device.is_dimmable and self._device.is_color_capable:
+4 -1
View File
@@ -1,6 +1,6 @@
"""Support for the Abode Security System locks."""
from typing import Any
from typing import Any, override
from jaraco.abode.devices.lock import Lock
@@ -32,15 +32,18 @@ class AbodeLock(AbodeDevice, LockEntity):
_device: Lock
_attr_name = None
@override
def lock(self, **kwargs: Any) -> None:
"""Lock the device."""
self._device.lock()
@override
def unlock(self, **kwargs: Any) -> None:
"""Unlock the device."""
self._device.unlock()
@property
@override
def is_locked(self) -> bool:
"""Return true if device is on."""
return bool(self._device.is_locked)
+3 -1
View File
@@ -2,7 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import cast
from typing import cast, override
from jaraco.abode.devices.sensor import Sensor
@@ -94,11 +94,13 @@ class AbodeSensor(AbodeDevice, SensorEntity):
self._attr_unique_id = f"{device.uuid}-{description.key}"
@property
@override
def native_value(self) -> float:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self._device)
@property
@override
def native_unit_of_measurement(self) -> str:
"""Return the native unit of measurement."""
return self.entity_description.native_unit_of_measurement_fn(self._device)
+8 -1
View File
@@ -1,6 +1,6 @@
"""Support for Abode Security System switches."""
from typing import Any, cast
from typing import Any, cast, override
from jaraco.abode.devices.switch import Switch
@@ -43,15 +43,18 @@ class AbodeSwitch(AbodeDevice, SwitchEntity):
_device: Switch
_attr_name = None
@override
def turn_on(self, **kwargs: Any) -> None:
"""Turn on the device."""
self._device.switch_on()
@override
def turn_off(self, **kwargs: Any) -> None:
"""Turn off the device."""
self._device.switch_off()
@property
@override
def is_on(self) -> bool:
"""Return true if device is on."""
return cast(bool, self._device.is_on)
@@ -62,6 +65,7 @@ class AbodeAutomationSwitch(AbodeAutomation, SwitchEntity):
_attr_translation_key = "automation"
@override
async def async_added_to_hass(self) -> None:
"""Set up trigger automation service."""
await super().async_added_to_hass()
@@ -69,11 +73,13 @@ class AbodeAutomationSwitch(AbodeAutomation, SwitchEntity):
signal = f"abode_trigger_automation_{self.entity_id}"
self.async_on_remove(async_dispatcher_connect(self.hass, signal, self.trigger))
@override
def turn_on(self, **kwargs: Any) -> None:
"""Enable the automation."""
if self._automation.enable(True):
self.schedule_update_ha_state()
@override
def turn_off(self, **kwargs: Any) -> None:
"""Disable the automation."""
if self._automation.enable(False):
@@ -84,6 +90,7 @@ class AbodeAutomationSwitch(AbodeAutomation, SwitchEntity):
self._automation.trigger()
@property
@override
def is_on(self) -> bool:
"""Return True if the automation is enabled."""
return bool(self._automation.enabled)
@@ -2,6 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import override
from aioacaia.acaiascale import AcaiaScale
@@ -56,6 +57,7 @@ class AcaiaBinarySensor(AcaiaEntity, BinarySensorEntity):
entity_description: AcaiaBinarySensorEntityDescription
@property
@override
def is_on(self) -> bool:
"""Return true if the binary sensor is on."""
return self.entity_description.is_on_fn(self._scale)
+2 -1
View File
@@ -2,7 +2,7 @@
from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from typing import Any
from typing import Any, override
from aioacaia.acaiascale import AcaiaScale
@@ -58,6 +58,7 @@ class AcaiaButton(AcaiaEntity, ButtonEntity):
entity_description: AcaiaButtonEntityDescription
@override
async def async_press(self) -> None:
"""Handle the button press."""
await self.entity_description.press_fn(self._scale)
@@ -1,7 +1,7 @@
"""Config flow for Acaia integration."""
import logging
from typing import Any
from typing import Any, override
from aioacaia.exceptions import AcaiaDeviceNotFound, AcaiaError, AcaiaUnknownDevice
from aioacaia.helpers import is_new_scale
@@ -34,6 +34,7 @@ class AcaiaConfigFlow(ConfigFlow, domain=DOMAIN):
self._discovered: dict[str, Any] = {}
self._discovered_devices: dict[str, str] = {}
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -94,6 +95,7 @@ class AcaiaConfigFlow(ConfigFlow, domain=DOMAIN):
errors=errors,
)
@override
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfoBleak
) -> ConfigFlowResult:
@@ -2,6 +2,7 @@
from datetime import timedelta
import logging
from typing import override
from aioacaia.acaiascale import AcaiaScale
from aioacaia.exceptions import AcaiaDeviceNotFound, AcaiaError
@@ -59,6 +60,7 @@ class AcaiaCoordinator(DataUpdateCoordinator[None]):
"""Return the scale object."""
return self._scale
@override
async def _async_update_data(self) -> None:
"""Fetch data."""
+2
View File
@@ -1,6 +1,7 @@
"""Base class for Acaia entities."""
from dataclasses import dataclass
from typing import override
from homeassistant.helpers.device_registry import (
CONNECTION_BLUETOOTH,
@@ -41,6 +42,7 @@ class AcaiaEntity(CoordinatorEntity[AcaiaCoordinator]):
)
@property
@override
def available(self) -> bool:
"""Returns whether entity is available."""
return super().available and self._scale.connected
+6
View File
@@ -2,6 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import override
from aioacaia.acaiascale import AcaiaDeviceState, AcaiaScale
from aioacaia.const import UnitMass as AcaiaUnitOfMass
@@ -98,6 +99,7 @@ class AcaiaSensor(AcaiaEntity, SensorEntity):
entity_description: AcaiaDynamicUnitSensorEntityDescription
@property
@override
def native_unit_of_measurement(self) -> str | None:
"""Return the unit of measurement of this entity."""
if (
@@ -108,6 +110,7 @@ class AcaiaSensor(AcaiaEntity, SensorEntity):
return self.entity_description.native_unit_of_measurement
@property
@override
def native_value(self) -> int | float | None:
"""Return the state of the entity."""
return self.entity_description.value_fn(self._scale)
@@ -119,6 +122,7 @@ class AcaiaRestoreSensor(AcaiaEntity, RestoreSensor):
entity_description: AcaiaSensorEntityDescription
_restored_data: SensorExtraStoredData | None = None
@override
async def async_added_to_hass(self) -> None:
"""Handle entity which will be added."""
await super().async_added_to_hass()
@@ -134,6 +138,7 @@ class AcaiaRestoreSensor(AcaiaEntity, RestoreSensor):
self._attr_native_value = self.entity_description.value_fn(self._scale)
@callback
@override
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
if self._scale.device_state is not None:
@@ -141,6 +146,7 @@ class AcaiaRestoreSensor(AcaiaEntity, RestoreSensor):
self._async_write_ha_state()
@property
@override
def available(self) -> bool:
"""Return True if entity is available."""
return super().available or self.native_value is not None
@@ -2,7 +2,7 @@
from asyncio import timeout
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
from accuweather import AccuWeather, ApiError, InvalidApiKeyError, RequestsExceededError
from aiohttp import ClientError
@@ -24,6 +24,7 @@ class AccuWeatherFlowHandler(ConfigFlow, domain=DOMAIN):
_latitude: float | None = None
_longitude: float | None = None
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -5,7 +5,7 @@ from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
from accuweather import AccuWeather, ApiError, InvalidApiKeyError, RequestsExceededError
from aiohttp.client_exceptions import ClientConnectorError
@@ -77,6 +77,7 @@ class AccuWeatherObservationDataUpdateCoordinator(
update_interval=UPDATE_INTERVAL_OBSERVATION,
)
@override
async def _async_update_data(self) -> dict[str, Any]:
"""Update data via library."""
try:
@@ -135,6 +136,7 @@ class AccuWeatherForecastDataUpdateCoordinator(
update_interval=update_interval,
)
@override
async def _async_update_data(self) -> list[dict[str, Any]]:
"""Update forecast data via library."""
try:
@@ -2,7 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, cast
from typing import Any, cast, override
from homeassistant.components.sensor import (
SensorDeviceClass,
@@ -436,16 +436,19 @@ class AccuWeatherSensor(
self._attr_device_info = coordinator.device_info
@property
@override
def native_value(self) -> str | int | float | None:
"""Return the state."""
return self.entity_description.value_fn(self._sensor_data)
@property
@override
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
return self.entity_description.attr_fn(self.coordinator.data)
@callback
@override
def _handle_coordinator_update(self) -> None:
"""Handle data update."""
self._sensor_data = self._get_sensor_data(
@@ -495,16 +498,19 @@ class AccuWeatherForecastSensor(
self.forecast_day = forecast_day
@property
@override
def native_value(self) -> str | int | float | None:
"""Return the state."""
return self.entity_description.value_fn(self._sensor_data)
@property
@override
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
return self.entity_description.attr_fn(self._sensor_data)
@callback
@override
def _handle_coordinator_update(self) -> None:
"""Handle data update."""
self._sensor_data = self._get_sensor_data(
@@ -1,6 +1,6 @@
"""Support for the AccuWeather service."""
from typing import cast
from typing import cast, override
from homeassistant.components.weather import (
ATTR_FORECAST_CLOUD_COVERAGE,
@@ -96,16 +96,19 @@ class AccuWeatherEntity(
self.hourly_coordinator = accuweather_data.coordinator_hourly_forecast
@property
@override
def condition(self) -> str | None:
"""Return the current condition."""
return CONDITION_MAP.get(self.observation_coordinator.data["WeatherIcon"])
@property
@override
def cloud_coverage(self) -> float:
"""Return the Cloud coverage in %."""
return cast(float, self.observation_coordinator.data["CloudCover"])
@property
@override
def native_apparent_temperature(self) -> float:
"""Return the apparent temperature."""
return cast(
@@ -116,6 +119,7 @@ class AccuWeatherEntity(
)
@property
@override
def native_temperature(self) -> float:
"""Return the temperature."""
return cast(
@@ -124,6 +128,7 @@ class AccuWeatherEntity(
)
@property
@override
def native_pressure(self) -> float:
"""Return the pressure."""
return cast(
@@ -131,6 +136,7 @@ class AccuWeatherEntity(
)
@property
@override
def native_dew_point(self) -> float:
"""Return the dew point."""
return cast(
@@ -138,11 +144,13 @@ class AccuWeatherEntity(
)
@property
@override
def humidity(self) -> int:
"""Return the humidity."""
return cast(int, self.observation_coordinator.data["RelativeHumidity"])
@property
@override
def native_wind_gust_speed(self) -> float:
"""Return the wind gust speed."""
return cast(
@@ -153,6 +161,7 @@ class AccuWeatherEntity(
)
@property
@override
def native_wind_speed(self) -> float:
"""Return the wind speed."""
return cast(
@@ -163,6 +172,7 @@ class AccuWeatherEntity(
)
@property
@override
def wind_bearing(self) -> int:
"""Return the wind bearing."""
return cast(
@@ -170,6 +180,7 @@ class AccuWeatherEntity(
)
@property
@override
def native_visibility(self) -> float:
"""Return the visibility."""
return cast(
@@ -178,11 +189,13 @@ class AccuWeatherEntity(
)
@property
@override
def uv_index(self) -> float:
"""Return the UV index."""
return cast(float, self.observation_coordinator.data["UVIndex"])
@callback
@override
def _async_forecast_daily(self) -> list[Forecast] | None:
"""Return the daily forecast in native units."""
return [
@@ -213,6 +226,7 @@ class AccuWeatherEntity(
]
@callback
@override
def _async_forecast_hourly(self) -> list[Forecast] | None:
"""Return the hourly forecast in native units."""
return [
@@ -2,7 +2,7 @@
import logging
import re
from typing import Any
from typing import Any, override
from serialx import Serial, SerialException
import voluptuous as vol
@@ -140,12 +140,14 @@ class AcerSwitch(SwitchEntity):
self._attributes[key] = awns
self._attr_extra_state_attributes = self._attributes
@override
def turn_on(self, **kwargs: Any) -> None:
"""Turn the projector on."""
msg = CMD_DICT[STATE_ON]
self._write_read(msg)
self._attr_is_on = True
@override
def turn_off(self, **kwargs: Any) -> None:
"""Turn the projector off."""
msg = CMD_DICT[STATE_OFF]
@@ -2,7 +2,7 @@
from asyncio import timeout
from contextlib import suppress
from typing import Any
from typing import Any, override
import aiopulse
import voluptuous as vol
@@ -22,6 +22,7 @@ class AcmedaFlowHandler(ConfigFlow, domain=DOMAIN):
"""Initialize the config flow."""
self.discovered_hubs: dict[str, aiopulse.Hub] | None = None
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
+13 -1
View File
@@ -1,6 +1,6 @@
"""Support for Acmeda Roller Blinds."""
from typing import Any
from typing import Any, override
from homeassistant.components.cover import (
ATTR_POSITION,
@@ -48,6 +48,7 @@ class AcmedaCover(AcmedaEntity, CoverEntity):
_attr_name = None
@property
@override
def current_cover_position(self) -> int | None:
"""Return the current position of the roller blind.
@@ -59,6 +60,7 @@ class AcmedaCover(AcmedaEntity, CoverEntity):
return position
@property
@override
def current_cover_tilt_position(self) -> int | None:
"""Return the current tilt of the roller blind.
@@ -70,6 +72,7 @@ class AcmedaCover(AcmedaEntity, CoverEntity):
return position
@property
@override
def supported_features(self) -> CoverEntityFeature:
"""Flag supported features."""
supported_features = CoverEntityFeature(0)
@@ -91,38 +94,47 @@ class AcmedaCover(AcmedaEntity, CoverEntity):
return supported_features
@property
@override
def is_closed(self) -> bool:
"""Return if the cover is closed."""
return self.roller.closed_percent == 100 # type: ignore[no-any-return]
@override
async def async_close_cover(self, **kwargs: Any) -> None:
"""Close the roller."""
await self.roller.move_down()
@override
async def async_open_cover(self, **kwargs: Any) -> None:
"""Open the roller."""
await self.roller.move_up()
@override
async def async_stop_cover(self, **kwargs: Any) -> None:
"""Stop the roller."""
await self.roller.move_stop()
@override
async def async_set_cover_position(self, **kwargs: Any) -> None:
"""Move the roller shutter to a specific position."""
await self.roller.move_to(100 - kwargs[ATTR_POSITION])
@override
async def async_close_cover_tilt(self, **kwargs: Any) -> None:
"""Close the roller."""
await self.roller.move_down()
@override
async def async_open_cover_tilt(self, **kwargs: Any) -> None:
"""Open the roller."""
await self.roller.move_up()
@override
async def async_stop_cover_tilt(self, **kwargs: Any) -> None:
"""Stop the roller."""
await self.roller.move_stop()
@override
async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
"""Tilt the roller shutter to a specific position."""
await self.roller.move_to(100 - kwargs[ATTR_POSITION])
@@ -1,5 +1,7 @@
"""Base class for Acmeda Roller Blinds."""
from typing import override
import aiopulse
from homeassistant.core import callback
@@ -40,6 +42,7 @@ class AcmedaEntity(entity.Entity):
await self.async_remove(force_remove=True)
@override
async def async_added_to_hass(self) -> None:
"""Entity has been added to hass."""
self.roller.callback_subscribe(self.notify_update)
@@ -52,6 +55,7 @@ class AcmedaEntity(entity.Entity):
)
)
@override
async def async_will_remove_from_hass(self) -> None:
"""Entity being removed from hass."""
self.roller.callback_unsubscribe(self.notify_update)
@@ -63,6 +67,7 @@ class AcmedaEntity(entity.Entity):
self.async_write_ha_state()
@property
@override
def unique_id(self) -> str:
"""Return the unique ID of this roller."""
return str(self.roller.id)
@@ -73,6 +78,7 @@ class AcmedaEntity(entity.Entity):
return self.roller.id # type: ignore[no-any-return]
@property
@override
def device_info(self) -> dr.DeviceInfo:
"""Return the device info."""
return dr.DeviceInfo(
@@ -1,5 +1,7 @@
"""Support for Acmeda Roller Blind Batteries."""
from typing import override
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
from homeassistant.const import PERCENTAGE
from homeassistant.core import HomeAssistant, callback
@@ -44,6 +46,7 @@ class AcmedaBattery(AcmedaEntity, SensorEntity):
_attr_native_unit_of_measurement = PERCENTAGE
@property
@override
def native_value(self) -> float | int | None:
"""Return the state of the device."""
return self.roller.battery # type: ignore[no-any-return]
@@ -1,7 +1,7 @@
"""Support for Actiontec MI424WR (Verizon FIOS) routers."""
import logging
from typing import Final
from typing import Final, override
import telnetlib # pylint: disable=deprecated-module
import voluptuous as vol
@@ -50,11 +50,13 @@ class ActiontecDeviceScanner(DeviceScanner):
data = self.get_actiontec_data()
self.success_init = data is not None
@override
def scan_devices(self) -> list[str]:
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [client.mac_address for client in self.last_results]
@override
def get_device_name(self, device: str) -> str | None:
"""Return the name of the given device or None if we don't know."""
for client in self.last_results:
+21 -1
View File
@@ -1,6 +1,6 @@
"""Climate platform for Actron Air integration."""
from typing import Any
from typing import Any, override
from actron_neo_api import ActronAirStatus, ActronAirZone
@@ -94,6 +94,7 @@ class ActronSystemClimate(ActronAirAcEntity, ActronAirClimateEntity):
self._attr_unique_id = self._serial_number
@property
@override
def hvac_modes(self) -> list[HVACMode]:
"""Return the list of supported HVAC modes."""
modes = [
@@ -105,11 +106,13 @@ class ActronSystemClimate(ActronAirAcEntity, ActronAirClimateEntity):
return modes
@property
@override
def min_temp(self) -> float:
"""Return the minimum temperature that can be set."""
return self._status.min_temp
@property
@override
def max_temp(self) -> float:
"""Return the maximum temperature that can be set."""
return self._status.max_temp
@@ -120,6 +123,7 @@ class ActronSystemClimate(ActronAirAcEntity, ActronAirClimateEntity):
return self.coordinator.data
@property
@override
def hvac_mode(self) -> HVACMode | None:
"""Return the current HVAC mode."""
if not self._status.user_aircon_settings.is_on:
@@ -129,39 +133,46 @@ class ActronSystemClimate(ActronAirAcEntity, ActronAirClimateEntity):
return HVAC_MODE_MAPPING_ACTRONAIR_TO_HA.get(mode)
@property
@override
def fan_mode(self) -> str | None:
"""Return the current fan mode."""
fan_mode = self._status.user_aircon_settings.base_fan_mode
return FAN_MODE_MAPPING_ACTRONAIR_TO_HA.get(fan_mode)
@property
@override
def current_humidity(self) -> float:
"""Return the current humidity."""
return self._status.master_info.live_humidity_pc
@property
@override
def current_temperature(self) -> float:
"""Return the current temperature."""
return self._status.master_info.live_temp_c
@property
@override
def target_temperature(self) -> float:
"""Return the target temperature."""
return self._status.user_aircon_settings.current_setpoint
@actron_air_command
@override
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set a new fan mode."""
api_fan_mode = FAN_MODE_MAPPING_HA_TO_ACTRONAIR[fan_mode]
await self._status.user_aircon_settings.set_fan_mode(api_fan_mode)
@actron_air_command
@override
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the HVAC mode."""
ac_mode = HVAC_MODE_MAPPING_HA_TO_ACTRONAIR[hvac_mode]
await self._status.ac_system.set_system_mode(ac_mode)
@actron_air_command
@override
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the temperature."""
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
@@ -191,6 +202,7 @@ class ActronZoneClimate(ActronAirZoneEntity, ActronAirClimateEntity):
self._attr_unique_id: str = self._zone_identifier
@property
@override
def hvac_modes(self) -> list[HVACMode]:
"""Return the list of supported HVAC modes."""
status = self.coordinator.data
@@ -203,11 +215,13 @@ class ActronZoneClimate(ActronAirZoneEntity, ActronAirClimateEntity):
return modes
@property
@override
def min_temp(self) -> float:
"""Return the minimum temperature that can be set."""
return self._zone.min_temp
@property
@override
def max_temp(self) -> float:
"""Return the maximum temperature that can be set."""
return self._zone.max_temp
@@ -219,6 +233,7 @@ class ActronZoneClimate(ActronAirZoneEntity, ActronAirClimateEntity):
return status.zones[self._zone_id]
@property
@override
def hvac_mode(self) -> HVACMode | None:
"""Return the current HVAC mode."""
if self._zone.is_active:
@@ -227,27 +242,32 @@ class ActronZoneClimate(ActronAirZoneEntity, ActronAirClimateEntity):
return HVACMode.OFF
@property
@override
def current_humidity(self) -> float | None:
"""Return the current humidity."""
return self._zone.humidity
@property
@override
def current_temperature(self) -> float | None:
"""Return the current temperature."""
return self._zone.live_temp_c
@property
@override
def target_temperature(self) -> float | None:
"""Return the target temperature."""
return self._zone.current_setpoint
@actron_air_command
@override
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the HVAC mode."""
is_enabled = hvac_mode != HVACMode.OFF
await self._zone.enable(is_enabled)
@actron_air_command
@override
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the temperature."""
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
@@ -2,7 +2,7 @@
import asyncio
from collections.abc import Mapping
from typing import Any
from typing import Any, override
from actron_neo_api import ActronAirAPI, ActronAirAuthError
@@ -30,6 +30,7 @@ class ActronAirConfigFlow(ConfigFlow, domain=DOMAIN):
self._expires_minutes: str = "30"
self.login_task: asyncio.Task[None] | None = None
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -2,6 +2,7 @@
from dataclasses import dataclass
from datetime import timedelta
from typing import override
from actron_neo_api import (
ActronAirAPI,
@@ -60,6 +61,7 @@ class ActronAirSystemCoordinator(DataUpdateCoordinator[ActronAirStatus]):
self.status = self.api.state_manager.get_status(self.serial_number)
self.last_seen = dt_util.utcnow()
@override
async def _async_update_data(self) -> ActronAirStatus:
"""Fetch updates and merge incremental changes into the full state."""
try:
@@ -2,7 +2,7 @@
from collections.abc import Callable, Coroutine
from functools import wraps
from typing import Any, Concatenate
from typing import Any, Concatenate, override
from actron_neo_api import ActronAirAPIError, ActronAirZone
@@ -50,6 +50,7 @@ class ActronAirEntity(CoordinatorEntity[ActronAirSystemCoordinator]):
self._serial_number = coordinator.serial_number
@property
@override
def available(self) -> bool:
"""Return True if entity is available."""
return not self.coordinator.is_device_stale()
@@ -2,7 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import Any
from typing import Any, override
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.const import EntityCategory
@@ -101,16 +101,19 @@ class ActronAirSwitch(ActronAirAcEntity, SwitchEntity):
self._attr_unique_id = f"{coordinator.serial_number}_{description.key}"
@property
@override
def is_on(self) -> bool:
"""Return true if the switch is on."""
return self.entity_description.is_on_fn(self.coordinator)
@actron_air_command
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
await self.entity_description.set_fn(self.coordinator, True)
@actron_air_command
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
await self.entity_description.set_fn(self.coordinator, False)
+9 -1
View File
@@ -1,6 +1,6 @@
"""Support for Adax wifi-enabled home heaters."""
from typing import Any, cast
from typing import Any, cast, override
from adax import Adax
from adax_local import Adax as AdaxLocal
@@ -82,6 +82,7 @@ class AdaxDevice(CoordinatorEntity[AdaxCloudCoordinator], ClimateEntity):
self._apply_data(self.room)
@property
@override
def available(self) -> bool:
"""Whether the entity is available or not."""
return super().available and self._device_id in self.coordinator.data
@@ -91,6 +92,7 @@ class AdaxDevice(CoordinatorEntity[AdaxCloudCoordinator], ClimateEntity):
"""Gets the data for this particular device."""
return self.coordinator.data[self._device_id]
@override
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set hvac mode."""
if hvac_mode == HVACMode.HEAT:
@@ -108,6 +110,7 @@ class AdaxDevice(CoordinatorEntity[AdaxCloudCoordinator], ClimateEntity):
# Request data refresh from source to verify that update was successful
await self.coordinator.async_request_refresh()
@override
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
@@ -117,6 +120,7 @@ class AdaxDevice(CoordinatorEntity[AdaxCloudCoordinator], ClimateEntity):
)
@callback
@override
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
if room := self.room:
@@ -161,6 +165,7 @@ class LocalAdaxDevice(CoordinatorEntity[AdaxLocalCoordinator], ClimateEntity):
manufacturer="Adax",
)
@override
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set hvac mode."""
if hvac_mode == HVACMode.HEAT:
@@ -179,6 +184,7 @@ class LocalAdaxDevice(CoordinatorEntity[AdaxLocalCoordinator], ClimateEntity):
self._attr_hvac_mode = hvac_mode
self.async_write_ha_state()
@override
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
@@ -211,11 +217,13 @@ class LocalAdaxDevice(CoordinatorEntity[AdaxLocalCoordinator], ClimateEntity):
self._attr_target_temperature = target_temp
@callback
@override
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._update_hvac_attributes()
super()._handle_coordinator_update()
@override
async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
+2 -1
View File
@@ -1,7 +1,7 @@
"""Config flow for Adax integration."""
import logging
from typing import Any
from typing import Any, override
import adax
import adax_local
@@ -39,6 +39,7 @@ class AdaxConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 2
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
+3 -1
View File
@@ -1,7 +1,7 @@
"""DataUpdateCoordinator for the Adax component."""
import logging
from typing import Any, cast
from typing import Any, cast, override
from adax import Adax
from adax_local import Adax as AdaxLocal
@@ -39,6 +39,7 @@ class AdaxCloudCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]):
websession=async_get_clientsession(hass),
)
@override
async def _async_update_data(self) -> dict[str, dict[str, Any]]:
"""Fetch data from the Adax."""
try:
@@ -87,6 +88,7 @@ class AdaxLocalCoordinator(DataUpdateCoordinator[dict[str, Any] | None]):
websession=async_get_clientsession(hass, verify_ssl=False),
)
@override
async def _async_update_data(self) -> dict[str, Any]:
"""Fetch data from the Adax."""
if result := await self.adax_data_handler.get_status():
+3 -1
View File
@@ -1,7 +1,7 @@
"""Support for Adax energy sensors."""
from dataclasses import dataclass
from typing import cast
from typing import cast, override
from homeassistant.components.sensor import (
SensorDeviceClass,
@@ -95,6 +95,7 @@ class AdaxSensor(CoordinatorEntity[AdaxCloudCoordinator], SensorEntity):
)
@property
@override
def available(self) -> bool:
"""Return True if entity is available."""
return (
@@ -104,6 +105,7 @@ class AdaxSensor(CoordinatorEntity[AdaxCloudCoordinator], SensorEntity):
)
@property
@override
def native_value(self) -> int | float | None:
"""Return the native value of the sensor."""
return self.coordinator.data[self._device_id].get(
@@ -1,6 +1,6 @@
"""Config flow to configure the AdGuard Home integration."""
from typing import Any
from typing import Any, override
from adguardhome import AdGuardHome, AdGuardHomeConnectionError
import voluptuous as vol
@@ -57,6 +57,7 @@ class AdGuardHomeFlowHandler(ConfigFlow, domain=DOMAIN):
errors=errors or {},
)
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -102,6 +103,7 @@ class AdGuardHomeFlowHandler(ConfigFlow, domain=DOMAIN):
},
)
@override
async def async_step_hassio(
self, discovery_info: HassioServiceInfo
) -> ConfigFlowResult:
@@ -1,5 +1,7 @@
"""AdGuard Home base entity."""
from typing import override
from adguardhome import AdGuardHomeError
from homeassistant.config_entries import SOURCE_HASSIO
@@ -47,6 +49,7 @@ class AdGuardHomeEntity(Entity):
raise NotImplementedError
@property
@override
def device_info(self) -> DeviceInfo:
"""Return device information about this AdGuard Home instance."""
if self._entry.source == SOURCE_HASSIO:
+3 -2
View File
@@ -3,7 +3,7 @@
from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from datetime import timedelta
from typing import Any
from typing import Any, override
from adguardhome import AdGuardHome
@@ -108,7 +108,7 @@ class AdGuardHomeSensor(AdGuardHomeEntity, SensorEntity):
"""Initialize AdGuard Home sensor."""
super().__init__(data, entry)
self.entity_description = description
self._attr_unique_id = "_".join(
self._attr_unique_id = "_".join( # pylint: disable=home-assistant-entity-unique-id-redundant-domain
[
DOMAIN,
self.adguard.host,
@@ -118,6 +118,7 @@ class AdGuardHomeSensor(AdGuardHomeEntity, SensorEntity):
]
)
@override
async def _adguard_update(self) -> None:
"""Update AdGuard Home entity."""
value = await self.entity_description.value_fn(self.adguard)
+5 -2
View File
@@ -3,7 +3,7 @@
from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from datetime import timedelta
from typing import Any
from typing import Any, override
from adguardhome import AdGuardHome, AdGuardHomeError
@@ -103,7 +103,7 @@ class AdGuardHomeSwitch(AdGuardHomeEntity, SwitchEntity):
"""Initialize AdGuard Home switch."""
super().__init__(data, entry)
self.entity_description = description
self._attr_unique_id = "_".join(
self._attr_unique_id = "_".join( # pylint: disable=home-assistant-entity-unique-id-redundant-domain
[
DOMAIN,
self.adguard.host,
@@ -113,6 +113,7 @@ class AdGuardHomeSwitch(AdGuardHomeEntity, SwitchEntity):
]
)
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the switch."""
try:
@@ -124,6 +125,7 @@ class AdGuardHomeSwitch(AdGuardHomeEntity, SwitchEntity):
translation_key="error_while_turn_off",
) from err
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the switch."""
try:
@@ -135,6 +137,7 @@ class AdGuardHomeSwitch(AdGuardHomeEntity, SwitchEntity):
translation_key="error_while_turn_on",
) from err
@override
async def _adguard_update(self) -> None:
"""Update AdGuard Home entity."""
self._attr_is_on = await self.entity_description.is_on_fn(self.adguard)()
+4 -2
View File
@@ -1,7 +1,7 @@
"""AdGuard Home Update platform."""
from datetime import timedelta
from typing import Any
from typing import Any, override
from adguardhome import AdGuardHomeError
@@ -46,10 +46,11 @@ class AdGuardHomeUpdate(AdGuardHomeEntity, UpdateEntity):
"""Initialize AdGuard Home update."""
super().__init__(data, entry)
self._attr_unique_id = "_".join(
self._attr_unique_id = "_".join( # pylint: disable=home-assistant-entity-unique-id-redundant-domain
[DOMAIN, self.adguard.host, str(self.adguard.port), "update"]
)
@override
async def _adguard_update(self) -> None:
"""Update AdGuard Home entity."""
value = await self.adguard.update.update_available()
@@ -58,6 +59,7 @@ class AdGuardHomeUpdate(AdGuardHomeEntity, UpdateEntity):
self._attr_release_summary = value.announcement
self._attr_release_url = value.announcement_url
@override
async def async_install(
self, version: str | None, backup: bool, **kwargs: Any
) -> None:
@@ -1,5 +1,7 @@
"""Support for ADS binary sensors."""
from typing import override
import pyads
import voluptuous as vol
@@ -60,11 +62,13 @@ class AdsBinarySensor(AdsEntity, BinarySensorEntity):
super().__init__(ads_hub, name, ads_var)
self._attr_device_class = device_class or BinarySensorDeviceClass.MOVING
@override
async def async_added_to_hass(self) -> None:
"""Register device notification."""
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_BOOL)
@property
@override
def is_on(self) -> bool:
"""Return True if the entity is on."""
return self._state_dict[STATE_KEY_STATE]
+9 -1
View File
@@ -1,6 +1,6 @@
"""Support for ADS covers."""
from typing import Any
from typing import Any, override
import pyads
import voluptuous as vol
@@ -122,6 +122,7 @@ class AdsCover(AdsEntity, CoverEntity):
if ads_var_pos_set is not None:
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
@override
async def async_added_to_hass(self) -> None:
"""Register device notification."""
if self._ads_var is not None:
@@ -133,6 +134,7 @@ class AdsCover(AdsEntity, CoverEntity):
)
@property
@override
def is_closed(self) -> bool | None:
"""Return if the cover is closed."""
if self._ads_var is not None:
@@ -142,15 +144,18 @@ class AdsCover(AdsEntity, CoverEntity):
return None
@property
@override
def current_cover_position(self) -> int:
"""Return current position of cover."""
return self._state_dict[STATE_KEY_POSITION]
@override
def stop_cover(self, **kwargs: Any) -> None:
"""Fire the stop action."""
if self._ads_var_stop:
self._ads_hub.write_by_name(self._ads_var_stop, True, pyads.PLCTYPE_BOOL)
@override
def set_cover_position(self, **kwargs: Any) -> None:
"""Set cover position."""
position = kwargs[ATTR_POSITION]
@@ -159,6 +164,7 @@ class AdsCover(AdsEntity, CoverEntity):
self._ads_var_pos_set, position, pyads.PLCTYPE_BYTE
)
@override
def open_cover(self, **kwargs: Any) -> None:
"""Move the cover up."""
if self._ads_var_open is not None:
@@ -166,6 +172,7 @@ class AdsCover(AdsEntity, CoverEntity):
elif self._ads_var_pos_set is not None:
self.set_cover_position(position=100)
@override
def close_cover(self, **kwargs: Any) -> None:
"""Move the cover down."""
if self._ads_var_close is not None:
@@ -174,6 +181,7 @@ class AdsCover(AdsEntity, CoverEntity):
self.set_cover_position(position=0)
@property
@override
def available(self) -> bool:
"""Return False if state has not been updated yet."""
if self._ads_var is not None or self._ads_var_position is not None:
+2 -1
View File
@@ -3,7 +3,7 @@
import asyncio
from asyncio import timeout
import logging
from typing import Any
from typing import Any, override
from homeassistant.helpers.entity import Entity
@@ -65,6 +65,7 @@ class AdsEntity(Entity):
_LOGGER.debug("Variable %s: Timeout during first update", ads_var)
@property
@override
def available(self) -> bool:
"""Return False if state has not been updated yet."""
return self._state_dict[STATE_KEY_STATE] is not None
+7 -1
View File
@@ -1,6 +1,6 @@
"""Support for ADS light sources."""
from typing import Any
from typing import Any, override
import pyads
import voluptuous as vol
@@ -120,6 +120,7 @@ class AdsLight(AdsEntity, LightEntity):
else DEFAULT_MAX_KELVIN
)
@override
async def async_added_to_hass(self) -> None:
"""Register device notification."""
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_BOOL)
@@ -139,20 +140,24 @@ class AdsLight(AdsEntity, LightEntity):
)
@property
@override
def brightness(self) -> int | None:
"""Return the brightness of the light (0..255)."""
return self._state_dict[STATE_KEY_BRIGHTNESS]
@property
@override
def color_temp_kelvin(self) -> int | None:
"""Return the color temperature in Kelvin."""
return self._state_dict[STATE_KEY_COLOR_TEMP_KELVIN]
@property
@override
def is_on(self) -> bool:
"""Return True if the entity is on."""
return self._state_dict[STATE_KEY_STATE]
@override
def turn_on(self, **kwargs: Any) -> None:
"""Turn the light on or set a specific dimmer value."""
brightness = kwargs.get(ATTR_BRIGHTNESS)
@@ -170,6 +175,7 @@ class AdsLight(AdsEntity, LightEntity):
self._ads_var_color_temp_kelvin, color_temp, pyads.PLCTYPE_UINT
)
@override
def turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
self._ads_hub.write_by_name(self._ads_var, False, pyads.PLCTYPE_BOOL)
+4
View File
@@ -1,5 +1,7 @@
"""Support for ADS select entities."""
from typing import override
import pyads
import voluptuous as vol
@@ -61,6 +63,7 @@ class AdsSelect(AdsEntity, SelectEntity):
self._attr_options = options
self._attr_current_option = None
@override
async def async_added_to_hass(self) -> None:
"""Register device notification."""
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_INT)
@@ -68,6 +71,7 @@ class AdsSelect(AdsEntity, SelectEntity):
self._ads_var, pyads.PLCTYPE_INT, self._handle_ads_value
)
@override
def select_option(self, option: str) -> None:
"""Change the selected option."""
if option in self._attr_options:
+4
View File
@@ -1,5 +1,7 @@
"""Support for ADS sensors."""
from typing import override
import voluptuous as vol
from homeassistant.components.sensor import (
@@ -108,6 +110,7 @@ class AdsSensor(AdsEntity, SensorEntity):
self._attr_state_class = state_class
self._attr_native_unit_of_measurement = unit_of_measurement
@override
async def async_added_to_hass(self) -> None:
"""Register device notification."""
await self.async_initialize_device(
@@ -118,6 +121,7 @@ class AdsSensor(AdsEntity, SensorEntity):
)
@property
@override
def native_value(self) -> StateType:
"""Return the state of the device."""
return self._state_dict[STATE_KEY_STATE]
+5 -1
View File
@@ -1,6 +1,6 @@
"""Support for ADS switch platform."""
from typing import Any
from typing import Any, override
import pyads
import voluptuous as vol
@@ -46,19 +46,23 @@ def setup_platform(
class AdsSwitch(AdsEntity, SwitchEntity):
"""Representation of an ADS switch device."""
@override
async def async_added_to_hass(self) -> None:
"""Register device notification."""
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_BOOL)
@property
@override
def is_on(self) -> bool:
"""Return True if the entity is on."""
return self._state_dict[STATE_KEY_STATE]
@override
def turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
self._ads_hub.write_by_name(self._ads_var, True, pyads.PLCTYPE_BOOL)
@override
def turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
self._ads_hub.write_by_name(self._ads_var, False, pyads.PLCTYPE_BOOL)
+5
View File
@@ -1,5 +1,7 @@
"""Support for ADS valves."""
from typing import override
import pyads
import voluptuous as vol
@@ -67,15 +69,18 @@ class AdsValve(AdsEntity, ValveEntity):
self._attr_reports_position = False
self._attr_is_closed = True
@override
async def async_added_to_hass(self) -> None:
"""Register device notification."""
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_BOOL)
@override
def open_valve(self, **kwargs) -> None:
"""Open the valve."""
self._ads_hub.write_by_name(self._ads_var, True, pyads.PLCTYPE_BOOL)
self._attr_is_closed = False
@override
def close_valve(self, **kwargs) -> None:
"""Close the valve."""
self._ads_hub.write_by_name(self._ads_var, False, pyads.PLCTYPE_BOOL)
@@ -1,5 +1,7 @@
"""Binary Sensor platform for Advantage Air integration."""
from typing import override
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
@@ -55,6 +57,7 @@ class AdvantageAirFilter(AdvantageAirAcEntity, BinarySensorEntity):
self._attr_unique_id += "-filter"
@property
@override
def is_on(self) -> bool:
"""Return if filter needs cleaning."""
return self._ac["filterCleanStatus"]
@@ -74,6 +77,7 @@ class AdvantageAirZoneMotion(AdvantageAirZoneEntity, BinarySensorEntity):
self._attr_unique_id += "-motion"
@property
@override
def is_on(self) -> bool:
"""Return if motion is detect."""
return self._zone["motion"] == 20
@@ -94,6 +98,7 @@ class AdvantageAirZoneMyZone(AdvantageAirZoneEntity, BinarySensorEntity):
self._attr_unique_id += "-myzone"
@property
@override
def is_on(self) -> bool:
"""Return if this zone is the myZone."""
return self._zone["number"] == self._ac["myZone"]
@@ -2,7 +2,7 @@
from decimal import Decimal
import logging
from typing import Any
from typing import Any, override
from homeassistant.components.climate import (
ATTR_TARGET_TEMP_HIGH,
@@ -156,12 +156,14 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
)
@callback
@override
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._async_configure_preset()
super()._handle_coordinator_update()
@property
@override
def current_temperature(self) -> float | None:
"""Return the selected zones current temperature."""
if self._myzone:
@@ -169,6 +171,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
return None
@property
@override
def target_temperature(self) -> float | None:
"""Return the current target temperature."""
# If the system is in MyZone mode, and a zone is set,
@@ -178,6 +181,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
return self._ac["setTemp"]
@property
@override
def hvac_mode(self) -> HVACMode | None:
"""Return the current HVAC modes."""
if self._ac["state"] == ADVANTAGE_AIR_STATE_ON:
@@ -185,6 +189,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
return HVACMode.OFF
@property
@override
def hvac_action(self) -> HVACAction | None:
"""Return the current running HVAC action."""
if self._ac["state"] == ADVANTAGE_AIR_STATE_OFF:
@@ -196,24 +201,29 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
return HVAC_ACTIONS.get(self._ac["mode"])
@property
@override
def fan_mode(self) -> str | None:
"""Return the current fan modes."""
return FAN_AUTO if self._ac["fan"] == ADVANTAGE_AIR_MYFAN else self._ac["fan"]
@property
@override
def target_temperature_high(self) -> float | None:
"""Return the temperature cool mode is enabled."""
return self._ac.get(ADVANTAGE_AIR_COOL_TARGET)
@property
@override
def target_temperature_low(self) -> float | None:
"""Return the temperature heat mode is enabled."""
return self._ac.get(ADVANTAGE_AIR_HEAT_TARGET)
@override
async def async_turn_on(self) -> None:
"""Set the HVAC State to on."""
await self.async_update_ac({"state": ADVANTAGE_AIR_STATE_ON})
@override
async def async_turn_off(self) -> None:
"""Set the HVAC State to off."""
await self.async_update_ac(
@@ -222,6 +232,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
}
)
@override
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the HVAC Mode and State."""
if hvac_mode == HVACMode.OFF:
@@ -236,6 +247,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
}
)
@override
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set the Fan Mode."""
if fan_mode == FAN_AUTO and self._ac.get(ADVANTAGE_AIR_AUTOFAN_ENABLED):
@@ -244,6 +256,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
mode = fan_mode
await self.async_update_ac({"fan": mode})
@override
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the Temperature."""
if ATTR_TEMPERATURE in kwargs:
@@ -256,6 +269,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
}
)
@override
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the preset mode."""
change = {}
@@ -289,6 +303,7 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
self._attr_name = self._zone["name"]
@property
@override
def hvac_mode(self) -> HVACMode:
"""Return the current state as HVAC mode."""
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
@@ -296,6 +311,7 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
return HVACMode.OFF
@property
@override
def hvac_action(self) -> HVACAction | None:
"""Return the HVAC action.
@@ -316,23 +332,28 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
return HVACAction.OFF
@property
@override
def current_temperature(self) -> float | None:
"""Return the current temperature."""
return self._zone["measuredTemp"]
@property
@override
def target_temperature(self) -> float:
"""Return the target temperature."""
return self._zone["setTemp"]
@override
async def async_turn_on(self) -> None:
"""Set the HVAC State to on."""
await self.async_update_zone({"state": ADVANTAGE_AIR_STATE_OPEN})
@override
async def async_turn_off(self) -> None:
"""Set the HVAC State to off."""
await self.async_update_zone({"state": ADVANTAGE_AIR_STATE_CLOSE})
@override
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the HVAC Mode and State."""
if hvac_mode == HVACMode.OFF:
@@ -340,6 +361,7 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
else:
await self.async_turn_on()
@override
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the Temperature."""
temp = kwargs.get(ATTR_TEMPERATURE)
@@ -1,6 +1,6 @@
"""Config Flow for Advantage Air integration."""
from typing import Any
from typing import Any, override
from advantage_air import ApiError, advantage_air
import voluptuous as vol
@@ -28,6 +28,7 @@ class AdvantageAirConfigFlow(ConfigFlow, domain=DOMAIN):
DOMAIN = DOMAIN
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -2,7 +2,7 @@
from datetime import timedelta
import logging
from typing import Any
from typing import Any, override
from advantage_air import ApiError, advantage_air
@@ -45,6 +45,7 @@ class AdvantageAirCoordinator(DataUpdateCoordinator[dict[str, Any]]):
)
self.api = api
@override
async def _async_update_data(self) -> dict[str, Any]:
"""Fetch data from the API."""
try:
@@ -1,6 +1,6 @@
"""Cover platform for Advantage Air integration."""
from typing import Any
from typing import Any, override
from homeassistant.components.cover import (
ATTR_POSITION,
@@ -66,27 +66,32 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, CoverEntity):
self._attr_name = self._zone["name"]
@property
@override
def is_closed(self) -> bool:
"""Return if vent is fully closed."""
return self._zone["state"] == ADVANTAGE_AIR_STATE_CLOSE
@property
@override
def current_cover_position(self) -> int:
"""Return vents current position as a percentage."""
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
return self._zone["value"]
return 0
@override
async def async_open_cover(self, **kwargs: Any) -> None:
"""Fully open zone vent."""
await self.async_update_zone(
{"state": ADVANTAGE_AIR_STATE_OPEN, "value": 100},
)
@override
async def async_close_cover(self, **kwargs: Any) -> None:
"""Fully close zone vent."""
await self.async_update_zone({"state": ADVANTAGE_AIR_STATE_CLOSE})
@override
async def async_set_cover_position(self, **kwargs: Any) -> None:
"""Change vent position."""
position = round(kwargs[ATTR_POSITION] / 5) * 5
@@ -117,14 +122,17 @@ class AdvantageAirThingCover(AdvantageAirThingEntity, CoverEntity):
self._attr_device_class = device_class
@property
@override
def is_closed(self) -> bool:
"""Return if cover is fully closed."""
return self._data["value"] == 0
@override
async def async_open_cover(self, **kwargs: Any) -> None:
"""Fully open zone vent."""
return await self.async_turn_on()
@override
async def async_close_cover(self, **kwargs: Any) -> None:
"""Fully close zone vent."""
return await self.async_turn_off()
@@ -1,6 +1,6 @@
"""Light platform for Advantage Air integration."""
from typing import Any
from typing import Any, override
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
from homeassistant.core import HomeAssistant
@@ -70,14 +70,17 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity):
return self.coordinator.data["myLights"]["lights"][self._id]
@property
@override
def is_on(self) -> bool:
"""Return if the light is on."""
return self._data["state"] == ADVANTAGE_AIR_STATE_ON
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
await self.async_update_state(True)
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
await self.async_update_state(False)
@@ -99,10 +102,12 @@ class AdvantageAirLightDimmable(AdvantageAirLight):
)
@property
@override
def brightness(self) -> int:
"""Return the brightness of this light between 0..255."""
return round(self._data["value"] * 255 / 100)
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on and optionally set the brightness."""
if ATTR_BRIGHTNESS in kwargs:
@@ -124,10 +129,12 @@ class AdvantageAirThingLightDimmable(AdvantageAirThingEntity, LightEntity):
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
@property
@override
def brightness(self) -> int:
"""Return the brightness of this light between 0..255."""
return round(self._data["value"] * 255 / 100)
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on by setting the brightness."""
await self.async_update_value(round(kwargs.get(ATTR_BRIGHTNESS, 255) / 2.55))
@@ -1,5 +1,7 @@
"""Select platform for Advantage Air integration."""
from typing import override
from homeassistant.components.select import SelectEntity
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
@@ -48,10 +50,12 @@ class AdvantageAirMyZone(AdvantageAirAcEntity, SelectEntity):
self._attr_options.append(zone["name"])
@property
@override
def current_option(self) -> str:
"""Return the current MyZone."""
return self._number_to_name[self._ac["myZone"]]
@override
async def async_select_option(self, option: str) -> None:
"""Set the MyZone."""
await self.async_update_ac({"myZone": self._name_to_number[option]})
@@ -1,7 +1,7 @@
"""Sensor platform for Advantage Air integration."""
from decimal import Decimal
from typing import Any
from typing import Any, override
from homeassistant.components.sensor import (
SensorDeviceClass,
@@ -67,11 +67,13 @@ class AdvantageAirTimeTo(AdvantageAirAcEntity, SensorEntity):
self._attr_unique_id += f"-timeto{action}"
@property
@override
def native_value(self) -> Decimal:
"""Return the current value."""
return self._ac[self._time_key]
@property
@override
def icon(self) -> str:
"""Return a representative icon of the timer."""
if self._ac[self._time_key] > 0:
@@ -100,6 +102,7 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, SensorEntity):
self._attr_unique_id += "-vent"
@property
@override
def native_value(self) -> Decimal:
"""Return the current value of the air vent."""
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
@@ -107,6 +110,7 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, SensorEntity):
return Decimal(0)
@property
@override
def icon(self) -> str:
"""Return a representative icon."""
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
@@ -130,11 +134,13 @@ class AdvantageAirZoneSignal(AdvantageAirZoneEntity, SensorEntity):
self._attr_unique_id += "-signal"
@property
@override
def native_value(self) -> Decimal:
"""Return the current value of the wireless signal."""
return self._zone["rssi"]
@property
@override
def icon(self) -> str:
"""Return a representative icon."""
if self._zone["rssi"] >= 80:
@@ -166,6 +172,7 @@ class AdvantageAirZoneTemp(AdvantageAirZoneEntity, SensorEntity):
self._attr_unique_id += "-temp"
@property
@override
def native_value(self) -> Decimal:
"""Return the current value of the measured temperature."""
return self._zone["measuredTemp"]
@@ -1,6 +1,6 @@
"""Switch platform for Advantage Air integration."""
from typing import Any
from typing import Any, override
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
from homeassistant.core import HomeAssistant
@@ -57,14 +57,17 @@ class AdvantageAirFreshAir(AdvantageAirAcEntity, SwitchEntity):
self._attr_unique_id += "-freshair"
@property
@override
def is_on(self) -> bool:
"""Return the fresh air status."""
return self._ac["freshAirStatus"] == ADVANTAGE_AIR_STATE_ON
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn fresh air on."""
await self.async_update_ac({"freshAirStatus": ADVANTAGE_AIR_STATE_ON})
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn fresh air off."""
await self.async_update_ac({"freshAirStatus": ADVANTAGE_AIR_STATE_OFF})
@@ -83,14 +86,17 @@ class AdvantageAirMyFan(AdvantageAirAcEntity, SwitchEntity):
self._attr_unique_id += "-myfan"
@property
@override
def is_on(self) -> bool:
"""Return the MyFan status."""
return self._ac[ADVANTAGE_AIR_AUTOFAN_ENABLED]
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn MyFan on."""
await self.async_update_ac({ADVANTAGE_AIR_AUTOFAN_ENABLED: True})
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn MyFan off."""
await self.async_update_ac({ADVANTAGE_AIR_AUTOFAN_ENABLED: False})
@@ -109,14 +115,17 @@ class AdvantageAirNightMode(AdvantageAirAcEntity, SwitchEntity):
self._attr_unique_id += "-nightmode"
@property
@override
def is_on(self) -> bool:
"""Return the Night Mode status."""
return self._ac[ADVANTAGE_AIR_NIGHT_MODE_ENABLED]
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn Night Mode on."""
await self.async_update_ac({ADVANTAGE_AIR_NIGHT_MODE_ENABLED: True})
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn Night Mode off."""
await self.async_update_ac({ADVANTAGE_AIR_NIGHT_MODE_ENABLED: False})
@@ -1,5 +1,7 @@
"""Advantage Air Update platform."""
from typing import override
from homeassistant.components.update import UpdateEntity
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
@@ -40,11 +42,13 @@ class AdvantageAirApp(AdvantageAirEntity, UpdateEntity):
)
@property
@override
def installed_version(self) -> str:
"""Return the current app version."""
return self.coordinator.data["system"]["myAppRev"]
@property
@override
def latest_version(self) -> str:
"""Return if there is an update."""
if self.coordinator.data["system"]["needsUpdate"]:
@@ -1,6 +1,6 @@
"""Config flow for AEMET OpenData."""
from typing import Any
from typing import Any, override
from aemet_opendata.exceptions import AuthError
from aemet_opendata.interface import AEMET, ConnectionOptions
@@ -31,6 +31,7 @@ OPTIONS_FLOW = {
class AemetConfigFlow(ConfigFlow, domain=DOMAIN):
"""Config flow for AEMET OpenData."""
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -82,6 +83,7 @@ class AemetConfigFlow(ConfigFlow, domain=DOMAIN):
@staticmethod
@callback
@override
def async_get_options_flow(
config_entry: ConfigEntry,
) -> SchemaOptionsFlowHandler:
@@ -4,7 +4,7 @@ from asyncio import timeout
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import Any, Final, cast
from typing import Any, Final, cast, override
from aemet_opendata.const import (
AOD_CONDITION,
@@ -60,6 +60,7 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
update_interval=WEATHER_UPDATE_INTERVAL,
)
@override
async def _async_update_data(self) -> dict[str, Any]:
"""Update coordinator data."""
async with timeout(API_TIMEOUT):
+2 -1
View File
@@ -1,6 +1,6 @@
"""Support for the AEMET OpenData images."""
from typing import Final
from typing import Final, override
from aemet_opendata.const import AOD_DATETIME, AOD_IMG_BYTES, AOD_IMG_TYPE, AOD_RADAR
from aemet_opendata.helpers import dict_nested_value
@@ -68,6 +68,7 @@ class AemetImage(AemetEntity, ImageEntity):
self._async_update_attrs()
@callback
@override
def _handle_coordinator_update(self) -> None:
"""Update attributes when the coordinator updates."""
self._async_update_attrs()
+2 -1
View File
@@ -3,7 +3,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
from typing import Final
from typing import Final, override
from aemet_opendata.const import (
AOD_CONDITION,
@@ -399,6 +399,7 @@ class AemetSensor(AemetEntity, SensorEntity):
self._attr_unique_id = f"{unique_id}-{description.key}"
@property
@override
def native_value(self):
"""Return the state of the device."""
value = self.get_aemet_value(self.entity_description.keys)
+11
View File
@@ -1,5 +1,7 @@
"""Support for the AEMET OpenData service."""
from typing import override
from aemet_opendata.const import (
AOD_CONDITION,
AOD_FORECAST_DAILY,
@@ -74,47 +76,56 @@ class AemetWeather(
self._attr_unique_id = unique_id
@property
@override
def condition(self) -> str | None:
"""Return the current condition."""
cond = self.get_aemet_value([AOD_WEATHER, AOD_CONDITION])
return CONDITIONS_MAP.get(cond)
@callback
@override
def _async_forecast_daily(self) -> list[Forecast]:
"""Return the daily forecast in native units."""
return self.get_aemet_forecast(AOD_FORECAST_DAILY)
@callback
@override
def _async_forecast_hourly(self) -> list[Forecast]:
"""Return the hourly forecast in native units."""
return self.get_aemet_forecast(AOD_FORECAST_HOURLY)
@property
@override
def humidity(self) -> float | None:
"""Return the humidity."""
return self.get_aemet_value([AOD_WEATHER, AOD_HUMIDITY])
@property
@override
def native_pressure(self) -> float | None:
"""Return the pressure."""
return self.get_aemet_value([AOD_WEATHER, AOD_PRESSURE])
@property
@override
def native_temperature(self) -> float | None:
"""Return the temperature."""
return self.get_aemet_value([AOD_WEATHER, AOD_TEMP])
@property
@override
def wind_bearing(self) -> float | None:
"""Return the wind bearing."""
return self.get_aemet_value([AOD_WEATHER, AOD_WIND_DIRECTION])
@property
@override
def native_wind_gust_speed(self) -> float | None:
"""Return the wind gust speed in native units."""
return self.get_aemet_value([AOD_WEATHER, AOD_WIND_SPEED_MAX])
@property
@override
def native_wind_speed(self) -> float | None:
"""Return the wind speed."""
return self.get_aemet_value([AOD_WEATHER, AOD_WIND_SPEED])
@@ -1,7 +1,7 @@
"""Config flow for AfterShip integration."""
import logging
from typing import Any
from typing import Any, override
from pyaftership import AfterShip, AfterShipException
import voluptuous as vol
@@ -20,6 +20,7 @@ class AfterShipConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
+4 -1
View File
@@ -1,7 +1,7 @@
"""Support for non-delivered packages recorded in AfterShip."""
import logging
from typing import Any, Final
from typing import Any, Final, override
from pyaftership import AfterShip, AfterShipException
@@ -96,15 +96,18 @@ class AfterShipSensor(SensorEntity):
self._attr_name = name
@property
@override
def native_value(self) -> int | None:
"""Return the state of the sensor."""
return self._state
@property
@override
def extra_state_attributes(self) -> dict[str, str]:
"""Return attributes for the sensor."""
return self._attributes
@override
async def async_added_to_hass(self) -> None:
"""Register callbacks."""
self.async_on_remove(
@@ -1,5 +1,7 @@
"""Support for Agent DVR Alarm Control Panels."""
from typing import override
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
@@ -70,23 +72,27 @@ class AgentBaseStation(AlarmControlPanelEntity):
else:
self._attr_alarm_state = AlarmControlPanelState.DISARMED
@override
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
await self._client.disarm()
self._attr_alarm_state = AlarmControlPanelState.DISARMED
@override
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command. Uses custom mode."""
await self._client.arm()
await self._client.set_active_profile(CONF_AWAY_MODE_NAME)
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
@override
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command. Uses custom mode."""
await self._client.arm()
await self._client.set_active_profile(CONF_HOME_MODE_NAME)
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
@override
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command. Uses custom mode."""
await self._client.arm()
@@ -2,6 +2,7 @@
from datetime import timedelta
import logging
from typing import override
from agent import AgentError
@@ -95,6 +96,7 @@ class AgentCamera(MjpegCamera):
}
@property
@override
def is_recording(self) -> bool:
"""Return whether the monitor is recording."""
return self.device.recording
@@ -115,11 +117,13 @@ class AgentCamera(MjpegCamera):
return self.device.connected
@property
@override
def is_on(self) -> bool:
"""Return true if on."""
return self.device.online
@property
@override
def motion_detection_enabled(self) -> bool:
"""Return the camera motion detection status."""
return self.device.detector_active
@@ -132,10 +136,12 @@ class AgentCamera(MjpegCamera):
"""Disable alerts."""
await self.device.alerts_off()
@override
async def async_enable_motion_detection(self) -> None:
"""Enable motion detection."""
await self.device.detector_on()
@override
async def async_disable_motion_detection(self) -> None:
"""Disable motion detection."""
await self.device.detector_off()
@@ -148,6 +154,7 @@ class AgentCamera(MjpegCamera):
"""Stop recording."""
await self.device.record_stop()
@override
async def async_turn_on(self) -> None:
"""Enable the camera."""
await self.device.enable()
@@ -156,6 +163,7 @@ class AgentCamera(MjpegCamera):
"""Take a snapshot."""
await self.device.snapshot()
@override
async def async_turn_off(self) -> None:
"""Disable the camera."""
await self.device.disable()
@@ -1,7 +1,7 @@
"""Config flow to configure Agent devices."""
from contextlib import suppress
from typing import Any
from typing import Any, override
from agent import AgentConnectionError, AgentError
from agent.a import Agent
@@ -20,6 +20,7 @@ DEFAULT_PORT = 8090
class AgentFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle an Agent config flow."""
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
+4 -1
View File
@@ -2,7 +2,7 @@
from collections.abc import AsyncGenerator
import contextlib
from typing import final
from typing import final, override
from propcache.api import cached_property
@@ -30,6 +30,7 @@ class AITaskEntity(RestoreEntity):
@property
@final
@override
def state(self) -> str | None:
"""Return the state of the entity."""
if self.__last_activity is None:
@@ -37,10 +38,12 @@ class AITaskEntity(RestoreEntity):
return self.__last_activity
@cached_property
@override
def supported_features(self) -> AITaskEntityFeature:
"""Flag supported features."""
return self._attr_supported_features
@override
async def async_internal_added_to_hass(self) -> None:
"""Call when the entity is added to hass."""
await super().async_internal_added_to_hass()
+3 -1
View File
@@ -6,7 +6,7 @@ import io
import mimetypes
from pathlib import Path
import tempfile
from typing import Any
from typing import Any, override
import voluptuous as vol
@@ -259,6 +259,7 @@ class GenDataTask:
llm_api: llm.API | None = None
"""API to provide to the LLM."""
@override
def __str__(self) -> str:
"""Return task as a string."""
return f"<GenDataTask {self.name}: {id(self)}>"
@@ -295,6 +296,7 @@ class GenImageTask:
attachments: list[conversation.Attachment] | None = None
"""List of attachments to go along the instructions."""
@override
def __str__(self) -> str:
"""Return task as a string."""
return f"<GenImageTask {self.name}: {id(self)}>"
@@ -1,6 +1,6 @@
"""Config flow for Aidot integration."""
from typing import Any
from typing import Any, override
from aidot.client import AidotClient
from aidot.const import CONF_ID, DEFAULT_COUNTRY_CODE, SUPPORTED_COUNTRY_CODES
@@ -34,6 +34,7 @@ DATA_SCHEMA = vol.Schema(
class AidotConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle aidot config flow."""
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -2,6 +2,7 @@
from datetime import timedelta
import logging
from typing import override
from aidot.client import AidotClient
from aidot.const import (
@@ -48,6 +49,7 @@ class AidotDeviceUpdateCoordinator(DataUpdateCoordinator[DeviceStatusData]):
)
self.device_client = device_client
@override
async def _async_setup(self) -> None:
"""Set up the coordinator."""
self.device_client.on_status_update = self._handle_status_update
@@ -56,6 +58,7 @@ class AidotDeviceUpdateCoordinator(DataUpdateCoordinator[DeviceStatusData]):
"""Handle status callback."""
self.async_set_updated_data(status)
@override
async def _async_update_data(self) -> DeviceStatusData:
"""Return current status."""
return self.device_client.status
@@ -86,6 +89,7 @@ class AidotDeviceManagerCoordinator(DataUpdateCoordinator[None]):
self.client.set_token_fresh_cb(self.token_fresh_cb)
self.device_coordinators: dict[str, AidotDeviceUpdateCoordinator] = {}
@override
async def _async_setup(self) -> None:
"""Set up the coordinator."""
try:
@@ -93,6 +97,7 @@ class AidotDeviceManagerCoordinator(DataUpdateCoordinator[None]):
except AidotUserOrPassIncorrect as error:
raise ConfigEntryError from error
@override
async def _async_update_data(self) -> None:
"""Update data async."""
try:
+5 -1
View File
@@ -1,6 +1,6 @@
"""Support for Aidot lights."""
from typing import Any
from typing import Any, override
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
@@ -78,16 +78,19 @@ class AidotLight(CoordinatorEntity[AidotDeviceUpdateCoordinator], LightEntity):
self._attr_rgbw_color = self.coordinator.data.rgbw
@property
@override
def available(self) -> bool:
"""Return if entity is available."""
return super().available and self.coordinator.data.online
@callback
@override
def _handle_coordinator_update(self) -> None:
"""Update."""
self._update_status()
super()._handle_coordinator_update()
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on, applying brightness, color temperature, RGBW, or plain on."""
if ATTR_BRIGHTNESS in kwargs:
@@ -114,6 +117,7 @@ class AidotLight(CoordinatorEntity[AidotDeviceUpdateCoordinator], LightEntity):
self._attr_is_on = True
self.async_write_ha_state()
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
await self.coordinator.device_client.async_turn_off()
@@ -2,7 +2,7 @@
from datetime import timedelta
import logging
from typing import Final, final
from typing import Final, final, override
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
@@ -131,6 +131,7 @@ class AirQualityEntity(Entity):
@final
@property
@override
def state_attributes(self) -> dict[str, str | int | float]:
"""Return the state attributes."""
data: dict[str, str | int | float] = {}
@@ -142,11 +143,13 @@ class AirQualityEntity(Entity):
return data
@property
@override
def state(self) -> StateType:
"""Return the current state."""
return self.particulate_matter_2_5
@property
@override
def unit_of_measurement(self) -> str:
"""Return the unit of measurement of this entity."""
return CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
@@ -279,7 +279,7 @@
"title": "Air Quality",
"triggers": {
"co2_changed": {
"description": "Triggers after one or more carbon dioxide levels change.",
"description": "Triggers when one or more carbon dioxide levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -288,7 +288,7 @@
"name": "Carbon dioxide level changed"
},
"co2_crossed_threshold": {
"description": "Triggers after one or more carbon dioxide levels cross a threshold.",
"description": "Triggers when one or more carbon dioxide levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -303,7 +303,7 @@
"name": "Carbon dioxide level crossed threshold"
},
"co_changed": {
"description": "Triggers after one or more carbon monoxide levels change.",
"description": "Triggers when one or more carbon monoxide levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -312,7 +312,7 @@
"name": "Carbon monoxide level changed"
},
"co_cleared": {
"description": "Triggers after one or more carbon monoxide sensors stop detecting carbon monoxide.",
"description": "Triggers when one or more carbon monoxide sensors stop detecting carbon monoxide.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -324,7 +324,7 @@
"name": "Carbon monoxide cleared"
},
"co_crossed_threshold": {
"description": "Triggers after one or more carbon monoxide levels cross a threshold.",
"description": "Triggers when one or more carbon monoxide levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -339,7 +339,7 @@
"name": "Carbon monoxide level crossed threshold"
},
"co_detected": {
"description": "Triggers after one or more carbon monoxide sensors start detecting carbon monoxide.",
"description": "Triggers when one or more carbon monoxide sensors start detecting carbon monoxide.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -351,7 +351,7 @@
"name": "Carbon monoxide detected"
},
"gas_cleared": {
"description": "Triggers after one or more gas sensors stop detecting gas.",
"description": "Triggers when one or more gas sensors stop detecting gas.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -363,7 +363,7 @@
"name": "Gas cleared"
},
"gas_detected": {
"description": "Triggers after one or more gas sensors start detecting gas.",
"description": "Triggers when one or more gas sensors start detecting gas.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -375,7 +375,7 @@
"name": "Gas detected"
},
"n2o_changed": {
"description": "Triggers after one or more nitrous oxide levels change.",
"description": "Triggers when one or more nitrous oxide levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -384,7 +384,7 @@
"name": "Nitrous oxide level changed"
},
"n2o_crossed_threshold": {
"description": "Triggers after one or more nitrous oxide levels cross a threshold.",
"description": "Triggers when one or more nitrous oxide levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -399,7 +399,7 @@
"name": "Nitrous oxide level crossed threshold"
},
"no2_changed": {
"description": "Triggers after one or more nitrogen dioxide levels change.",
"description": "Triggers when one or more nitrogen dioxide levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -408,7 +408,7 @@
"name": "Nitrogen dioxide level changed"
},
"no2_crossed_threshold": {
"description": "Triggers after one or more nitrogen dioxide levels cross a threshold.",
"description": "Triggers when one or more nitrogen dioxide levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -423,7 +423,7 @@
"name": "Nitrogen dioxide level crossed threshold"
},
"no_changed": {
"description": "Triggers after one or more nitrogen monoxide levels change.",
"description": "Triggers when one or more nitrogen monoxide levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -432,7 +432,7 @@
"name": "Nitrogen monoxide level changed"
},
"no_crossed_threshold": {
"description": "Triggers after one or more nitrogen monoxide levels cross a threshold.",
"description": "Triggers when one or more nitrogen monoxide levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -447,7 +447,7 @@
"name": "Nitrogen monoxide level crossed threshold"
},
"ozone_changed": {
"description": "Triggers after one or more ozone levels change.",
"description": "Triggers when one or more ozone levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -456,7 +456,7 @@
"name": "Ozone level changed"
},
"ozone_crossed_threshold": {
"description": "Triggers after one or more ozone levels cross a threshold.",
"description": "Triggers when one or more ozone levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -471,7 +471,7 @@
"name": "Ozone level crossed threshold"
},
"pm10_changed": {
"description": "Triggers after one or more PM10 levels change.",
"description": "Triggers when one or more PM10 levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -480,7 +480,7 @@
"name": "PM10 level changed"
},
"pm10_crossed_threshold": {
"description": "Triggers after one or more PM10 levels cross a threshold.",
"description": "Triggers when one or more PM10 levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -495,7 +495,7 @@
"name": "PM10 level crossed threshold"
},
"pm1_changed": {
"description": "Triggers after one or more PM1 levels change.",
"description": "Triggers when one or more PM1 levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -504,7 +504,7 @@
"name": "PM1 level changed"
},
"pm1_crossed_threshold": {
"description": "Triggers after one or more PM1 levels cross a threshold.",
"description": "Triggers when one or more PM1 levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -519,7 +519,7 @@
"name": "PM1 level crossed threshold"
},
"pm25_changed": {
"description": "Triggers after one or more PM2.5 levels change.",
"description": "Triggers when one or more PM2.5 levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -528,7 +528,7 @@
"name": "PM2.5 level changed"
},
"pm25_crossed_threshold": {
"description": "Triggers after one or more PM2.5 levels cross a threshold.",
"description": "Triggers when one or more PM2.5 levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -543,7 +543,7 @@
"name": "PM2.5 level crossed threshold"
},
"pm4_changed": {
"description": "Triggers after one or more PM4 levels change.",
"description": "Triggers when one or more PM4 levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -552,7 +552,7 @@
"name": "PM4 level changed"
},
"pm4_crossed_threshold": {
"description": "Triggers after one or more PM4 levels cross a threshold.",
"description": "Triggers when one or more PM4 levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -567,7 +567,7 @@
"name": "PM4 level crossed threshold"
},
"smoke_cleared": {
"description": "Triggers after one or more smoke sensors stop detecting smoke.",
"description": "Triggers when one or more smoke sensors stop detecting smoke.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -579,7 +579,7 @@
"name": "Smoke cleared"
},
"smoke_detected": {
"description": "Triggers after one or more smoke sensors start detecting smoke.",
"description": "Triggers when one or more smoke sensors start detecting smoke.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -591,7 +591,7 @@
"name": "Smoke detected"
},
"so2_changed": {
"description": "Triggers after one or more sulphur dioxide levels change.",
"description": "Triggers when one or more sulphur dioxide levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -600,7 +600,7 @@
"name": "Sulphur dioxide level changed"
},
"so2_crossed_threshold": {
"description": "Triggers after one or more sulphur dioxide levels cross a threshold.",
"description": "Triggers when one or more sulphur dioxide levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -615,7 +615,7 @@
"name": "Sulphur dioxide level crossed threshold"
},
"voc_changed": {
"description": "Triggers after one or more volatile organic compound levels change.",
"description": "Triggers when one or more volatile organic compound levels change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -624,7 +624,7 @@
"name": "Volatile organic compounds level changed"
},
"voc_crossed_threshold": {
"description": "Triggers after one or more volatile organic compounds levels cross a threshold.",
"description": "Triggers when one or more volatile organic compounds levels cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -639,7 +639,7 @@
"name": "Volatile organic compounds level crossed threshold"
},
"voc_ratio_changed": {
"description": "Triggers after one or more volatile organic compound ratios change.",
"description": "Triggers when one or more volatile organic compound ratios change.",
"fields": {
"threshold": {
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
@@ -648,7 +648,7 @@
"name": "Volatile organic compounds ratio changed"
},
"voc_ratio_crossed_threshold": {
"description": "Triggers after one or more volatile organic compounds ratios cross a threshold.",
"description": "Triggers when one or more volatile organic compounds ratios cross a threshold.",
"fields": {
"behavior": {
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
@@ -2,6 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import override
from airgradient import AirGradientClient, ConfigurationControl
@@ -103,6 +104,7 @@ class AirGradientButton(AirGradientEntity, ButtonEntity):
self._attr_unique_id = f"{coordinator.serial_number}-{description.key}"
@exception_handler
@override
async def async_press(self) -> None:
"""Press the button."""
await self.entity_description.press_fn(self.coordinator.client)
@@ -1,7 +1,7 @@
"""Config flow for Airgradient."""
from collections.abc import Mapping
from typing import Any
from typing import Any, override
from airgradient import (
AirGradientClient,
@@ -42,6 +42,7 @@ class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
if config.configuration_control is ConfigurationControl.NOT_INITIALIZED:
await self.client.set_configuration_control(ConfigurationControl.LOCAL)
@override
async def async_step_zeroconf(
self, discovery_info: ZeroconfServiceInfo
) -> ConfigFlowResult:
@@ -83,6 +84,7 @@ class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
},
)
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -2,6 +2,7 @@
from dataclasses import dataclass
from datetime import timedelta
from typing import override
from airgradient import AirGradientClient, AirGradientError, Config, Measures
@@ -47,6 +48,7 @@ class AirGradientCoordinator(DataUpdateCoordinator[AirGradientData]):
assert self.config_entry.unique_id
self.serial_number = self.config_entry.unique_id
@override
async def _async_setup(self) -> None:
"""Set up the coordinator."""
try:
@@ -60,6 +62,7 @@ class AirGradientCoordinator(DataUpdateCoordinator[AirGradientData]):
translation_placeholders={"error": str(error)},
) from error
@override
async def _async_update_data(self) -> AirGradientData:
try:
measures = await self.client.get_current_measures()
@@ -2,6 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import override
from airgradient import AirGradientClient, Config
from airgradient.models import ConfigurationControl
@@ -119,11 +120,13 @@ class AirGradientNumber(AirGradientEntity, NumberEntity):
self._attr_unique_id = f"{coordinator.serial_number}-{description.key}"
@property
@override
def native_value(self) -> int | None:
"""Return the state of the number."""
return self.entity_description.value_fn(self.coordinator.data.config)
@exception_handler
@override
async def async_set_native_value(self, value: float) -> None:
"""Set the selected value."""
await self.entity_description.set_value_fn(self.coordinator.client, int(value))
@@ -2,6 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import override
from airgradient import AirGradientClient, Config
from airgradient.models import ConfigurationControl, LedBarMode, TemperatureUnit
@@ -215,11 +216,13 @@ class AirGradientSelect(AirGradientEntity, SelectEntity):
self._attr_unique_id = f"{coordinator.serial_number}-{description.key}"
@property
@override
def current_option(self) -> str | None:
"""Return the state of the select."""
return self.entity_description.value_fn(self.coordinator.data.config)
@exception_handler
@override
async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
await self.entity_description.set_value_fn(self.coordinator.client, option)
@@ -2,6 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import override
from airgradient import Config
from airgradient.models import (
@@ -295,6 +296,7 @@ class AirGradientMeasurementSensor(AirGradientSensor):
entity_description: AirGradientMeasurementSensorEntityDescription
@property
@override
def native_value(self) -> StateType:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self.coordinator.data.measures)
@@ -318,6 +320,7 @@ class AirGradientConfigSensor(AirGradientSensor):
)
@property
@override
def native_value(self) -> StateType:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self.coordinator.data.config)
@@ -2,7 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import Any
from typing import Any, override
from airgradient import AirGradientClient, Config
from airgradient.models import ConfigurationControl
@@ -97,17 +97,20 @@ class AirGradientSwitch(AirGradientEntity, SwitchEntity):
self._attr_unique_id = f"{coordinator.serial_number}-{description.key}"
@property
@override
def is_on(self) -> bool:
"""Return the state of the switch."""
return self.entity_description.value_fn(self.coordinator.data.config)
@exception_handler
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
await self.entity_description.set_value_fn(self.coordinator.client, True)
await self.coordinator.async_request_refresh()
@exception_handler
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
await self.entity_description.set_value_fn(self.coordinator.client, False)
@@ -2,6 +2,7 @@
from datetime import timedelta
import logging
from typing import override
from airgradient import AirGradientConnectionError
from propcache.api import cached_property
@@ -42,20 +43,24 @@ class AirGradientUpdate(AirGradientEntity, UpdateEntity):
self._attr_unique_id = f"{coordinator.serial_number}-update"
@cached_property
@override
def should_poll(self) -> bool:
"""Return True because we need to poll the latest version."""
return True
@property
@override
def installed_version(self) -> str:
"""Return the installed version of the entity."""
return self.coordinator.data.measures.firmware_version
@property
@override
def available(self) -> bool:
"""Return if entity is available."""
return super().available and self._attr_available
@override
async def async_update(self) -> None:
"""Update the entity."""
try:
@@ -2,7 +2,7 @@
from asyncio import timeout
from http import HTTPStatus
from typing import Any
from typing import Any, override
from aiohttp import ClientSession
from airly import Airly
@@ -26,6 +26,7 @@ class AirlyFlowHandler(ConfigFlow, domain=DOMAIN):
VERSION = 1
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:

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