Compare commits

...

960 Commits

Author SHA1 Message Date
Michael Hansen 90eeb25419 Merge branch 'dev' into synesthesiam-20250925-aioesphomeapi-bump 2025-09-25 11:00:33 -05:00
Joost Lekkerkerker 7ee31f0884 Bump pySmartThings to 3.3.0 (#152977) 2025-09-25 17:57:30 +02:00
Daniel Potthast 0c5e12571a Update mvglive component (#146479)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-25 17:20:43 +02:00
Luke Lashley 9db973217f Fix incorrect Roborock test (#152980) 2025-09-25 17:18:24 +02:00
Michael Hansen 0e54ce0077 Bump aioesphomeapi to 41.10.0 2025-09-25 09:46:38 -05:00
Artur Pragacz cf1a745283 Move condition-specific fields into options (#152635) 2025-09-25 15:55:50 +02:00
peteS-UK 834e3f1963 Add HassKey for hass.data in Squeezebox (#149129) 2025-09-25 14:05:40 +02:00
Joakim Sørensen 3f8f7573c9 Bump hass-nabucasa from 1.1.1 to 1.1.2 (#152950) 2025-09-25 11:34:14 +01:00
Karsten Bade 0ae272f1f6 Add return types and docstring to sonos component (#152946) 2025-09-25 11:34:38 +02:00
Paul Bottein 8774295e2e Update frontend to 20250925.0 (#152945) 2025-09-25 11:33:01 +02:00
Erwin Douna 0c8d2594ef Portainer fix unique entity (#152941)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-25 09:49:22 +02:00
Simone Chemelli 205bd2676b Update IQS to platinum for Alexa Devices (#152905) 2025-09-25 09:45:50 +02:00
dependabot[bot] 25849fd9cc Bump actions/cache from 4.2.4 to 4.3.0 (#152934)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-25 09:43:03 +02:00
Sab44 7d6eac9ff7 Bump librehardwaremonitor-api to version 1.4.0 (#152938) 2025-09-25 09:42:31 +02:00
Luke Lashley 31017ebc98 Fix logical error when user has no Roborock maps (#152752) 2025-09-25 09:39:52 +02:00
Jimmy Zhening Luo 724a7b0ecc Quality: mark installation param doc as done (#152909) 2025-09-25 09:06:13 +02:00
Paulus Schoutsen 91e13d447a Prevent common control calling async methods from thread (#152931)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-09-24 23:09:54 -04:00
J. Nick Koston 7c8ad9d535 Fix ESPHome reauth not being triggered on incorrect password (#152911) 2025-09-24 22:27:40 -04:00
Franck Nijhof 9cd3ab853d Add block Spook < 4.0.0 as breaking Home Assistant (#152930) 2025-09-24 22:18:06 -04:00
Paulus Schoutsen 0b0f8c5829 Remove some more domains from common controls (#152927) 2025-09-24 22:15:29 -04:00
J. Nick Koston ae7bc7fb1b Bump aioesphomeapi to 41.9.4 (#152923) 2025-09-24 19:16:48 -05:00
Franck Nijhof 09750872b5 Bump version to 2025.11.0dev0 (#152915) 2025-09-24 23:55:32 +02:00
Franck Nijhof 076e51017b Bump to home-assistant/wheels@2025.09.0 (#152920) 2025-09-24 23:12:20 +02:00
Simone Chemelli 95e7b00996 Update IQS to platinum for Comelit SimpleHome (#152906) 2025-09-24 22:03:31 +01:00
J. Nick Koston ddecf1ac21 Bump aioesphomeapi to 41.9.3 to fix segfault (#152912) 2025-09-24 22:00:45 +01:00
Marc Mueller 9cc78680d6 Fix lg_thinq test RuntimeWarning (#152910) 2025-09-24 21:28:49 +03:00
Simone Chemelli 14d42e43bf Add dynamic devices management for Alexa Devices (#151975) 2025-09-24 19:00:35 +02:00
Simone Chemelli ed5f5d4b33 Add dynamic devices management for Comelit SimpleHome (#152137) 2025-09-24 18:57:56 +02:00
Kinachi249 c3ba086fad Add new Cync by GE integration (#149848)
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-24 18:43:50 +02:00
Abílio Costa 7b5314605c Revert "Rename function arguments in modbus (#152814)" (#152904) 2025-09-24 17:25:01 +01:00
Karsten Bade 3a806d6603 Add dc:title support for Sonos sharelinks (#152774)
Co-authored-by: Pete Sage <76050312+PeteRager@users.noreply.github.com>
2025-09-24 17:23:58 +01:00
starkillerOG 6dd33f900d Add support for Reolink chime connected to Home Hub (#151199) 2025-09-24 18:07:23 +02:00
Paul Bottein 2844bd474a Update frontend to 20250924.0 (#152901) 2025-09-24 18:05:13 +02:00
Artur Pragacz d865fcf999 Do not include capabilities in extended analytics (#152900)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2025-09-24 11:58:44 -04:00
Bouwe Westerdijk 79a2fc5a01 Snapshot testing for Plugwise Select platform (#152827) 2025-09-24 17:51:04 +02:00
alorente 19d87abb8a Add Q-Adapt to Airzone integration (#151945) 2025-09-24 17:43:32 +02:00
Joris Pelgröm c4de46a85b Add number platform to LetPot integration (#151092) 2025-09-24 17:41:36 +02:00
epenet e79a434d9b Use DeviceCategory in Tuya remaining platforms (#152890) 2025-09-24 17:39:46 +02:00
Manu 9a801424c7 Fix deleting message filters in ntfy integration (#152783) 2025-09-24 17:38:40 +02:00
Paulus Schoutsen 5cb186980a Mark MQTT as service (#152899) 2025-09-24 11:35:23 -04:00
Ravaka Razafimanantsoa 1629ade97f Add Smart Meter B Route integration (#123446)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-24 17:31:30 +02:00
puddly ccf0011ac2 Skip ignored discovery entries when showing migrate/setup config flow steps for ZHA and Hardware (#152895) 2025-09-24 17:31:04 +02:00
puddly 70077511a3 Unload ZHA integration before adapter migration (#152896) 2025-09-24 17:28:55 +02:00
Petar Petrov dfbaf66021 Add progress step decorator for easier config flows (#152739)
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-09-24 18:18:42 +03:00
Richard Polzer 62cea48a58 Fix typo in ekeybionyx strings.json (#152889) 2025-09-24 15:46:22 +01:00
Michael Hansen c493c7dd67 Bump intents and fix tests (#152893) 2025-09-24 09:24:42 -05:00
Maciej Bieniek fdaceaddfd Add new virtual integration Neo (#152886) 2025-09-24 14:57:22 +02:00
epenet a2f4073d54 Use DeviceCategory in Tuya more platforms (#152885) 2025-09-24 14:40:25 +02:00
epenet 2d01a99ec2 Bump renault-api to 0.4.1 (#152883) 2025-09-24 12:44:33 +01:00
epenet 311d4c4262 Use DeviceCategory in Tuya binary sensor (#152882) 2025-09-24 13:31:44 +02:00
Erik Montnemery e14f5ba44d Fix misleading + unclear comment in homeassistant.const (#152878) 2025-09-24 13:22:32 +02:00
Artur Pragacz 9babc85517 Add analytics to core files (#152877) 2025-09-24 13:21:40 +02:00
Marc Mueller 332a3fad3c Fix mypy errors (#152879) 2025-09-24 13:09:32 +02:00
Michael 8782aa4f60 Hide asserts behind TYPE_CHECKING in Synology DSM (#152880) 2025-09-24 12:49:44 +02:00
jan iversen 475b84cc5f Remove codeowner. (#152869) 2025-09-24 12:43:22 +02:00
Artur Pragacz 0f904d418b Filter out integration types in extended analytics (#152874) 2025-09-24 12:32:30 +02:00
Artur Pragacz 4ea4eec2d8 Remove analytics platform in template (#152876) 2025-09-24 12:32:14 +02:00
Artur Pragacz afefa16615 Remove analytics platform in automation (#152875) 2025-09-24 12:29:33 +02:00
Martin Hjelmare 1dccbee45c Remove hardware flow thread confirm step after install (#152868) 2025-09-24 11:28:10 +01:00
Simone Chemelli 711a56db2f Add dynamic devices management for UptimeRobot (#152139) 2025-09-24 10:56:56 +01:00
Joost Lekkerkerker 9d1c7dadff Make SmartThings AC preset modes translatable (#152833) 2025-09-24 10:55:28 +01:00
Richard Polzer 7d1953e387 Add Ekey Bionyx integration (#139132)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-24 11:54:27 +02:00
Martin Hjelmare 023ecf2a64 Patch async_setup_entry in hardware integration flow tests (#152871) 2025-09-24 11:49:01 +02:00
epenet 934db458a3 Simplify access to Tuya device manager in async_setup_entry (#152859) 2025-09-24 11:47:28 +02:00
epenet 0a6ae3b52a Add enum for Tuya device categories (#152858) 2025-09-24 11:46:33 +02:00
Patrick bdd0b74d51 Enhance Synology DSM handling of external USB drives (#145943)
Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>
2025-09-24 11:26:22 +02:00
Norbert Rittel 8837f2aca7 Capitalize "Auto Cycle Link" as feature name in smartthings (#152864) 2025-09-24 11:11:35 +02:00
Artur Pragacz 403cd2d8ef Filter out custom integrations in extended analytics (#152820) 2025-09-24 10:24:42 +02:00
Erik Montnemery ddfc528d63 Fix apparent copy-paste error in tests of trigger helper (#152855) 2025-09-24 08:38:32 +02:00
Nick Kuiper ddea2206c3 Add start charge session action for blue current integration. (#145446) 2025-09-24 08:11:33 +02:00
J. Nick Koston 32aacac550 Fix async_get_scanner return type for BleakScanner compatibility (#152840) 2025-09-23 23:14:08 -05:00
Luke Lashley dadba274aa Bump python-roborock to 2.47.1 (#152844) 2025-09-23 22:16:32 -04:00
TheJulianJES 14b5b9742c Bump ZHA to 0.0.72 (#152850) 2025-09-23 22:15:00 -04:00
Michael Hansen a0be737925 Auto select first active wake word (#152562) 2025-09-23 17:19:04 -04:00
Marcel van der Veldt ff47839c61 Fix support for new Hue bulbs with very wide color temperature support (#152834) 2025-09-23 16:56:16 -04:00
Copilot 9ba7dda864 Rename logbook integration to "Activity" in user-facing strings (#150950) 2025-09-23 22:55:11 +02:00
J. Nick Koston 911f901d9d Bump aioesphomeapi to 41.9.0 (#152841) 2025-09-23 22:54:31 +02:00
Marcel van der Veldt 2008a73657 Add support for Hue MotionAware sensors (#152811)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-09-23 16:52:09 -04:00
Pete Sage 60bf298ca6 File add read_file action with Response (#139216) 2025-09-23 22:25:56 +02:00
jan iversen 3bc2ea7b5f Use DOMAIN not MODBUS_DOMAIN (#152823) 2025-09-23 22:07:24 +02:00
Kevin Stillhammer 3bac6b86df Fix multiple_here_travel_time_entries issue description (#152839) 2025-09-23 22:06:06 +02:00
Stefan Agner 20293e2a11 Bump aiohasupervisor to 0.3.3b0 (#152835)
Co-authored-by: Claude <noreply@anthropic.com>
2025-09-23 22:05:38 +02:00
Martin Hjelmare 15cc28e6c1 Move first probe firmware to firmware progress in hardware flow (#152819) 2025-09-23 22:03:04 +02:00
puddly 874ca1323b Simplified ZHA adapter migration and setup flow (#152389) 2025-09-23 22:00:31 +02:00
Ludovic BOUÉ ca186925af Add Matter Thermostat OutdoorTemperature sensor (#152632) 2025-09-23 21:28:24 +02:00
andreimoraru 2ab051b716 Bump yt-dlp to 2025.09.23 (#152818) 2025-09-23 20:03:53 +01:00
epenet a2a726de34 Rename function arguments in modbus (#152814) 2025-09-23 20:54:52 +02:00
Sarah Seidman 5d543d2185 Bump pydroplet version to 2.3.3 (#152832) 2025-09-23 19:36:06 +01:00
epenet a78c909b34 Rename cover property in tuya (#152822) 2025-09-23 19:35:47 +01:00
Artur Pragacz f00ab80d17 Add analytics platform to template (#152824) 2025-09-23 13:53:53 -04:00
Joakim Sørensen 014881d985 Fix error handling in subscription info retrieval and update tests (#148397)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-23 19:53:12 +02:00
Artur Pragacz 29a42a8e58 Add analytics platform to automation (#152828) 2025-09-23 13:52:58 -04:00
Rohan Kapoor 3f70084d7f Handle ignored and disabled entries correctly in zeroconf discovery for Music Assistant (#152792)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-23 10:15:52 -07:00
Felipe Santos b1ae9c95c9 Add a switch entity for add-ons (#151431)
Co-authored-by: Stefan Agner <stefan@agner.ch>
2025-09-23 17:27:35 +02:00
Artur Pragacz 8be79ecdb0 Move conversation trigger registration to manager (#152749) 2025-09-23 10:01:46 -05:00
Jan Bouwhuis f6b8aa893b Add mqtt image subentry support (#151586) 2025-09-23 16:31:40 +02:00
jan iversen c867026bdd Add test to validate multiple host/port for modbus. (#152658)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2025-09-23 16:03:42 +02:00
Kevin Stillhammer da3a164e66 Change here_travel_time update interval to 30min (#147222) 2025-09-23 15:56:13 +02:00
Josef Zweck 32688e1108 Bump aioacaia to 0.1.17 (#152815) 2025-09-23 15:29:16 +02:00
Artur Pragacz 4305ea9b4c Create analytics platform (#151974) 2025-09-23 09:16:37 -04:00
epenet 61153ec456 Deduplicate code in modbus service call (#152808)
Co-authored-by: jan iversen <jancasacondor@gmail.com>
2025-09-23 13:44:28 +02:00
Marcel van der Veldt 9e4a2d5fa9 Bump aiohue to 4.8.0 (#152807) 2025-09-23 13:39:58 +02:00
Marcel van der Veldt 72e608918b Handle toggling of the 'expose_to_ha' setting in Music Assistant integration (#152779) 2025-09-23 13:22:16 +02:00
Erik Montnemery 86db60c442 Freeze time in irm_kmi tests (#152810) 2025-09-23 13:21:59 +02:00
cdnninja 25806615a9 Bump pyvesync to 3.0.0 (#152726) 2025-09-23 13:00:59 +02:00
Paulus Schoutsen a0f67381e5 Allow configuring Z-Wave JS to talk via ESPHome (#152590)
Co-authored-by: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-09-23 12:58:36 +02:00
Jan Čermák 90bfadda9b Support all reported preset modes in Smartthings climate (#148056)
Co-authored-by: abmantis <amfcalt@gmail.com>
2025-09-23 12:56:27 +02:00
Maciej Bieniek 0f8e700965 Add a cable unplugged sensor for Shelly Flood Gen4 (#152559) 2025-09-23 12:55:44 +02:00
Jan Čermák 21d4ed2837 Add profiler service for dumping sockets used by HA (#152440)
Co-authored-by: Stefan Agner <stefan@agner.ch>
2025-09-23 12:55:29 +02:00
Luke Lashley ce363b3835 Make Roborock load_multi_map always cloud dependent. (#152698) 2025-09-23 12:55:07 +02:00
G Johansson dd3e6b8df5 Only load selected processes in systemmonitor (#152777) 2025-09-23 12:41:31 +02:00
epenet abbf8390ac Move switch to valve for Tuya sfkzq category (#152478) 2025-09-23 12:39:37 +02:00
epenet 689039959c Improve current_state support in Tuya curtains (#152801) 2025-09-23 12:38:47 +02:00
epenet 52c25cfc88 Rename modbus internal variable (#152805) 2025-09-23 12:14:05 +02:00
G Johansson 00b2017767 Fix resource and payload template in scrape (#152670) 2025-09-23 11:59:00 +02:00
Martin Hjelmare dd7f7be6ad Move hardware thread add-on install after firmware install (#152800) 2025-09-23 11:47:30 +02:00
Robert Resch 22709506c6 Add Ecovacs custom water amount entity (#152782)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-23 11:21:11 +02:00
Lukas f0c0492375 Add MAC address to Pooldose device (#152760)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-23 11:11:08 +02:00
Robert Resch 58459cb80f Bump deebot-client to 14.0.0 (#152448) 2025-09-23 10:47:37 +02:00
epenet a19e378447 Add Tuya test fixture files (#152795) 2025-09-23 10:44:36 +02:00
J. Nick Koston 38a5a3ed4b Handle wrong ESPHome device without encryption appearing at the configured IP (#152758) 2025-09-23 10:27:13 +02:00
Matthias Lohr e76bed4a83 Add reconfigure flow to tolo (#137609)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2025-09-23 10:21:06 +02:00
Karsten Bade d73309ba60 Bump SoCo to 0.30.12 (#152797) 2025-09-23 09:49:33 +02:00
Przemko92 19fdea024c Bump compit-inext-api to 0.3.1 (#152781) 2025-09-23 09:48:53 +02:00
Manu a3cfd7f707 Fix coordinator data handling in Bring integration (#152786) 2025-09-23 09:03:01 +02:00
Petro31 3dd941eff7 Fix section and entity variable resolution for template platforms (#149660)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-23 08:12:24 +02:00
J. Nick Koston d389141aee Bump aioesphomeapi to 41.6.0 (#152787) 2025-09-22 21:43:20 -05:00
Rohan Kapoor 3c542b8d43 Only update Music Assistant URL on zeroconf discovery when current URL is unreachable (#152030) 2025-09-22 13:49:41 -07:00
starkillerOG 2367df89d9 Bump reolink-aio to 0.15.2 (#152775) 2025-09-22 21:39:06 +01:00
Manu 7bfdfb3fc7 Bump pynecil to v4.2.0 (#152776) 2025-09-22 21:35:19 +01:00
G Johansson 485916265a Fix manual updating of Nord Pool sensors (#152773) 2025-09-22 22:04:17 +02:00
Stefan Agner 1bb3c96fc1 Drop Windows compatibility code from systemmonitor integration (#152545) 2025-09-22 21:26:26 +02:00
Artur Pragacz 4eaf6784af Use satellite entity area in the default agent (#152762) 2025-09-22 13:34:31 -05:00
Abílio Costa 7b7265a6b0 Revert "Add EZVIZ battery camera power status and online status sensor (#146822)" (#152767) 2025-09-22 19:03:32 +02:00
Thomas D 9059e3dadc Prepare Volvo integration for new platforms (#152042) 2025-09-22 18:41:44 +02:00
J. Nick Koston d9d42b3ad5 Pass timezone to aioesphomeapi to ensure HA timezone takes precedence (#152756) 2025-09-22 09:54:15 -06:00
epenet d565fb3cb4 Bump mcp to 1.14.1 (#152737) 2025-09-22 17:33:48 +02:00
G Johansson 6e93e480d1 Use automatic reload options flow in integration (#152686) 2025-09-22 15:27:19 +01:00
Maciej Bieniek 5a3570702d Add re-auth flow to AccuWeather integration (#152755) 2025-09-22 16:27:09 +02:00
Abílio Costa b26b1df143 Fix unitless converter missing valid units (#152665) 2025-09-22 15:19:31 +01:00
Manu fdbff76733 Add collapse checklist field to Habitica create/update task actions (#150988) 2025-09-22 16:16:47 +02:00
epenet 018d59a892 Drop hass argument from service extraction helpers (#152738) 2025-09-22 16:08:07 +02:00
Andrew Jackson 4b6dd0eb8f Add optional language to Mastodon post action (#151072) 2025-09-22 16:01:09 +02:00
Wendelin b7db87bd3d Update regex for core logs path to include latest logs (#152747) 2025-09-22 14:07:49 +01:00
Jules Dejaeghere 86dc453c55 Add integration for Belgian weather provider meteo.be (#144689)
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-22 13:28:41 +02:00
Abílio Costa a4f2c88c7f Add TriggerConfig to reduce ambiguity (#152563) 2025-09-22 12:24:47 +01:00
Erik Montnemery 3cdb894e61 Small improvement of exposed_entities test (#152744) 2025-09-22 13:16:02 +02:00
Bouwe Westerdijk cb837aaae5 Number snapshot testing for Plugwise (#152673) 2025-09-22 11:55:57 +02:00
G Johansson 82443ded34 Use already cached data in Nord Pool if valid (#152664) 2025-09-22 11:55:00 +02:00
Retha Runolfsson 71cc3b7fcd Add K11+ Vacuum for switchbot integration (#152643) 2025-09-22 11:51:39 +02:00
G Johansson e5658f9747 Use automatic reload options flow in statistics (#152682) 2025-09-22 11:48:58 +02:00
G Johansson 868ded141f Use automatic reload options flow in threshold (#152684) 2025-09-22 11:48:37 +02:00
LG-ThinQ-Integration 1151fa698d Add energy usage sensors of ThinQ devices. (#152141)
Co-authored-by: yunseon.park <yunseon.park@lge.com>
2025-09-22 11:47:18 +02:00
Paulus Schoutsen 2796d6110a Split up media source integration (#152721)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-22 11:46:24 +02:00
Tom Matheussen 844b97bd32 Add Satel Integra diagnostics (#152621)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-22 11:38:26 +02:00
Lukas 286b2500bd Pooldose: Add Dhcp discovery (#152253)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-22 11:31:40 +02:00
Joshua Leaper 4b7746ab51 Bump nessclient to 1.3.1 (#152700) 2025-09-22 11:01:04 +03:00
Abílio Costa ca1c366f4f Remove unused var from llm helper (#152724) 2025-09-22 09:57:16 +02:00
epenet de42ac14ac Drop unused hass argument from internal helper (#152733) 2025-09-22 09:56:52 +02:00
J. Nick Koston 7f7bd5a97f Bump aioesphomeapi to 41.5.0 (#152730) 2025-09-22 09:56:20 +02:00
epenet 8a70a1badb Drop hass argument from verify_domain_control (#147946) 2025-09-22 08:15:41 +02:00
Shay Levy 181741cab6 Use component role in Shelly sensor platform (#152710)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-22 01:03:29 +03:00
Maciej Bieniek 1e14fb6dab Use the common unique_id schema in the Shelly button platform (#152707) 2025-09-21 19:34:50 +02:00
Maciej Bieniek 2b6a125927 Support Shelly presencezone component (#152393)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
Co-authored-by: Simone Chemelli <simone.chemelli@gmail.com>
2025-09-21 19:27:40 +02:00
Abílio Costa e61ad10708 Split sensor unit long condition (#152668) 2025-09-21 16:49:13 +01:00
Shay Levy 5177f9e8c2 Add support for Shelly object based entities (#152046)
Co-authored-by: Simone Chemelli <simone.chemelli@gmail.com>
2025-09-21 17:08:43 +03:00
Luke Lashley 850aeeb5eb Explicitly connect to the Roborock API before sending messages (#152697) 2025-09-21 12:37:15 +02:00
J. Nick Koston a1b9061060 Bump aiohomekit to 3.2.18 (#152694) 2025-09-21 12:14:21 +02:00
Maciej Bieniek 0ec1f27489 Use DeviceClass.PM4 in NAM integration (#152703) 2025-09-21 11:59:09 +02:00
J. Diego Rodríguez Royo befc93bc73 Delete Home Connect alarm clock entity from time platform (#152188) 2025-09-21 10:23:51 +01:00
Luke Lashley 1526d953bf Make Roborock A01 initilization threadsafe (#152699) 2025-09-21 07:52:26 +02:00
G Johansson d38082a5c8 Use automatic reload options flow in Scrape (#152681) 2025-09-20 22:02:23 +01:00
G Johansson 42850421d2 Use automatic reload options flow in wake_on_lan (#152683) 2025-09-20 22:01:11 +01:00
avee87 21a835c4b4 Expose pressure as a separate sensor for metoffice (#152685) 2025-09-20 21:59:14 +01:00
Manu e9294dbf72 Bump pyecotrend-ista to v3.4.0 (#152678) 2025-09-20 21:52:51 +01:00
Daniel Hjelseth Høyer 5c4dfbff1b Update Tibber lib 0.32.1 (#152677) 2025-09-20 20:52:24 +02:00
G Johansson abe628506d Use OptionsFlowWithReload in pvpc_hourly_pricing (#151255) 2025-09-20 18:45:06 +02:00
Franck Nijhof 12cc0ed18d Refactor template engine: Extract raise_no_default() into helper module (#152661)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-20 17:20:05 +01:00
Franck Nijhof 8ca7562390 Merge branch 'master' into dev 2025-09-20 14:28:37 +00:00
GSzabados 942f7eebb1 Add PM4 device class for Ecowitt (#152568) 2025-09-20 14:40:21 +02:00
Franck Nijhof 1a167e6aee Refactor template engine: Extract context and render info (#152630) 2025-09-20 14:15:24 +02:00
Stephan van Rooij 9531ae10f2 Remove volvooncall (#150725)
Co-authored-by: G Johansson <goran.johansson@shiftit.se>
2025-09-20 14:08:53 +02:00
tronikos bfc9616abf Deprecate google_generative_ai_conversation.generate_content (#152644) 2025-09-20 07:50:31 -04:00
Jan Bouwhuis 054a5d751a Organize order MQTT subentry (test) globals and translation strings (#152576) 2025-09-20 13:24:30 +02:00
Andrea Turri a43ba4f966 Miele add new program phase mapping (#152647) 2025-09-20 11:33:12 +02:00
J. Nick Koston 1a5cae125f Handle unparsable responses during HomeKit Controller initial polling (#152636) 2025-09-19 22:51:21 -05:00
Franck Nijhof f3b9bda876 2025.9.4 (#152634) 2025-09-19 23:08:58 +02:00
Yevhenii Vaskivskyi 3f3aaa2815 Bump asusrouter to 1.21.0 (#151607) 2025-09-19 20:38:05 +00:00
Franck Nijhof 6dc7870779 Bump version to 2025.9.4 2025-09-19 20:07:56 +00:00
G Johansson be83416c72 Bump holidays to 0.81 (#152569) 2025-09-19 20:07:27 +00:00
G Johansson c745ee18eb Bump holidays to 0.80 (#152306) 2025-09-19 20:07:25 +00:00
tronikos cf907ae196 Bump opower to 0.15.5 (#152531) 2025-09-19 20:05:04 +00:00
Pete Sage 8eee53036a Fix Sonos set_volume float precision issue (#152493) 2025-09-19 20:00:42 +00:00
Alexandre CUER b37237d24b Bump pyemoncms to 0.1.3 (#152436) 2025-09-19 20:00:41 +00:00
Matthias Alphart 950e758b62 Fix KNX UI schema missing DPT (#152430) 2025-09-19 20:00:40 +00:00
Josef Zweck 9cd940b7df Add La Marzocco specific client headers (#152419) 2025-09-19 20:00:38 +00:00
Josef Zweck 10b186a20d Bump pylamarzocco to 2.1.0 (#152364) 2025-09-19 20:00:37 +00:00
Imeon-Energy 757aec1c6b Bump imeon_inverter_api to 0.4.0 (#152351)
Co-authored-by: TheBushBoy <theodavid@icloud.com>
2025-09-19 20:00:36 +00:00
Allen Porter 0b159bdb9c Update authorization server to prefer absolute urls (#152313)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-19 20:00:34 +00:00
J. Nick Koston 8728312e87 Bump aiohomekit to 3.2.17 (#152297) 2025-09-19 20:00:33 +00:00
Åke Strandberg bbb67db354 Add proper error handling for /actions endpoint for miele (#152290) 2025-09-19 20:00:31 +00:00
J. Nick Koston 265f5da21a Bump bluetooth-auto-recovery to 1.5.3 (#152256) 2025-09-19 20:00:30 +00:00
J. Nick Koston 54859e8a83 Bump aiohomekit to 3.2.16 (#152255) 2025-09-19 20:00:28 +00:00
Sean Dague c87dba878d Upgrade waterfurnace to 1.2.0 (#152241) 2025-09-19 20:00:27 +00:00
J. Nick Koston 8d8e008123 Fix HomeKit Controller overwhelming resource-limited devices by batching characteristic polling (#152209) 2025-09-19 20:00:25 +00:00
Yevhenii Vaskivskyi b30667a469 Fix bug with the hardcoded configuration_url (asuswrt) (#151858) 2025-09-19 20:00:23 +00:00
Manu 8920c548d5 Bump habiticalib to v0.4.5 (#151720) 2025-09-19 20:00:22 +00:00
Manu eac719f9af Bump habiticalib to v0.4.4 (#151332) 2025-09-19 20:00:20 +00:00
Aidan Timson 71c274cb91 Add power usage sensor to System Bridge (#152625) 2025-09-19 21:16:30 +02:00
Retha Runolfsson d4902361e6 Bump pySwitchbot to 0.71.0 (#152597) 2025-09-19 22:04:42 +03:00
Norbert Rittel f63eee3889 Fix typo and sentence-casing in honeywell exception string (#152619) 2025-09-19 17:07:46 +02:00
Aidan Timson 21bfe610d1 Update systembridgeconnector to 5.1.0 (#152623) 2025-09-19 17:07:15 +02:00
J. Nick Koston 21c174e895 Bump aioesphomeapi to 41.4.0 (#152618)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2025-09-19 08:20:00 -06:00
Simon Roberts ec148e0459 Add PM4 (particulates < 4μm) sensor and number device classes (#112867)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-09-19 08:12:09 -06:00
Maciej Bieniek 286763b998 Fix KeyError for Shelly Duo Bulb Gen3 (#152612) 2025-09-19 07:22:48 -06:00
Shay Levy 5f88122a2b Fix Shelly Wall Display virtual button platform (#152582) 2025-09-19 11:44:08 +03:00
Åke Strandberg 31968d16ab Refactor miele program phase codes part 2(3) (#144180) 2025-09-19 09:54:24 +02:00
epenet c125554817 Rename modbus base entities (#152595) 2025-09-19 09:17:31 +02:00
Abílio Costa 10f2955d34 Update Whirlpool quality scale to silver (#152505) 2025-09-19 08:30:10 +02:00
Paulus Schoutsen 55712b784c Bump aioesphomeapi to 41.3.0 (#152588) 2025-09-18 22:49:03 -04:00
Paulus Schoutsen fe3a929556 Fix reolink test (#152587) 2025-09-18 21:03:13 -04:00
J. Nick Koston 534801e80d Migrate yale and august integrations to use new lock API (#152579) 2025-09-18 17:20:38 -05:00
J. Nick Koston 8aeda5a0c0 Bump aioesphomeapi to 41.2.0 (#152578) 2025-09-19 01:03:59 +03:00
Ville Skyttä eb1cbbc75c Upgrade upcloud-api to 2.8.0 (#152577) 2025-09-19 01:03:31 +03:00
Przemko92 fa8a4d7098 Add Compit integration (#132164)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-18 21:53:49 +01:00
Andre Lengwenus 2623ebac4d Bump pypck to 0.8.12 (#152573) 2025-09-18 23:34:37 +03:00
Michael Hansen 1746c51ce4 Fix error with pipeline device removal due to multiple selects (#152560) 2025-09-18 14:34:03 -05:00
Joakim Sørensen 8b984a2105 Remove ludeeus as a codeowner for analytics (#152558) 2025-09-18 22:08:22 +03:00
Allen Porter ebee370a56 Bump python roborock to 2.44.1 (#152557) 2025-09-18 21:51:16 +03:00
starkillerOG dabd096587 Add color temperature support to Reolink light entity (#152546) 2025-09-18 21:48:18 +03:00
Simone Chemelli 21399818af Remove stale devices for Comelit SimpleHome (#151519) 2025-09-18 19:43:38 +01:00
G Johansson 4354214fbf Bump holidays to 0.81 (#152569) 2025-09-18 20:35:21 +02:00
Erik Montnemery 5bd39804f1 Remove EntityComponent.async_register_legacy_entity_service (#152539) 2025-09-18 20:34:25 +02:00
Norbert Rittel 6d3ad3ab9c Replace "iCloud account" with "Apple Account" (#152561) 2025-09-18 18:39:54 +02:00
Petar Petrov 4c212bdcd4 Enable thread migration for ZBT integration (#152550) 2025-09-18 18:33:06 +03:00
Petar Petrov b91b39580f Add migrate options to ZBT protocol picker (#152532) 2025-09-18 11:13:58 -04:00
Jan Bouwhuis 472d70b6c9 Add comment on conversion factor for Carbon monoxide on dependency molecular weight (#152535) 2025-09-18 15:36:12 +02:00
tronikos 017a84a859 Bump opower to 0.15.5 (#152531) 2025-09-18 14:29:27 +03:00
starkillerOG d184540967 Bump reolink-aio to 0.15.1 (#152533) 2025-09-18 14:28:16 +03:00
Erik Montnemery 1740984b3b Improve comments in SelectedEntities (#152540) 2025-09-18 14:12:33 +03:00
droans 4db8592c61 Add support for overriding entity_picture to universal (#149387) 2025-09-18 11:59:29 +02:00
Stefan Agner 27e630c107 Make systemmonitor tests timezone independent (#152537) 2025-09-18 12:58:09 +03:00
Åke Strandberg ea8833342d Bump dependency pymiele to v0.5.5 and subsequent code changes (#152534) 2025-09-18 10:33:55 +02:00
epenet 87be2ba823 Use compat UOM in _is_valid_suggested_unit (#152350)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-18 08:38:15 +02:00
Artur Pragacz 51c35eb631 Move default conversation agent to manager (#152479) 2025-09-18 08:22:56 +02:00
Samuel Xiao 24a86d042f Bumb switchbot api to v2.8.0 (#152506) 2025-09-18 07:46:51 +02:00
Manu cd6f653123 Bump aiontfy to v0.6.0 (#152520) 2025-09-18 07:45:22 +02:00
J. Nick Koston fd05ddca28 Bump yalexs to 9.2.0 (#152527) 2025-09-18 07:43:54 +02:00
Artur Pragacz a1f2eb44ae Move trigger-specific fields into options in new-style triggers (#151314) 2025-09-18 07:35:39 +02:00
Samuel Xiao c4ddc03dbc Update codeowner for switchbot cloud Integration (#152526) 2025-09-17 22:54:22 -05:00
J. Nick Koston 9db5aafb71 Bump yalexs to 9.1.0 (#152457) 2025-09-17 22:11:35 -05:00
Ivan Lopez Hernandez 64cdcfb613 Bump google-genai to 1.38.0 (#152523) 2025-09-17 22:14:04 -04:00
Paulus Schoutsen c761ce699c Tweak usage prediction common control algorithm (#152490) 2025-09-17 19:04:25 -04:00
Martin Hjelmare 40ebce4ae8 Improve Home Assistant Hardware flow (#152451)
Co-authored-by: puddly <32534428+puddly@users.noreply.github.com>
2025-09-17 18:23:38 -04:00
puddly 29914d6722 Bump ZHA to 0.0.71 (#152511) 2025-09-17 18:23:08 -04:00
Jan Bouwhuis 5eef6edded Add mg/m³ as a valid UOM for sensor/number Carbon Monoxide device class (#152456) 2025-09-17 22:04:23 +01:00
epenet db729273a5 Add pymodbus to PACKAGE_CHECK_VERSION_RANGE (#152494) 2025-09-17 17:22:45 +02:00
Abílio Costa 946d75d651 Merge similar Whirlpool init tests (#152497) 2025-09-17 17:18:54 +02:00
Abílio Costa 093f779edb Remove target humidity methods from Whirlpool climate (#152498) 2025-09-17 17:18:20 +02:00
Paulus Schoutsen 87658e77a7 Clean up stale comment in AI Task test (#152492) 2025-09-17 17:17:20 +02:00
dontinelli 38f65cda98 Bump solarlog_cli to 0.6.0 (#152500) 2025-09-17 16:02:51 +01:00
Jan Čermák 797c6ddedd Fix APT cache restore failures in CI (#152481)
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
2025-09-17 16:52:09 +02:00
NANI fe8a53407a Add Victron Remote Monitoring integration (#143687)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-09-17 16:38:04 +02:00
Abílio Costa ae5f57fd99 Add unique_id to Whirlpool config entry mock (#152496) 2025-09-17 14:38:53 +01:00
Abílio Costa a93c3cc23c Make Whirlpool log when entity goes unavailable (#152064) 2025-09-17 15:00:23 +02:00
Pete Sage 804b42e1fb Fix Sonos set_volume float precision issue (#152493) 2025-09-17 14:39:28 +02:00
karwosts a4f15e4840 Add debug logging to derivative (#152489) 2025-09-17 14:19:48 +02:00
Pete Sage 2471177c84 Set Sonos quality scale to bronze (#152487) 2025-09-17 14:16:08 +02:00
Yuxin Wang a494d3ec69 Sort the resources for deterministic sensor addition order in APCUPSD (#152467) 2025-09-17 10:41:19 +02:00
Paulus Schoutsen b10a9721a7 Add async_get_image helper to Image integration (#152465) 2025-09-17 10:35:55 +02:00
Paulus Schoutsen 04c0bb20d6 AI Task to store generated images in media dir (#152463) 2025-09-17 10:30:15 +02:00
Paulus Schoutsen 1598c4ebe8 Bump aioesphomeapi to 41.1.0 (#152461)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-09-16 20:18:54 -04:00
karwosts d67ec7593a Add diagnostics to history_stats (#152460) 2025-09-17 00:02:35 +01:00
Franck Nijhof 4a4c124181 Refactor template engine: Extract collection & data structure functions into CollectionExtension (#152446) 2025-09-16 18:48:50 -04:00
Franck Nijhof c34af4be86 Add active built-in and custom integrations to Cloud support package (#152452) 2025-09-16 18:47:00 -04:00
GSzabados 823071b722 Add LDS01 support (#151820)
Co-authored-by: Robert Resch <robert@resch.dev>
2025-09-16 21:33:47 +02:00
Daniel Jansen 462fa77ba1 Improve waze_travel_time tests (#146495)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-16 21:24:51 +02:00
Yevhenii Vaskivskyi 24fc8b9297 Fix bug with the hardcoded configuration_url (asuswrt) (#151858) 2025-09-16 21:18:29 +02:00
Paulus Schoutsen 2596ab2940 OpenAI to use provided mimetype when available (#152407) 2025-09-16 22:11:46 +03:00
Robert Resch 23fa84e20e Verify that Ecovacs integration is setup without any errors in the tests (#152447) 2025-09-16 20:55:44 +02:00
Shay Levy 7f13141297 Bump aioshelly 13.10.0 (#152442) 2025-09-16 21:25:09 +03:00
karwosts 770f41d079 Diagnostics for derivative sensor (#152445) 2025-09-16 14:24:05 -04:00
Shay Levy df16e85359 Fix typo in update_not_available key in Shelly strings (#152444) 2025-09-16 14:23:10 -04:00
Nathan Spencer 3c6db923a3 Deprecate Litter-Robot 4 night light mode switch (#152249) 2025-09-16 20:18:26 +02:00
Thomas D 450c47f932 Use new method to get the access token in the Volvo integration (#151625)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-16 20:17:43 +02:00
Norbert Rittel 048f64eccf Improve two unsupported_xxx issue descriptions in hassio (#152387)
Co-authored-by: Stefan Agner <stefan@agner.ch>
2025-09-16 19:52:12 +02:00
Maciej Bieniek c4c523e8b7 Open a repair issue if Shelly Wall Display firmware is older than 2.3.0 (#152399) 2025-09-16 19:48:47 +02:00
Matthias Alphart 87e30e0907 Fix KNX UI schema missing DPT (#152430) 2025-09-16 19:39:39 +02:00
Alexandre CUER 74660da2d2 Bump pyemoncms to 0.1.3 (#152436) 2025-09-16 18:32:13 +02:00
Maciej Bieniek 6b8c180509 Bump imgw_pib to version 1.5.6 (#152435) 2025-09-16 18:30:22 +02:00
Alessandro Manighetti eb4a873c43 Add m/min of speed sensors (#146441) 2025-09-16 18:02:22 +02:00
G Johansson 6aafa666d6 Add calendar to Workday (#150596) 2025-09-16 17:29:04 +02:00
Mike Degatano 9ee9bb368d Move Supervisor created persistent notifications into repairs (#152066) 2025-09-16 11:24:48 -04:00
Tom Matheussen 6e4258c8a9 Add Satel Integra config flow (#138946)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
2025-09-16 17:24:15 +02:00
Paulus Schoutsen d65e704823 Add usage_prediction integration (#151206)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-09-16 10:33:46 -04:00
Retha Runolfsson aadaf87c16 Add switchbot relayswitch 2PM (#146140) 2025-09-16 15:59:13 +02:00
Timothy e70b147c0c Add missing content type to backup http endpoint (#152433) 2025-09-16 09:45:21 -04:00
yufeng 031b12752f Add sensors for Tuya energy storage systems (xnyjcn) (#149237)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2025-09-16 15:34:21 +02:00
Samuel Xiao df0cfd69a9 Add Climate Panel support to Switchbot Cloud (#152427) 2025-09-16 14:14:09 +02:00
marc7s b2c53f2d78 Add geocaching cache sensors (#145453) 2025-09-16 14:13:54 +02:00
Rafael López Diez 3649e949b1 Add support for sending chat actions in Telegram bot integration (#151378) 2025-09-16 14:06:15 +02:00
Rafael López Diez de7e2303a7 Add support for multi-tap action in Lutron Caseta integration (#150551) 2025-09-16 13:32:10 +02:00
onsmam 892f3f267b Added rain_start and lightningstrike event to publish on the event bus (#146652)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-16 13:31:43 +02:00
Marc Mueller 0254285285 Fix warning in template extensions tests (#152425) 2025-09-16 13:30:36 +02:00
Chris Oldfield 44a95242dc Add downloading and seeding counts to Deluge (#150623) 2025-09-16 13:06:14 +02:00
Marc Mueller f9b1c52d65 Fix warning in prowl tests (#152424) 2025-09-16 12:42:37 +02:00
Josef Zweck aa8d78622c Add La Marzocco specific client headers (#152419) 2025-09-16 13:15:57 +03:00
Franck Nijhof ca6289a576 Refactor template engine: Extract string functions into StringExtension (#152420) 2025-09-16 13:15:43 +03:00
Erik Montnemery 0f372f4b47 Improve condition schema validation (#144793) 2025-09-16 10:44:26 +02:00
Franck Nijhof 4bba167ab3 Refactor template engine: Extract regex functions into RegexExtension (#152417) 2025-09-16 10:38:01 +02:00
Jan-Philipp Benecke 962c0c443d Improve setup completion message of Improv BLE (#152412) 2025-09-16 10:37:47 +02:00
Duco Sebel c6b4cac28a Remember HomeWizard uptime sensor value as timestamp to prevent it spamming the state (#150680)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-16 10:29:37 +02:00
dependabot[bot] 3c7e3a5e30 Bump home-assistant/builder from 2025.03.0 to 2025.09.0 (#152413)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-16 10:28:49 +02:00
Maciej Bieniek fa698956c3 Fix the illuminance level entity name in Shelly integration (#152400)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
2025-09-16 10:16:43 +02:00
Klaas Schoute 32f136b12f Update P1 Monitor integration to use settings method during config flow (#152391) 2025-09-16 10:11:29 +02:00
Josef Zweck e1f617df25 Bump pylamarzocco to 2.1.0 (#152364) 2025-09-16 10:08:08 +02:00
Tomeroeni 84f1b8a5cc Bump aiounifi version to 87 (#152395) 2025-09-16 10:04:06 +02:00
kylehakala e9cedf4852 Bump aioridwell to 2025.09.0 (#152405) 2025-09-16 10:01:50 +02:00
kingy444 9c72b40ab4 Bump HunterDouglas_Powerview dependency to aiopvapi 3.2.1 (#152409) 2025-09-16 09:58:41 +02:00
Marcus Gustavsson 65f655e5f5 Change Prowl to use the prowlpy library and add tests for the Prowl component (#149034)
Co-authored-by: Joostlek <joostlek@outlook.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-16 09:23:08 +02:00
Erik Montnemery af28573894 Refactor zwave js event trigger (#144885) 2025-09-16 07:49:09 +02:00
Jan-Philipp Benecke c5fc1de3df Update url in success message of Improv BLE to use markdown (#152388) 2025-09-15 19:50:19 +01:00
karwosts 1df1144eb9 Add 'stations near me' to radio browser (#150907) 2025-09-15 14:47:16 -04:00
Artur Pragacz d51c0e3752 Revert "Add Matter service actions for vacuum area (#151467)" (#152386) 2025-09-15 20:14:09 +02:00
Ernst Klamer f5157878c2 Bthome encryption fix (#152384) 2025-09-15 20:46:43 +03:00
Lennard Beers fb723571b6 Bump eq3btsmart to 2.3.0 (#152383) 2025-09-15 18:36:12 +01:00
puddly dbf80c3ce3 Bump universal-silabs-flasher to 0.0.32 (#152381) 2025-09-15 19:10:52 +02:00
Joost Lekkerkerker e0a774b598 Add sensor test to Nederlandse Spoorwegen (#152375) 2025-09-15 18:03:14 +01:00
Manu 168afc5f0e Bump pyrate-limiter to v3.9.0 (#152370) 2025-09-15 18:54:26 +02:00
Paulus Schoutsen af23670854 Add quality-scale-verifier Claude agent (#152333) 2025-09-15 17:40:15 +01:00
Jan Bouwhuis 935ce421df Remove unused const in MQTT JSON Light component (#152377) 2025-09-15 11:36:19 -05:00
Klaas Schoute c60ad8179d Bump p1-monitor to v3.2.0 (#152378) 2025-09-15 18:12:04 +02:00
Nc Hodges 14ad3364e3 Add Re-Configure workflow to the Elk M1 Integration (#146368)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-09-15 11:02:00 -05:00
J. Nick Koston e229f36648 Clarify contributor responsibility when using AI-generated code (#152379) 2025-09-15 17:59:06 +02:00
Norbert Rittel f4f99e015c Clarify "discovery_requires_supervisor" message in zwave_js (#152345) 2025-09-15 17:14:41 +02:00
Joost Lekkerkerker 5dc509cba0 Add typing to Nederlandse Spoorwegen (#152367) 2025-09-15 16:19:39 +02:00
Shay Levy 75597ac98d Add Shelly removal condition for virtual components (#152312) 2025-09-15 16:15:15 +03:00
Heindrich Paul b503f792b5 Add config flow to NS (#151567)
Signed-off-by: Heindrich Paul <heindrich.paul@gmail.com>
Co-authored-by: Norbert Rittel <norbert@rittel.de>
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-15 15:13:43 +02:00
Ludovic BOUÉ 410c3df6dd Add Matter service actions for vacuum area (#151467)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-09-15 13:52:26 +02:00
virtualbitzz f1bf28df18 Add Matter climate running state heat fan and cool fan (#151535)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2025-09-15 13:28:40 +02:00
Patrick 99fb64af9b Add new USB drives to Synology DSM without reloading integration (#146829)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-15 13:12:57 +02:00
Shay Levy c0af0159e3 Use Entity Description in Shelly light platform (#137118) 2025-09-15 14:10:25 +03:00
Jan Bouwhuis 71749da3a3 Rename MQTT tag and device_automation setup helpers (#152344) 2025-09-15 11:52:24 +02:00
Norbert Rittel b01be94034 Update "Find my iPhone" to "Find My" in icloud (#152354) 2025-09-15 11:52:08 +02:00
Jan Gutowski 47ec8b7f12 Bump nibe to 2.18.0 (#152353) 2025-09-15 11:41:44 +02:00
dependabot[bot] 93ec9e448e Bump sigstore/cosign-installer from 3.9.2 to 3.10.0 (#152343)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-15 11:20:21 +02:00
Lennard Beers 90bc41dd02 Bump eq3btsmart to 2.2.0 (#152334) 2025-09-15 11:16:39 +02:00
epenet 410d869f3d Improve type hints in zha tests (#152347) 2025-09-15 11:16:10 +02:00
Imeon-Energy d75d9f2589 Bump imeon_inverter_api to 0.4.0 (#152351)
Co-authored-by: TheBushBoy <theodavid@icloud.com>
2025-09-15 11:14:31 +02:00
Christopher Fenner afbb832a57 Improve config flow for openweathermap integration (#152319) 2025-09-15 11:13:39 +02:00
epenet bdc881c87a Handle missing argument in hass_enforce_type_hints (#152342) 2025-09-15 09:45:27 +02:00
J. Nick Koston 22ea269ed8 Bump aioesphomeapi to 41.0.0 (#152332) 2025-09-14 23:22:10 -04:00
tronikos 10fecbaf4d Mark Opower as bronze (#148103)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2025-09-14 23:21:05 -04:00
Franck Nijhof cbdc1dc5b6 Refactor template engine: Extract math & statistical functions into MathExtension (#152266) 2025-09-14 20:48:29 -04:00
J. Nick Koston b203a831c9 Bump aioesphomeapi to 40.2.1 (#152327) 2025-09-14 19:31:55 -05:00
G Johansson 5ccbee4c9a Break long strings in entity platform/component tests (#152320) 2025-09-14 23:27:04 +02:00
Allen Porter 1483c9488f Update authorization server to prefer absolute urls (#152313)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-14 14:07:31 -07:00
Paulus Schoutsen f5535db24c Automatically generate entity platform enum (#152193)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-14 22:44:48 +02:00
Shay Levy e40ecdfb00 Remove Shelly empty sub-devices (#152251) 2025-09-14 22:43:37 +02:00
Norbert Rittel 2f4c69bbd5 Simplify description of direction_command_topic in mqtt (#150617) 2025-09-14 22:05:05 +02:00
Norbert Rittel dd0f6a702b Small fixes of user-facing strings in esphome (#152311) 2025-09-14 21:36:05 +03:00
Norbert Rittel 5ba580bc25 Capitalize "Supervisor" in two issues strings of hassio (#152303)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2025-09-14 21:35:47 +03:00
Samuel Xiao c13002bdd5 Add supported device[Plug-Mini-EU] for switchbot cloud (#151019) 2025-09-14 20:00:15 +02:00
Niklas Wagner 75d22191a0 Fix local_todo capitalization to preserve user input (#150814) 2025-09-14 19:53:41 +02:00
GSzabados 58d6549f1c Add display precision for rain rate and rain count (#151822) 2025-09-14 19:49:59 +02:00
Åke Strandberg 1fcc6df1fd Add proper error handling for /actions endpoint for miele (#152290) 2025-09-14 19:47:01 +02:00
J. Nick Koston 9bf467e6d1 Bump aioesphomeapi to 40.2.0 (#152272) 2025-09-14 19:39:44 +02:00
J. Nick Koston d877d6d93f Fix Lutron Caseta shade stuttering and improve stop functionality (#152207)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-14 19:35:18 +02:00
Lukas Waslowski d2b255ba92 nitpick: Add parameter types to _test_selector function signature (#152226) 2025-09-14 19:33:43 +02:00
Christopher Fenner 1509c429d6 Improve husqvarna_automower_ble config flow (#144877) 2025-09-14 19:32:10 +02:00
G Johansson af9717c1cd Raise error for entity services without a correct schema (#151165) 2025-09-14 19:17:26 +02:00
karwosts 49e75c9cf8 Fix browse by language in radio browser (#152296) 2025-09-14 19:04:59 +02:00
J. Nick Koston c97f16a96d Bump aiohomekit to 3.2.17 (#152297) 2025-09-14 19:02:11 +02:00
Bram Gerritsen a3a4433d62 Add missing unit conversion for BTU/h (#152300) 2025-09-14 19:00:44 +02:00
G Johansson f832002afd Bump holidays to 0.80 (#152306) 2025-09-14 17:51:47 +02:00
J. Diego Rodríguez Royo dbc7f2b43c Remove Home Connect stale code (#152307) 2025-09-14 17:51:11 +02:00
Galorhallen 1cd3a1eede Updated govee local api to 2.2.0 (#152289) 2025-09-14 16:16:26 +02:00
Norbert Rittel 7d6e0d44b0 Capitalize "Core" and "Supervisor" in backup issue strings (#152292) 2025-09-14 16:14:08 +02:00
jan iversen 2bb6d745ca Flexit: Fix wrong import from modbus. (#152225) 2025-09-14 12:04:07 +02:00
Todd Fast beb9d7856c Reduce PurpleAir sensor polling rate from every 2m to every 5m (#152271) 2025-09-14 11:59:48 +02:00
PaulCavill 6a4c8a550a Fix login issue with pyicloud (#129059)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-14 11:34:14 +02:00
Simon Lamon 7d23752a3f Unpin home-assistant/builder action (#152279) 2025-09-14 11:11:59 +02:00
Adam Goode c2b2a78db5 Change prusalink update cooldown to 1.0 seconds (#151060) 2025-09-14 10:58:00 +02:00
Manu 0fb6bbee59 Improve error logging for protected topic subscription in ntfy integration (#152244) 2025-09-14 10:02:48 +03:00
Denis Shulyaka d93e0a105a Save AI generated images to files (#152231) 2025-09-13 17:37:39 -04:00
karwosts ab1619c0b4 Adjust logbook filtering rules (#149349)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-09-13 16:34:55 -05:00
Franck Nijhof 70df7b8503 Restructure template engine, add crypto & base64 Jinja extension (#152261) 2025-09-13 22:21:29 +02:00
Denis Shulyaka 0e2c2ad355 Create dir on media upload if not exists (#152254) 2025-09-13 15:34:12 -04:00
J. Nick Koston 4c26718739 Bump bluetooth-auto-recovery to 1.5.3 (#152256) 2025-09-13 20:19:37 +02:00
J. Nick Koston 96034e1525 Bump aiohomekit to 3.2.16 (#152255) 2025-09-13 12:44:34 -05:00
Marc Mueller df1302fc1c Update mypy-dev to 1.19.0a2 (#152250) 2025-09-13 19:28:02 +02:00
Marc Mueller 5a5b639aa4 Update pytest-asyncio to 1.2.0 (#152156) 2025-09-13 19:27:47 +02:00
J. Nick Koston e9fbe2227f Fix HomeKit Controller overwhelming resource-limited devices by batching characteristic polling (#152209) 2025-09-13 19:24:05 +02:00
Yuxin Wang 82b57568a0 Set diagnostic entity category for "mode" in APCUPSD (#152246) 2025-09-13 18:38:47 +02:00
Simon Lamon be692ab2fd Reapply "Pin SHA for all github actions" (#152233) 2025-09-13 16:47:33 +02:00
Tor André Roland 24c04cceee Reflect Verisure lock, alarm control panel and switch state immediately without cloud pull (#149479)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-13 15:41:51 +01:00
w531t4 97077898bb Add Twitch entity for self (#150525)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-13 15:39:11 +01:00
Sean Dague 08485f4e09 Upgrade waterfurnace to 1.2.0 (#152241) 2025-09-13 15:36:15 +01:00
Marc Mueller b64d60fce4 Fix lg_thinq RuntimeWarning in tests (#152221) 2025-09-13 16:30:17 +02:00
Marc Mueller 3690497e1f Update pydantic to 2.11.9 (#152213) 2025-09-13 15:17:49 +01:00
Paulus Schoutsen 3499ed7a98 2025.9.3 (#152237) 2025-09-13 08:44:08 -04:00
Paulus Schoutsen 2c809d5903 Bump version to 2025.9.3 2025-09-13 12:14:15 +00:00
J. Nick Koston 40988198f3 Bump habluetooth to 5.6.4 (#152227) 2025-09-13 12:14:08 +00:00
Paulus Schoutsen b87e581cde Drop use of aiofiles in TTS (#152208) 2025-09-13 07:29:09 -04:00
J. Nick Koston f1c55ee7e2 Bump habluetooth to 5.6.4 (#152227) 2025-09-13 07:04:58 -04:00
J. Nick Koston 9f17a82acf Revert "Pin SHA for all github actions" (#152229) 2025-09-13 05:50:31 -05:00
Shay Levy 3955391cda Fix Shelly orphaned entity removal logic to handle sub-devices (#152195) 2025-09-13 12:11:47 +03:00
karwosts d9a757c7e6 Play url_resolved for radio browser instead of url (#150888) 2025-09-12 22:14:19 -04:00
Michael Hansen aa1ec944c0 Add secondary wake word and pipeline to ESPHome voice satellites (#151710) 2025-09-12 22:11:09 -04:00
Beat 88c3b6a9f5 Remove myself from enocean code owners (#151149) 2025-09-12 21:28:20 -04:00
skbeh ada73953f6 Use ephemeral port for SSDP server (#152049) 2025-09-12 23:56:53 +01:00
epenet 42e9b9a0bc Refactor _is_valid_suggested_unit in sensor (#151956) 2025-09-12 23:48:30 +01:00
Brandon Rothweiler ec6a052ff5 Add Hot Water+ Level select entity to A. O. Smith integration (#151548) 2025-09-13 00:46:26 +02:00
WardZhou c91d64e04d Add support for Thread Integration to Display Icons for GLiNet TBRs (#151386) 2025-09-12 23:45:43 +01:00
Franck Nijhof ab5d1d27f1 2025.9.2 (#152198) 2025-09-12 23:10:27 +02:00
wollew 1c10b85fed Use position percentage for closed status in Velux (#151679)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-12 20:39:06 +00:00
Franck Nijhof 91a7db08ff Bump version to 2025.9.2 2025-09-12 20:20:56 +00:00
Bram Kragten a764d54123 Update frontend to 20250903.5 (#152170) 2025-09-12 20:20:44 +00:00
Joakim Sørensen dc09e33556 Bump hass-nabucasa from 1.1.0 to 1.1.1 (#152147) 2025-09-12 20:20:43 +00:00
Simone Chemelli 14173bd9ec Fix reauth for Alexa Devices (#152128) 2025-09-12 20:20:42 +00:00
Jan Bouwhuis d2e7537629 Fix supported _color_modes attribute not set for on/off MQTT JSON light (#152126) 2025-09-12 20:20:41 +00:00
J. Nick Koston 9a165a64fe Fix DoorBird being updated with wrong IP addresses during discovery (#152088)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-12 20:20:39 +00:00
Abílio Costa 9c749a6abc Fix duplicated IP port usage in Govee Light Local (#152087) 2025-09-12 20:20:38 +00:00
J. Nick Koston 2e33222c71 Fix HomeKit Controller stale values at startup (#152086)
Co-authored-by: TheJulianJES <TheJulianJES@users.noreply.github.com>
2025-09-12 20:20:37 +00:00
Maciej Bieniek ab1c2c4f70 Bump accuweather to version 4.2.1 (#152029) 2025-09-12 20:20:36 +00:00
Joost Lekkerkerker 529219ae69 Bump yt-dlp to 2025.09.05 (#152006) 2025-09-12 20:20:35 +00:00
J. Nick Koston d6ce71fa61 Bump habluetooth to 5.6.2 (#151985) 2025-09-12 20:20:33 +00:00
peteS-UK e5b67d513a Fix playlist media_class_filter in search_media for squeezebox (#151973) 2025-09-12 20:20:32 +00:00
peteS-UK a547179f66 Fix for squeezebox track content_type (#151963) 2025-09-12 20:20:31 +00:00
epenet 8c61788a7d Fix invalid logger in Tuya (#151957) 2025-09-12 20:19:26 +00:00
J. Nick Koston 6b934d94db Bump habluetooth to 5.6.0 (#151942) 2025-09-12 20:18:38 +00:00
J. Nick Koston d30ad82774 Bump bleak-esphome to 3.3.0 (#151922)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-12 20:18:37 +00:00
J. Nick Koston 4618b33e93 Bump habluetooth to 5.5.1 (#151921) 2025-09-12 20:18:36 +00:00
epenet d6299094db Fix _is_valid_suggested_unit in sensor platform (#151912) 2025-09-12 20:18:35 +00:00
Simone Chemelli 087d9d30c0 Avoid cleanup/recreate of device_trackers not linked to a device for Vodafone Station (#151904) 2025-09-12 20:18:33 +00:00
Simone Chemelli f07890cf5c Bump aiovodafone to 1.2.1 (#151901) 2025-09-12 20:18:31 +00:00
Avi Miller e5b78cc481 Bump aiolifx-themes to 1.0.2 to support newer LIFX devices (#151898)
Signed-off-by: Avi Miller <me@dje.li>
2025-09-12 20:18:30 +00:00
Manu 12b409d8e1 Bump aiontfy to v0.5.5 (#151869) 2025-09-12 20:18:29 +00:00
Maciej Bieniek def5408db8 Use native_visibility property instead of visibility for OpenWeatherMap weather entity (#151867) 2025-09-12 20:18:28 +00:00
Robert Resch f105b45ee2 Bump aioecowitt to 2025.9.1 (#151859) 2025-09-12 20:18:26 +00:00
wollew 9d904c30a7 fix rain sensor for Velux GPU windows (#151857) 2025-09-12 20:18:25 +00:00
Martins Sipenko 99b047939f Update pysmarty2 to 0.10.3 (#151855) 2025-09-12 20:18:24 +00:00
J. Nick Koston 3a615908ee Bump aioharmony to 0.5.3 (#151853) 2025-09-12 20:18:23 +00:00
David Knowles baff541f46 Bump pydrawise to 2025.9.0 (#151842) 2025-09-12 20:18:22 +00:00
jan iversen 6d8c35cfe9 removed assert fron entity in modbus. (#151834) 2025-09-12 20:18:20 +00:00
jan iversen b8d9883e74 max_temp / min_temp in modbus light could only be int, otherwise an assert was provoked. (#151833) 2025-09-12 20:18:19 +00:00
jan iversen c3c65af450 Allow delay > 1 in modbus. (#151832) 2025-09-12 20:18:18 +00:00
Maciej Bieniek 3af8616764 Mark Tractive switches as unavailable when tacker is in the enegy saving zone (#151817) 2025-09-12 20:18:17 +00:00
Matthias Alphart 64ec4609c5 Fix KNX Light - individual color initialisation from UI config (#151815) 2025-09-12 20:18:15 +00:00
Matthias Alphart c78bc26b83 Fix KNX BinarySensor config_store data (#151808) 2025-09-12 20:18:14 +00:00
J. Nick Koston 0c093646c9 Bump habluetooth to 5.3.1 (#151803) 2025-09-12 20:18:13 +00:00
Simone Chemelli 1b27acdde0 Improve config entry migration for edge cases in Alexa Devices (#151788) 2025-09-12 20:18:12 +00:00
Ludovic BOUÉ 9dafc0e02f Remove device class for Matter NitrogenDioxideSensor (#151782)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-12 20:18:10 +00:00
Tsvi Mostovicz 0091dafcb0 Revert "Jewish Calendar add coordinator " (#151780) 2025-09-12 20:18:09 +00:00
Jan Bouwhuis b387acffb7 Fix update of the entity ID does not clean up an old restored state (#151696)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-12 20:18:08 +00:00
blotus 36b3133fa2 Fix support for Ecowitt soil moisture sensors (#151685) 2025-09-12 20:18:06 +00:00
hbludworth fe01e96012 Fix Aladdin Connect state not updating (#151652)
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-12 20:18:05 +00:00
Thomas55555 0b56ec16ed Add event entity on websocket ready in Husqvarna Automower (#151428) 2025-09-12 20:18:04 +00:00
Mark Adkins ca79f4c963 Update SharkIQ authentication method (#151046) 2025-09-12 20:18:02 +00:00
Bob Igo 9a43f2776d Fix XMPP not working with non-TLS servers (#150957) 2025-09-12 20:18:01 +00:00
hbludworth 0ac7cb311d Fix Aladdin Connect state not updating (#151652)
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-12 22:16:37 +02:00
Shay Levy 3472020812 Add icons for volume flow rate (#152196) 2025-09-12 22:09:01 +02:00
RoboMagus dcd09523a6 Webhook trigger: Enable templated webhook_id (#151193) 2025-09-12 15:48:52 -04:00
Jozef Lačný a5bfdc697b Add MEASUREMENT state_class to temperature sensors of flexit_bacnet (#152120) 2025-09-12 15:16:26 -04:00
Petar Petrov dbb29a7c7d Add attributes.entity_id to min_max sensors similar to groups (#151480) 2025-09-12 15:16:06 -04:00
Nathan Spencer 124a63d846 Add globe light settings for Litter-Robot 4 (#152190) 2025-09-12 14:55:50 -04:00
Michael Hansen 3de701a9ab Acknowledge if targets in same area (#150655)
Co-authored-by: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com>
2025-09-12 13:40:16 -05:00
Nc Hodges bfe1dd65b3 Add device and state class to Temp and Voltage entities. (#145613)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-09-12 12:57:58 -05:00
AdrianEddy 71bf5e14cc Add On/Off switch for DiscreteHeatingSystem in Overkiz (#151778)
Co-authored-by: Mick Vleeshouwer <mick@imick.nl>
2025-09-12 19:24:59 +02:00
Daniel Hjelseth Høyer 6d231c2c99 Tibber 15min prices (#151881)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-12 19:23:34 +02:00
Artur Pragacz b93072865b Clean up unused partial action response in intent helper (#151908) 2025-09-12 19:21:41 +02:00
Simon Lamon 14ebb6cd74 Pin SHA for all github actions (#151939) 2025-09-12 19:20:20 +02:00
Shay Levy 2ddbcd560e Add Shelly support for virtual buttons (#151940) 2025-09-12 19:16:54 +02:00
jan iversen c5ff7ed1c9 Remove self._lock in modbus. (#151997)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2025-09-12 19:15:15 +02:00
Yuxin Wang c4bea5616c Upgrade aioapcaccess to 1.0.0 (#151844) 2025-09-12 19:09:46 +02:00
epenet 17fe147726 Add support for Tuya szjcy category (water quality sensors) (#152020) 2025-09-12 19:08:29 +02:00
epenet 9fae4e7e1f Add support for Tuya bzyd category (white noise machine) (#152025) 2025-09-12 19:00:54 +02:00
Thijs W. 0cebca498c Bump pymodbus to 3.11.2 (#152097)
Co-authored-by: Franck Nijhof <git@frenck.dev>
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2025-09-12 18:55:22 +02:00
Luke Lashley 521ff62aae Make Roborock map transparent by default (#152092) 2025-09-12 18:50:42 +02:00
Marcos Alano fd1df5ad88 Add select for up/down/stop to electric desk (#152166) 2025-09-12 18:39:05 +02:00
Nathan Spencer 91e7a35a07 Add gravity mode switch for Feeder-Robot (#152175) 2025-09-12 18:36:58 +02:00
Maciej Bieniek 09381abf46 Add hourly forecast for AccuWeather integration (#152178) 2025-09-12 18:34:56 +02:00
laiho-vogels 3713c03c07 Drop index from preset name in MotionMount (#151301)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-12 17:33:26 +01:00
Erik Montnemery bd8ddd7cd8 Register androidtv entity services in async_setup (#152172) 2025-09-12 18:29:47 +02:00
Jan Bouwhuis f0dc1f927b Fix ai_task generate image service test (#152184) 2025-09-12 18:19:03 +02:00
Simone Chemelli 984590c6d1 Fix Pylance errors in UptimeRobot tests (#152185) 2025-09-12 18:18:27 +02:00
Iskra kranj d324021a3f Bump pyiskra to 0.1.27 (#152160) 2025-09-12 18:05:37 +02:00
jan iversen 1f4c0b3e9b Add codeowner for Modbus (#152163) 2025-09-12 18:04:01 +02:00
Bram Kragten 69893aba4b Update frontend to 20250903.5 (#152170) 2025-09-12 18:01:16 +02:00
Paulus Schoutsen b9dcf89b37 Fix hassfest error for internal integrations (#152173)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-12 17:53:08 +02:00
Artur Pragacz 54fd55a1c6 Remove unused ATTR_STEP_VALIDATION from number (#152179) 2025-09-12 16:46:42 +02:00
Matthias Alphart cc64fa639d Add KNX UI entity config to diagnostics (#151620) 2025-09-12 15:41:17 +02:00
Benjamin Pearce 84140ba414 Add remote codes which can be used with remote.send_command to diagnostics (#152017)
Co-authored-by: Maciej Bieniek <bieniu@users.noreply.github.com>
2025-09-12 14:41:15 +02:00
Marc Mueller d1726b84c8 Update pytest-cov to 7.0.0 (#152157) 2025-09-12 13:34:20 +02:00
Jan Bouwhuis 4724ecbc38 Suppress warning if object_id is still added when default_entity_id is used in MQTT discovery (#151996) 2025-09-12 13:11:10 +02:00
Marc Mueller 85afe87b5e Update coverage to 7.10.6 (#152158) 2025-09-12 13:02:01 +02:00
Nathan Spencer 5960179844 Add food dispensed today and next feeding sensors to litterrobot (#152016)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-12 11:17:45 +01:00
Thomas55555 9f8f7d2fde Add event entity on websocket ready in Husqvarna Automower (#151428) 2025-09-12 11:52:29 +02:00
ekobres 4c22264b13 Add support for inH₂O pressure unit (#148289)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-12 11:24:45 +02:00
Andrea Turri baf4382724 Miele consumption sensors consistent behavior with RestoreSensor (#151098) 2025-09-12 11:17:10 +02:00
Manu 8263ea4a4a Don't try to connect after exiting loop in ntfy (#152011) 2025-09-12 11:14:01 +02:00
Bouwe Westerdijk 8412581be4 Implement snapshot-testing for Plugwise climate platform (#151070) 2025-09-12 11:10:49 +02:00
J. Nick Koston 207c848438 Improve SwitchBot device discovery when Bluetooth adapter is in passive mode (#152074) 2025-09-12 11:08:51 +02:00
Paulus Schoutsen 2b61601fd7 Remove the host from the AI Task generated image URL (#151887) 2025-09-12 11:03:01 +02:00
Denis Shulyaka ee506e6c14 Implement thinking content for Gemini (#150347)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-12 05:02:39 -04:00
Brett Adams 8003a49571 Add guest mode switch to Teslemetry (#151550) 2025-09-12 10:44:38 +02:00
Maciej Bieniek e438b11afb Use native_visibility property instead of visibility for OpenWeatherMap weather entity (#151867) 2025-09-12 10:44:22 +02:00
Matthias Alphart 64ba43703c Fix KNX Light - individual color initialisation from UI config (#151815) 2025-09-12 10:43:45 +02:00
Jeremy Cook 1d214ae120 For the met integration Increase the hourly forecast limit to 48 hours in coordinator. (#150486) 2025-09-12 10:19:29 +02:00
Joakim Sørensen 68d987f866 Bump hass-nabucasa from 1.1.0 to 1.1.1 (#152147) 2025-09-12 10:18:58 +02:00
Norbert Rittel 299cc5e40c Fix sentence-casing of "CPU temperature" in fritz (#152149) 2025-09-12 10:18:12 +02:00
Retha Runolfsson 2c3456177e Add humidifier support for switchbot cloud integration (#149039) 2025-09-12 10:08:01 +02:00
Retha Runolfsson 1ef90180cc Add plug mini eu for switchbot integration (#151130) 2025-09-12 10:05:15 +02:00
Erik Montnemery 4c1364dfd1 Fix wrong type annotation in exposed_entities (#152142) 2025-09-12 09:32:17 +02:00
Norbert Rittel 09a44a6a30 Fix spelling of "H.265" encoding standard in reolink (#152130) 2025-09-12 08:05:01 +02:00
Maciej Bieniek 63303bdcde Allow port and SNMP community configuration for Brother printer (#151506) 2025-09-12 00:21:05 +02:00
Markus Adrario 59cd24f54b Add dynamic devices to Homee (#151934) 2025-09-12 00:19:37 +02:00
Duco Sebel 82b9fead39 Add support for controlling LED brightness on HomeWizard Plug-In Battery and P1 Meter (#151186) 2025-09-11 23:46:00 +02:00
karwosts a879e36e9b Designate helpers as internal quality (#149021) 2025-09-11 23:41:06 +02:00
HarvsG b12c458188 Log bayesian sensor name for unavailable observations (#152039) 2025-09-11 22:14:51 +01:00
Simone Chemelli 4985f9a5a1 Fix reauth for Alexa Devices (#152128) 2025-09-11 22:26:47 +02:00
Maciej Bieniek ae70ca7cba Add sw_version to Shelly BLU TRV device info (#152129) 2025-09-11 21:50:03 +02:00
Norbert Rittel 66d1cf8af7 Add missing period in "H.264" standard name in onvif (#152132) 2025-09-11 22:12:02 +03:00
Roland Moers 27c0df3da8 Add CPU temperature sensor to AVM FRITZ!Box Tools (#151328) 2025-09-11 21:05:59 +02:00
Norbert Rittel 5413131885 Replace "cook time" with correct "cooking time" in matter (#152110) 2025-09-11 20:49:13 +03:00
Michael Hansen 0acd77e60a Only use media path for TTS stream override (#152084) 2025-09-11 19:46:36 +02:00
epenet c5d552dc4a Use translation_key in Tuya dr category (electric blanket) (#152099) 2025-09-11 19:45:21 +02:00
Jan Bouwhuis 4f045b45ac Fix supported _color_modes attribute not set for on/off MQTT JSON light (#152126) 2025-09-11 19:43:44 +02:00
markhannon 4ad29161bd Bump zcc-helper to 3.7 (#151807) 2025-09-11 19:42:24 +02:00
LG-ThinQ-Integration fea7f537a8 Bump thinqconnect to 1.0.8 (#152100)
Co-authored-by: yunseon.park <yunseon.park@lge.com>
2025-09-11 19:39:01 +02:00
epenet 442b6e9cca Add initial support for Tuya sjz category (electric desk) (#152036) 2025-09-11 19:35:24 +02:00
wollew 531b67101d fix rain sensor for Velux GPU windows (#151857) 2025-09-11 19:14:59 +02:00
J. Nick Koston 596a3fc879 Add async_current_scanners API to Bluetooth integration (#152122) 2025-09-11 13:06:51 -04:00
Joost Lekkerkerker 0e8295604e Fail hassfest if translation key is obsolete (#151924)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-11 18:56:56 +02:00
Manu 9cfdb99e76 Add repair to unsubscribe protected topic in ntfy integration (#152009) 2025-09-11 18:52:12 +02:00
Marc Mueller b1a6e403fb Cache apt install [ci] (#152113) 2025-09-11 18:44:43 +02:00
Samuel Xiao 937d3e4a96 Add more light models to SwitchBot Cloud (#150986) 2025-09-11 18:39:29 +02:00
Manu a368ad4ab5 Set sensors to unknown when no next alarm is set in Sleep as Android (#150558) 2025-09-11 18:38:33 +02:00
peteS-UK 254694b024 Fix track icons for Apps and Radios in Squeezebox (#151001) 2025-09-11 18:37:21 +02:00
Sam Reed bcfa7a7383 squeezebox: Improve update notification string (#151003) 2025-09-11 18:36:22 +02:00
Abílio Costa ab7081d26a Include non-primary entities targeted directly by label (#149309) 2025-09-11 17:34:15 +01:00
epenet 4762c64c25 Add initial support for Tuya msp category (cat toilet) (#152035) 2025-09-11 18:22:39 +02:00
Artur Pragacz 1b99ffe61b Pass satellite id through assist pipeline (#151992) 2025-09-11 11:13:23 -05:00
Imeon-Energy d5132e8ea9 Add select to Imeon inverter integration (#150889)
Co-authored-by: TheBushBoy <theodavid@icloud.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-09-11 17:55:55 +02:00
J. Nick Koston 1bcf3cfbb2 Fix DoorBird being updated with wrong IP addresses during discovery (#152088)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-11 10:58:59 -04:00
Norbert Rittel d4d912ef55 Add missing "to" in invalid_auth exception of portainer (#152116) 2025-09-11 16:40:39 +02:00
Martin Hjelmare 393826635b Add next_flow to config flow result (#151998) 2025-09-11 15:48:59 +02:00
Abílio Costa 9edd5c35e0 Fix duplicated IP port usage in Govee Light Local (#152087) 2025-09-11 14:47:59 +01:00
J. Nick Koston e8c1d3dc3c Add repair issue for Bluetooth adapter passive mode fallback (#152076) 2025-09-11 08:52:57 -04:00
Paulus Schoutsen 46463ea4f8 Rename Google Gen AI to Google Gemini (#151653) 2025-09-11 08:35:50 -04:00
Paulus Schoutsen 88e6b0c8d9 Make LocalSource reusable (#151886) 2025-09-11 08:35:10 -04:00
Maciej Bieniek 2ed92c720f Add entities for Shelly presence component (#151816) 2025-09-11 14:23:27 +02:00
Åke Strandberg 7389f23d9a Bump miele quality scale to platinum (#149736) 2025-09-11 13:18:55 +02:00
Retha Runolfsson a0cef80cf2 Add sensors for switchbot cloud integration (#147663) 2025-09-11 12:58:36 +02:00
Marc Hörsken 343b17788f Add support for valance shades / volants to WMS WebControl pro (#150882) 2025-09-11 12:57:53 +02:00
Erik Montnemery 50349e49f1 Register sonos entity services in async_setup (#152047) 2025-09-11 12:52:58 +02:00
Shay Levy 42d0415a86 Update Shelly Neo water valve device class and units (#152080) 2025-09-11 13:36:11 +03:00
G Johansson 1428b41a25 Improve sql config flow (#150757)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-11 12:27:48 +02:00
Foscam-wangzhengyu e65b4292b2 Add volume control to Foscam Upgrade dependencies (#150618)
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-11 11:59:05 +02:00
Marc Mueller 2fc2bb97fc Update PyNaCl to 1.6.0 (#152107) 2025-09-11 10:30:33 +02:00
epenet 40da606177 Add support for Tuya swtz category (cooking thermometer) (#152022) 2025-09-11 10:28:20 +02:00
epenet d613b69e4e Fix typo in Tuya strings (#152103) 2025-09-11 10:27:25 +02:00
Erik Montnemery 3c5d09e114 Fix stale docstring in alarm_control_panel (#152026) 2025-09-11 10:26:34 +02:00
dependabot[bot] 9c54cc369b Bump github/codeql-action from 3.30.1 to 3.30.3 (#152098)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-11 09:11:22 +02:00
Paulus Schoutsen f91e4090f9 Add path to resolved media in image_upload (#152093) 2025-09-10 22:55:59 -04:00
Paulus Schoutsen 2cdf0b74d5 Gemini: Reuse attachment mime type if known (#152094) 2025-09-10 19:49:10 -07:00
J. Nick Koston 86750ae5c3 Fix HomeKit Controller stale values at startup (#152086)
Co-authored-by: TheJulianJES <TheJulianJES@users.noreply.github.com>
2025-09-10 19:45:22 -05:00
J. Nick Koston c1eb492616 Fix Bluetooth mock to prevent degraded mode repair issues in tests (#152081) 2025-09-10 17:19:15 -05:00
karwosts ac154c020c Use a state selector for history_stats (#150445)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-10 23:52:50 +02:00
Manu 0e23eb9ebd Update Sleep as Android quality scale to platinum 🏆️ (#150449) 2025-09-10 23:37:12 +02:00
Tsvi Mostovicz 8367930f42 Jewish Calendar quality scale (#143763) 2025-09-10 23:25:16 +02:00
Joost Lekkerkerker d71b1246cf Add DHCP discovery to Aladdin Connect (#151532) 2025-09-10 22:57:46 +02:00
Ville Skyttä 4ad664a652 Add huawei_lte quality scale YAML (#143347)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-10 22:32:21 +02:00
Whitney Young 002493c3e1 Openuv protection window internal update (#146409) 2025-09-10 22:18:50 +02:00
Ludovic BOUÉ 720ecde568 Support for Matter MountedDimmableLoadControl device type (#151330)
Support for Matter MountedDimmableLoadControl device type:
Matter MountedDimmableLoadControl device was wrongly reco
gnized as Switch entity.
This PR fix thte behavior and makes it recognized as Light entity as expected.
There is no Matter MountedDimmableLoadControl device in the market yet so it doesn't really breaks anything.
2025-09-10 22:16:43 +02:00
Paul Bottein 4c548830b4 Use state selector for select option service (#148960) 2025-09-10 22:15:23 +02:00
Raphael Hehl 214925e10a Refactor unifiprotect RTSP repair flow to use publicapi create_rtsps_streams method (#149542) 2025-09-10 22:13:14 +02:00
Joost Lekkerkerker 885256299f Enable PYI059 and fix violations (#152069) 2025-09-10 21:52:21 +02:00
Joost Lekkerkerker e73c670025 Enable PYI061 and fix violations (#152070) 2025-09-10 21:17:59 +02:00
Joost Lekkerkerker e3c0cfd1e2 Enable RUF059 and fix violations (#152071) 2025-09-10 21:16:09 +02:00
Maciej Bieniek 46c38f185c Adapt AccuWeather to new paid API plans (#152056)
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-10 21:15:48 +02:00
Abílio Costa 9082637133 Raise on service calls in Whirlpool (#152057)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-10 21:13:12 +02:00
Simone Chemelli 0a35fd0ea4 Add key reconfigure to UptimeRobot config flow (#151562) 2025-09-10 21:12:57 +02:00
Simone Chemelli c4649fc068 Avoid cleanup/recreate of device_trackers not linked to a device for Vodafone Station (#151904) 2025-09-10 21:09:44 +02:00
Erwin Douna b496637bdd Add Portainer integration (#142875)
Co-authored-by: Manu <4445816+tr4nt0r@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-10 21:01:41 +02:00
Retha Runolfsson 7d471f9624 Add rgbicww light for switchbot integration (#151129) 2025-09-10 13:52:47 -05:00
Joost Lekkerkerker 83f3b3e3eb Bump ruff to 0.13.0 (#152067) 2025-09-10 20:48:31 +02:00
J. Nick Koston 4592d6370a Bump PySwitchBot to 0.70.0 (#152072) 2025-09-10 13:39:52 -05:00
Abílio Costa ccef31a37a Set PARALLEL_UPDATES in Whirlpool integration (#152065) 2025-09-10 19:47:31 +02:00
Simone Chemelli 6a482b1a3e Remove stale devices for Alexa Devices (#151909) 2025-09-10 19:20:40 +02:00
Marc Mueller 6f00f8a920 Update feedreader to 6.0.12 (#152054) 2025-09-10 11:09:11 -05:00
Sarah Seidman ceeeb22040 Add integration for Droplet (#149989)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
Co-authored-by: Josef Zweck <josef@zweck.dev>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-10 17:38:49 +02:00
Simone Chemelli 2cda0817b2 Add illuminance sensor for Shelly Plug US Gen4 (#150681) 2025-09-10 17:31:56 +02:00
epenet 881a0bd1fa Add missing Tuya translation string (#152051) 2025-09-10 15:59:21 +02:00
epenet dba6f419c9 Remove unneeded Tuya translation key (#152052) 2025-09-10 15:59:03 +02:00
Abílio Costa fad8d4fca2 Remove uneeded check for fan mode in Whirlpool (#152053) 2025-09-10 15:47:05 +02:00
Ludovic BOUÉ 1663ad1adb Remove device class for Matter NitrogenDioxideSensor (#151782)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-10 15:34:32 +02:00
Marc Mueller 6a8152bc7f Update isal to 1.8.0 (#152043) 2025-09-10 08:25:19 -05:00
Felipe Santos e5edccd56f Fix Supervisor Ingress WebSocket not handling Connection and Timeout Error (#151951)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-10 13:59:42 +02:00
Erik Montnemery 480527eb68 Call DeviceRegistry._async_update_device from device registry (#151295) 2025-09-10 13:14:03 +02:00
Maciej Bieniek 1475108f1c Bump accuweather to version 4.2.1 (#152029) 2025-09-10 12:25:20 +02:00
Erik Montnemery a1e68336fc Add service helper for registering platform services (#151965)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-09-10 11:21:31 +01:00
Erik Montnemery 07392e3ff7 Fix lifx tests opening sockets (#152037) 2025-09-10 12:18:58 +02:00
Erik Montnemery 3e39f77e92 Remove duplicated call to time.time in device registry (#152024) 2025-09-10 11:15:59 +02:00
anishsane a12617645b Add support for Tasmota camera (#144067)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-10 08:13:48 +02:00
Manu 723476457e Add subentry reconfigure flow to ntfy integration (#143718) 2025-09-10 07:57:55 +02:00
Megamind 7053727426 Feature - add Time-to-Live (ttl) parameter support to Pushover integration (#143791) 2025-09-10 07:56:36 +02:00
Denis Shulyaka 0f4ce58f28 Raise repair issue when organization verification is required by OpenAI (#151878)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-09-09 23:35:29 -04:00
J. Nick Koston 2c72cd3832 Add repair issue for Bluetooth adapters in degraded mode due to missing container permissions (#151947)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-09 23:34:19 -04:00
Michael Hansen e8d5615e54 Allow overriding TTS result stream with media id (#151718) 2025-09-09 23:30:00 -04:00
Nathan Spencer 7a332d489d Bump pylitterbot to 2024.2.4 (#152015) 2025-09-09 22:28:54 -05:00
J. Nick Koston 504421e257 Fix ESPHome lock showing as unlocked when state is unknown (#152012) 2025-09-09 21:52:48 -04:00
Joost Lekkerkerker a0ace3b082 Bump yt-dlp to 2025.09.05 (#152006) 2025-09-09 18:28:49 -05:00
J. Nick Koston aea055b444 Bump aioesphomeapi to 40.1.0 (#152005) 2025-09-09 16:07:53 -05:00
Keith Burzinski 5b107349a1 Patch ESPHome client to handle climate UI correctly (#151897)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-09-09 15:55:38 -05:00
RogerSelwyn 46fa98e0b2 Fix Private Groups in Hue integration cause delay in startup (#151896) 2025-09-09 22:30:36 +02:00
peteS-UK 96e66009e5 Fix playlist media_class_filter in search_media for squeezebox (#151973) 2025-09-09 22:22:28 +02:00
GSzabados ad14a66187 WH46 missing PM1.0 and PM4.0 sensors (#151821)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-09 22:17:13 +02:00
Manu 777ac97acb Add state attribute translations to ntfy integration (#152004) 2025-09-09 22:12:50 +02:00
Paulus Schoutsen af07ab4752 Allow passing an LLM API to AI Task generate data (#151081) 2025-09-09 15:12:20 -04:00
Simone Chemelli 74b731528d Improve config entry migration for edge cases in Alexa Devices (#151788) 2025-09-09 21:08:04 +02:00
Erik Montnemery c361c32407 Bump hatasmota to 0.10.1 (#151988)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-09 20:55:01 +03:00
Álvaro Fernández Rojas 75c1eddaf9 Update aioairzone to v1.0.1 (#151990)
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2025-09-09 20:43:50 +03:00
Manu 715aba3aca Bump aiontfy to v0.5.5 (#151869) 2025-09-09 20:42:49 +03:00
Paulus Schoutsen 285619e913 Allow storing AI Task generate image preferred entity (#151938) 2025-09-09 18:29:14 +01:00
Manu eaf400f3b7 Add ntfy.publish action to ntfy integration (#143560)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-09-09 19:08:49 +02:00
J. Nick Koston 3d79a73110 Bump habluetooth to 5.6.2 (#151985) 2025-09-09 11:38:45 -05:00
Manu 6271765eaf Add event platform to ntfy integration (#143529) 2025-09-09 17:53:19 +02:00
skbeh 9e73ff06d2 Prevent socket leak on SSDP when finding available port (#150999)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-09 16:50:52 +01:00
tronikos 36edfd8c04 Mark Android TV Remote as platinum (#148047) 2025-09-09 17:33:09 +02:00
tronikos a750cfcac6 Make "Add new" translatable in Android TV Remote options (#151749) 2025-09-09 17:32:32 +02:00
Joost Lekkerkerker 026f20932a Remove manually adding domain in android TV remote (#151983) 2025-09-09 08:12:18 -07:00
GSzabados 07d4e11c30 Add VPD - Vapour Pressure Deficit support to Ecowitt (#141727)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-09 17:08:23 +02:00
epenet 9c80d75588 Add charge_state to Tuya siren alarm (#151220) 2025-09-09 17:02:31 +02:00
epenet 1818a103b6 Use motor rotation mode in Tuya clkg covers (curtain) (#151767) 2025-09-09 17:02:04 +02:00
epenet 3e4bb4eb7e Add PM10 to Tuya air quality monitor (co2bj category) (#151980) 2025-09-09 16:54:47 +02:00
Bob Igo 1117b92dde Fix XMPP not working with non-TLS servers (#150957) 2025-09-09 15:18:48 +02:00
Stefan Agner f5a1523068 Update Home Assistant base image to 2025.09.1 (#151960) 2025-09-09 08:17:30 -05:00
peteS-UK 7005a70a4e Fix for squeezebox track content_type (#151963) 2025-09-09 15:16:19 +02:00
Joost Lekkerkerker 9b862a8e4e Set otbr config entry title to ZBT-1 with a SkyConnect (#151911) 2025-09-09 15:03:17 +02:00
epenet f5dba77636 Fix invalid logger in Tuya (#151957) 2025-09-09 14:44:31 +02:00
Joost Lekkerkerker da7f9f6154 Remove obsolete Ecobee strings (#151970) 2025-09-09 15:37:48 +03:00
Joost Lekkerkerker 9a92d58613 Remove obsolete LCN strings (#151969) 2025-09-09 15:36:47 +03:00
epenet 9ea438024d Add Tuya test fixtures (#151972) 2025-09-09 14:28:25 +02:00
Joost Lekkerkerker 58edc3742a Remove obsolete alexa devices strings (#151971) 2025-09-09 13:47:30 +02:00
epenet 3c0580880d Add Tuya test fixtures (#151953) 2025-09-09 13:44:32 +02:00
J. Nick Koston 04b5eb7d53 Bump habluetooth to 5.6.0 (#151942) 2025-09-08 16:45:11 -05:00
Shay Levy cecae10a15 Bump aioshelly to 13.9.0 (#151943) 2025-09-09 00:23:26 +03:00
HarvsG 2e2b9483df Improve efficiency of config_entries _async_abort_entries_match() (#148344)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-09-08 15:17:29 -05:00
Paulus Schoutsen 0444467858 Gemini: add support for AI Task generate image (#151880) 2025-09-08 16:11:06 -04:00
michnovka d990c2bee2 Fix timestamps exposed to LLM to be in local timezone (#139825)
Co-authored-by: Michael Hansen <mike@rhasspy.org>
2025-09-08 14:51:17 -05:00
Nathan Spencer 03a7052151 Add last feeding sensor for Feeder-Robots (#151871) 2025-09-08 21:40:18 +02:00
Manu 4025e23c67 Remove unused translation string in Bring! integration (#151927) 2025-09-08 21:37:47 +02:00
Abílio Costa 82c3fcccc9 Update whirlpool-sixth-sense to 0.21.3 (#151929)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-09-08 21:37:18 +02:00
J. Nick Koston 7ee7a3c0b5 Bump bleak-esphome to 3.3.0 (#151922)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-08 14:32:31 -05:00
Abílio Costa e7cb0173b0 Increase timeout of install os dependencies step (#151931) 2025-09-08 13:41:38 -05:00
J. Nick Koston dbdbf1cf16 Bump habluetooth to 5.5.1 (#151921) 2025-09-08 13:37:50 -05:00
Markus Adrario b5704f3e8b Bump pyHomee to 1.3.8 (#151874) 2025-09-08 18:53:13 +01:00
Artur Pragacz df3d4b5db1 Clean up unused intent category (#151917) 2025-09-08 19:42:23 +02:00
Jan Bouwhuis 0ab232b904 Fix typo in MQTT strings (#151907) 2025-09-08 18:43:15 +02:00
Joost Lekkerkerker acc75e4419 Remove image filename parameter from Google Generative AI (#151914) 2025-09-08 09:01:41 -07:00
Norbert Rittel 8aa672882a Replace "STT" with "Speech-to-Text" in google_cloud UI (#151918) 2025-09-08 08:59:18 -07:00
Artur Pragacz 3cbf3bdf4c Remove Kodi media player platform yaml support (#151786) 2025-09-08 17:16:23 +02:00
epenet 56c865dcfe Fix _is_valid_suggested_unit in sensor platform (#151912) 2025-09-08 16:35:33 +02:00
karwosts b7360dfad8 Allow deleting kitchen_sink devices (#151826) 2025-09-08 15:01:08 +01:00
dependabot[bot] f2204e97ab Bump github/codeql-action from 3.30.0 to 3.30.1 (#151890)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 14:49:05 +02:00
Artur Pragacz 98df5f5f0c Validate selectors in the condition helper (#151884) 2025-09-08 14:20:11 +02:00
Simone Chemelli 064d43480d Bump aiovodafone to 1.2.1 (#151901) 2025-09-08 12:58:26 +02:00
Jan Bouwhuis 1536375e82 Fix update of the entity ID does not clean up an old restored state (#151696)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-08 12:48:23 +02:00
Avi Miller 39e9ffff29 Bump aiolifx-themes to 1.0.2 to support newer LIFX devices (#151898)
Signed-off-by: Avi Miller <me@dje.li>
2025-09-08 13:45:42 +03:00
puddly 12f152d6e4 Home Assistant Connect ZBT-2 integration (#151015)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-09-08 11:18:31 +02:00
Jan Bouwhuis c7f0560208 Deprecate object_id and instead suggest to use default_entity_id to set the suggested entity_id in MQTT entity configurations (#151775) 2025-09-08 09:22:12 +02:00
Denis Shulyaka 65603a3829 Add signature to ai_task generated images URL (#151882) 2025-09-07 16:58:51 -04:00
Robert Resch 38ea5c6813 Bump aioecowitt to 2025.9.1 (#151859) 2025-09-07 19:52:05 +02:00
Norbert Rittel 5b1fd8f58b Fix sentence-casing in volvooncall (#151863) 2025-09-07 19:51:16 +02:00
Maciej Bieniek e5f99a617f Mark Tractive switches as unavailable when tacker is in the enegy saving zone (#151817) 2025-09-07 13:34:31 +02:00
Martins Sipenko 7f8b5f2288 Update pysmarty2 to 0.10.3 (#151855) 2025-09-07 09:36:45 +02:00
J. Nick Koston 75f69cd5b6 Bump aioharmony to 0.5.3 (#151853) 2025-09-06 23:55:27 -04:00
Paulus Schoutsen d7fab27351 Remove myself as code owner of integrations (#151851) 2025-09-06 20:42:25 -05:00
David Knowles 6c6ec7534f Bump pydrawise to 2025.9.0 (#151842) 2025-09-06 23:07:56 +03:00
Norbert Rittel 8e3780264a Capitalize "AC" in nut (#151831) 2025-09-06 20:25:42 +02:00
jan iversen 78b009dd8f Allow delay > 1 in modbus. (#151832) 2025-09-06 21:21:12 +03:00
jan iversen 76d72ad280 max_temp / min_temp in modbus light could only be int, otherwise an assert was provoked. (#151833) 2025-09-06 21:20:49 +03:00
jan iversen e5be9426a4 removed assert fron entity in modbus. (#151834) 2025-09-06 21:20:21 +03:00
Norbert Rittel 0922f12ec0 Use "credentials" only for username and password in overkiz (#151837) 2025-09-06 21:19:52 +03:00
Norbert Rittel 89f424e1d3 Fix sentence-casing of "Application credentials" in common strings (#151828) 2025-09-06 19:21:33 +02:00
Norbert Rittel 143eb20d99 Fix sentence-casing of two tesla_fleet user-facing strings (#151829) 2025-09-06 17:56:54 +02:00
Artur Pragacz 3187506eb9 Ignore incorrect themes (#151794) 2025-09-06 13:49:03 +02:00
Matthias Alphart a328b23437 Fix KNX BinarySensor config_store data (#151808) 2025-09-06 13:02:35 +02:00
Norbert Rittel 7e6a949559 Fix exceptions of climate.set_temperature action to use friendly names (#151811) 2025-09-06 14:00:15 +03:00
J. Nick Koston da7db5e22b Bump habluetooth to 5.3.1 (#151803) 2025-09-06 13:57:44 +03:00
Jan-Philipp Benecke ec58943c8c Bump zeroconf to 0.147.2 (#151809) 2025-09-06 13:56:52 +03:00
Norbert Rittel 61a05490e9 Fix missing sentence-casing of "temperature" in bsblan (#151810) 2025-09-06 13:55:13 +03:00
Joakim Plate 6a1629d2ed Update philips_js to 3.2.4 (#151796) 2025-09-06 08:16:06 +02:00
Paulus Schoutsen 106e1ce224 Gen translations in script/bootstrap (#151806) 2025-09-06 07:22:47 +02:00
Abílio Costa 601d63e3b7 Add top-level target support to condition schema (#149634)
Co-authored-by: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com>
2025-09-05 22:55:28 +01:00
Jan Bouwhuis 6a5f5b9adc Mock discovery in lifx sensor tests to avoid socket access in tests (#151787) 2025-09-05 21:46:07 +02:00
karwosts 8ecf5a98a5 Catch more invalid themes in validation (#151719) 2025-09-05 20:09:33 +02:00
Tsvi Mostovicz 1728c577f7 Revert "Jewish Calendar add coordinator " (#151780) 2025-09-05 17:47:29 +02:00
wollew 1006d5e0ba Use position percentage for closed status in Velux (#151679)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-05 16:45:29 +01:00
Artur Pragacz 6c29d5dc49 Add entity info to device database analytics (#151670) 2025-09-05 16:12:35 +02:00
Carlos Morán a4e086f0d9 Add manual mode to the map of Overkiz to HVAC modes (#151438) 2025-09-05 15:43:54 +02:00
Marko Todorić 0fecf012e6 SFTP/SSH as remote Backup location (#135844)
Co-authored-by: Josef Zweck <josef@zweck.dev>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-05 15:43:26 +02:00
blotus 63c8bfaa9b Fix support for Ecowitt soil moisture sensors (#151685) 2025-09-05 14:40:14 +02:00
Mark Adkins 435926fd41 Update SharkIQ authentication method (#151046) 2025-09-05 13:14:28 +02:00
Franck Nijhof 0cda883b56 2025.9.1 (#151766) 2025-09-05 13:13:34 +02:00
Ludovic BOUÉ c621f0c139 Matter RVC ServiceArea EstimatedEndTime attribute (#151384) 2025-09-05 12:49:32 +02:00
Artur Pragacz fa9007777d Add myself as codeowner to Voice components (#151764) 2025-09-05 12:45:17 +02:00
Franck Nijhof ae58e633f0 Bump version to 2025.9.1 2025-09-05 10:33:36 +00:00
jan iversen 06480bfd9d Fix enable/disable entity in modbus (#151626) 2025-09-05 10:33:04 +00:00
jan iversen e1afadb28c Fix enable/disable entity in modbus (#151626) 2025-09-05 12:31:33 +02:00
Artur Pragacz 625f586945 Fix recognition of entity names in default agent with interpunction (#151759) 2025-09-05 10:30:27 +00:00
Richard Kroegel 7dbeaa475d Bump bimmer_connected to 0.17.3 (#151756) 2025-09-05 10:30:24 +00:00
David Knowles dff3d5f8af Bump pyschlage to 2025.9.0 (#151731) 2025-09-05 10:30:21 +00:00
Michael Hansen 89c335919a Handle match failures in intent HTTP API (#151726) 2025-09-05 10:30:16 +00:00
Daniel Hjelseth Høyer 2bb4573357 Update Mill library 0.13.1 (#151712) 2025-09-05 10:30:01 +00:00
Dan Raper 7037ce989c Bump ohmepy version to 1.5.2 (#151707) 2025-09-05 10:29:58 +00:00
Dan Raper bfdd2053ba Require OhmeAdvancedSettingsCoordinator to run regardless of entities (#151701) 2025-09-05 10:29:55 +00:00
Bram Kragten fcc3f92f8c Update frontend to 20250903.3 (#151694) 2025-09-05 10:29:51 +00:00
Marcel van der Veldt 8710267d53 Bump aiohue to 4.7.5 (#151684) 2025-09-05 10:29:48 +00:00
Imeon-Energy 85b6adcc9a Fix, entities stay unavailable after timeout error, Imeon inverter integration (#151671)
Co-authored-by: TheBushBoy <theodavid@icloud.com>
2025-09-05 10:29:46 +00:00
Felipe Santos beec6e86e0 Fix WebSocket proxy for add-ons not forwarding ping/pong frame data (#151654) 2025-09-05 10:29:45 +00:00
Pete Sage 3dacffaaf9 Fix Sonos Dialog Select type conversion (#151649) 2025-09-05 10:29:41 +00:00
Manu d90f2a1de1 Correct capitalization of "FRITZ!Box" in FRITZ!Box Tools integration (#151637) 2025-09-05 10:29:39 +00:00
karwosts b6c9217429 Add missing device trigger duration localizations (#151578)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-05 10:29:37 +00:00
Marcel van der Veldt 7fc8da6769 Add support for migrated Hue bridge (#151411)
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-05 10:29:34 +00:00
tronikos 34c45eae56 Translate exceptions in Android TV Remote media player (#151744) 2025-09-05 12:29:06 +02:00
tronikos 71b8da6497 Limit the scope of try except blocks in Android TV Remote (#151746) 2025-09-05 12:28:46 +02:00
tronikos caa0e357ee Improve Android TV Remote tests by testing we can recover from errors (#151752) 2025-09-05 12:26:31 +02:00
Imeon-Energy 0721ac6c73 Fix, entities stay unavailable after timeout error, Imeon inverter integration (#151671)
Co-authored-by: TheBushBoy <theodavid@icloud.com>
2025-09-05 12:11:44 +02:00
Marcel van der Veldt 783c742e09 Add support for migrated Hue bridge (#151411)
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-05 12:09:37 +02:00
tronikos d2324086af Remove unused class variables in Android TV Remote entity (#151743) 2025-09-05 12:04:14 +02:00
Marc Mueller 2ffd5f4c97 Update types packages (#151760) 2025-09-05 11:54:14 +02:00
Norbert Rittel aa4a110923 Improve action descriptions in homematic (#151751) 2025-09-05 11:46:28 +02:00
Artur Pragacz 0a3032e766 Fix recognition of entity names in default agent with interpunction (#151759) 2025-09-05 11:42:56 +02:00
Richard Kroegel c4db422355 Bump bimmer_connected to 0.17.3 (#151756) 2025-09-05 11:37:51 +02:00
Michael Hansen f4e0b9ba15 Handle match failures in intent HTTP API (#151726) 2025-09-05 10:28:37 +02:00
dependabot[bot] f3b997720d Bump actions/github-script from 7 to 8 (#151747)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-05 10:18:31 +02:00
dependabot[bot] f5d3a89f90 Bump codecov/codecov-action from 5.5.0 to 5.5.1 (#151748)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-05 10:17:12 +02:00
Norbert Rittel b90296d853 Remove trailing periods from title strings in sia (#151754) 2025-09-05 10:07:37 +02:00
tronikos c6d6349908 Remove extra whitespace in Android TV Remote strings (#151741) 2025-09-05 09:25:00 +02:00
J. Nick Koston 2be6f17505 Bump aioesphomeapi to 40.0.1 (#151737) 2025-09-05 09:24:28 +02:00
epenet 4c953f36c8 Bump tuya-device-sharing-sdk to 0.2.4 (#151742) 2025-09-05 09:21:34 +02:00
Dan Raper ec2fa202e9 Require OhmeAdvancedSettingsCoordinator to run regardless of entities (#151701) 2025-09-05 07:37:40 +02:00
G Johansson 1a970e6c88 Make sensor startup code more dry in System monitor (#151164) 2025-09-05 07:36:37 +02:00
Dan Raper b9db828df3 Bump ohmepy version to 1.5.2 (#151707) 2025-09-05 04:23:57 +02:00
Daniel Hjelseth Høyer 50c0f41e8f Update Mill library 0.13.1 (#151712) 2025-09-05 04:23:08 +02:00
David Knowles 8cc66ee96c Bump pyschlage to 2025.9.0 (#151731) 2025-09-05 04:21:09 +02:00
Louis Christ 71981975a4 Update pyblu to 2.0.5 and fix code (#151728) 2025-09-04 23:34:59 +01:00
Manu b875af9667 Bump pyotp to v2.9.0 (#151721) 2025-09-05 00:09:23 +02:00
Manu 89cd55c878 Bump habiticalib to v0.4.5 (#151720) 2025-09-04 22:58:28 +01:00
Daniel Hjelseth Høyer b25708cec2 Update Tibber library 0.31.7 (#151711)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2025-09-05 00:21:26 +03:00
Franck Nijhof bb9c65bc4b Update debugpy to v1.8.16 (#151716) 2025-09-05 00:17:58 +03:00
Franck Nijhof 447c7b64a9 Update cryptography to 45.0.7 (#151715) 2025-09-04 23:40:08 +03:00
Marc Mueller b111a33b8c Update ciso8601 to 2.3.3 (#151704) 2025-09-04 13:54:49 -05:00
Marc Mueller 4fcd02bc5d Update requests to 2.32.5 (#151705) 2025-09-04 20:53:16 +02:00
Marc Mueller 80d26b8d2e Update pytest to 8.4.2 (#151706) 2025-09-04 20:52:48 +02:00
flonou a475ecb342 Shelly cover position update when moving (#139008)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
2025-09-04 20:22:07 +03:00
Simone Chemelli 42aec9cd91 Remove attributes from all Shelly entities (#140386) 2025-09-04 20:21:32 +03:00
karwosts 5409181b79 Add missing device trigger duration localizations (#151578)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-04 17:25:25 +02:00
Marc Mueller c1945211fa [ci] Add timeout to install os dependencies step (#151682) 2025-09-04 17:20:17 +02:00
Abílio Costa 29537dc87d Add tests for hassfest conditions module (#151646)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-04 17:18:51 +02:00
Bram Kragten 72e1a8f912 Update frontend to 20250903.3 (#151694) 2025-09-04 17:04:49 +02:00
epenet b742e4898c Ensure Tuya fixtures are correctly referenced (#151691) 2025-09-04 16:53:48 +02:00
Marcel van der Veldt e5565c75f6 Bump aiohue to 4.7.5 (#151684) 2025-09-04 14:44:10 +02:00
epenet a7ca618327 Check badly formatted dhcp addresses in tests (#147814) 2025-09-04 13:43:51 +01:00
epenet 6cbb881647 Drop Tuya compatibility code for mqtt (#151666) 2025-09-04 12:10:58 +02:00
Kevin McCormack eae1fe4a56 Add strict typing, shared constants, and fix OPNsense name casing (#151599) 2025-09-04 11:20:16 +02:00
epenet 8d945d89de Bump tuya-device-sharing-sdk to 0.2.3 (#151659) 2025-09-04 10:37:25 +02:00
dependabot[bot] 86e7f3713f Bump actions/stale from 9.1.0 to 10.0.0 (#151660)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-04 10:11:50 +02:00
Pete Sage 3bc772a196 Fix Sonos Dialog Select type conversion (#151649) 2025-09-04 09:33:43 +02:00
Felipe Santos c2290d6edb Fix WebSocket proxy for add-ons not forwarding ping/pong frame data (#151654) 2025-09-04 09:30:23 +02:00
dependabot[bot] 2a458dcec9 Bump actions/setup-python from 5.6.0 to 6.0.0 (#151662)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-04 09:22:28 +02:00
dependabot[bot] ab5ef3674f Bump pypa/gh-action-pypi-publish from 1.12.4 to 1.13.0 (#151661)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-04 09:22:22 +02:00
Norbert Rittel f28251bc76 Small fixes of user-facing strings in fritz (#151663) 2025-09-04 09:20:15 +02:00
Mike Kelly 1cca65b5c5 Add MCF (1000 Cubic Feet) as an alternate unit of measure for volume (#150015) 2025-09-04 09:29:37 +03:00
karwosts ed134e22f9 Allow defining the start weekday for statistic_during_period (#149033) 2025-09-04 09:27:12 +03:00
Paulus Schoutsen 300c582ea0 Devcontainer fixes for Debian 13 (#151655) 2025-09-04 06:23:45 +02:00
Franck Nijhof 52f7e20b5c Merge branch 'master' into dev 2025-09-03 21:32:40 +00:00
epenet 813098cb1a Use correctly formatted MAC in esphome tests (#151622) 2025-09-03 15:07:03 -05:00
Manu 000df08bca Correct capitalization of "FRITZ!Box" in FRITZ!Box Tools integration (#151637) 2025-09-03 21:23:48 +02:00
J. Nick Koston 9b80cf7d94 Prevent multiple Home Assistant instances from running with the same config directory (#151631) 2025-09-03 13:13:02 -05:00
Franck Nijhof 220c233c0b 2025.9.0 (#151263) 2025-09-03 19:49:19 +02:00
Franck Nijhof cdf7d8df16 Bump version to 2025.9.0 2025-09-03 17:12:06 +00:00
karwosts 3385151c26 Test for async_show_menu sort (#151630) 2025-09-03 18:46:57 +02:00
Franck Nijhof 5db4057781 Bump version to 2025.9.0b6 2025-09-03 16:17:57 +00:00
Bram Kragten 5d9277e4ab Update frontend to 20250903.2 (#151629) 2025-09-03 16:16:36 +00:00
Michael Hansen 67d3a9623d Bump intents (#151627) 2025-09-03 16:14:25 +00:00
Norbert Rittel 0ad44e423b Fix naming of "State of charge" sensor in growatt_server (#151619) 2025-09-03 16:12:59 +00:00
jan iversen cb7097cdf1 Simplify Modbus update methods (#151494) 2025-09-03 16:12:57 +00:00
mattreim 22b8ad9d0b Fix for deCONZ issue - Detected that integration 'deconz' calls device_registry.async_get_or_create referencing a non existing via_device - #134539 (#150355) 2025-09-03 16:12:56 +00:00
Michael Hansen 111fa78c57 Bump intents (#151627) 2025-09-03 18:11:37 +02:00
Erik Montnemery e67df73c4e Clarify behavior of ConfigEntry.async_on_state_change (#151628) 2025-09-03 17:21:28 +02:00
Bram Kragten b9f24bbb2a Update frontend to 20250903.2 (#151629) 2025-09-03 16:54:37 +02:00
karwosts 18ca9590f0 Sort template config menu step by user language (#151596) 2025-09-03 17:02:45 +03:00
Paulus Schoutsen eccadd4a11 script/bootstrap to update core deps (#151624) 2025-09-03 09:58:29 -04:00
BenJewell aeff62faea Correct critical notification variable name in Flo (#151523)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-03 14:15:13 +01:00
Norbert Rittel e5a44e5966 Fix naming of "State of charge" sensor in growatt_server (#151619) 2025-09-03 15:13:04 +02:00
mattreim 1369a98fa3 Fix for deCONZ issue - Detected that integration 'deconz' calls device_registry.async_get_or_create referencing a non existing via_device - #134539 (#150355) 2025-09-03 14:28:52 +02:00
jan iversen 0e1dd04083 Simplify Modbus update methods (#151494) 2025-09-03 14:23:36 +02:00
G Johansson df46816b2f Add reload support to schema options flow handler (#151260) 2025-09-03 12:55:21 +01:00
Jack 955ef3b5e7 Remove deprecated target position attributes from ZHA covers (#142534)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-03 13:43:29 +02:00
Franck Nijhof 26c9d283a4 Bump version to 2025.9.0b5 2025-09-03 11:38:27 +00:00
Bram Kragten 4dbccbc056 Update frontend to 20250903.1 (#151617) 2025-09-03 11:38:03 +00:00
Erik Montnemery 17466ce866 Bump device registry version to 1.12 (#151616) 2025-09-03 11:38:02 +00:00
Erik Montnemery 422862a699 Handle colliding aliases for floors (#151614) 2025-09-03 11:38:00 +00:00
Erik Montnemery 5be2e4e14b Handle colliding aliases for areas (#151613) 2025-09-03 11:37:59 +00:00
Bram Kragten 75ebbe60db Update frontend to 20250903.0 (#151612) 2025-09-03 11:37:58 +00:00
Robert Resch f0e18cc63d Bump aioecowitt to 2025.9.0 (#151608) 2025-09-03 11:37:57 +00:00
Krisjanis Lejejs c2b4e9b075 Bump hass-nabucasa from 1.0.0 to 1.1.0 (#151606) 2025-09-03 11:37:55 +00:00
jan iversen baa1c51bcf Fix racing bug in slave entities in Modbus (#151522) 2025-09-03 11:37:54 +00:00
Bram Kragten 5fc6fb9cf3 Update frontend to 20250903.1 (#151617) 2025-09-03 13:31:33 +02:00
Erik Montnemery 9ee9e1775d Bump device registry version to 1.12 (#151616) 2025-09-03 13:12:49 +02:00
jan iversen 712c9b9edc Fix racing bug in slave entities in Modbus (#151522) 2025-09-03 13:09:42 +02:00
Erik Montnemery d571857770 Handle colliding aliases for floors (#151614) 2025-09-03 12:43:03 +02:00
Bram Kragten de90922297 Update frontend to 20250903.0 (#151612) 2025-09-03 12:42:27 +02:00
Erik Montnemery e0b3a5337c Handle colliding aliases for areas (#151613) 2025-09-03 12:39:03 +02:00
Yevhenii Vaskivskyi 215603fae1 Bump asusrouter to 1.21.0 (#151607) 2025-09-03 12:16:00 +02:00
Krisjanis Lejejs 1a12c619e9 Bump hass-nabucasa from 1.0.0 to 1.1.0 (#151606) 2025-09-03 12:12:29 +02:00
yufeng 34c061df19 Add energy consumption/production for Tuya kg category (smart switches) (#149234) 2025-09-03 11:47:23 +02:00
yufeng c12b638b3d Adds initial support for tuya category xnyjcn (solar inverter) (#151549)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2025-09-03 11:39:54 +02:00
Robert Resch b9427deed2 Bump aioecowitt to 2025.9.0 (#151608) 2025-09-03 11:34:45 +02:00
yufeng d66016588b Add support for new energy sensor entities for DLQ (circuit breaker) devices in the Tuya integration (#151551)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2025-09-03 11:34:08 +02:00
Franck Nijhof a1d484fa73 Bump version to 2025.9.0b4 2025-09-03 09:24:19 +00:00
Paul Bottein 6013f50aa6 Update frontend to 20250902.1 (#151593) 2025-09-03 09:23:18 +00:00
Stefan Agner b4ab63d9db Update Home Assistant base image to 2025.09.0 (#151582) 2025-09-03 09:23:16 +00:00
Thomas D 7229781aeb Bump volvocarsapi to v0.4.2 (#151579) 2025-09-03 09:23:15 +00:00
Erik Montnemery 465512b0ea Improve migration to device registry version 1.10 (#151571) 2025-09-03 09:23:14 +00:00
Erik Montnemery 75d6c0bb53 Improve migration to entity registry version 1.18 (#151570) 2025-09-03 09:23:12 +00:00
Erik Montnemery 7500406e36 Revert "Improve migration to device registry version 1.11" (#151563) 2025-09-03 09:23:11 +00:00
Erik Montnemery 2afbca9751 Revert "Improve migration to entity registry version 1.18" (#151561) 2025-09-03 09:23:09 +00:00
Simone Chemelli 6023a8e6b0 Remove config entry from device instead of deleting in Uptime robot (#151557) 2025-09-03 09:23:08 +00:00
Erik Montnemery 869801b643 Exclude non mowers from husqvarna_automower_ble discovery (#151507) 2025-09-03 09:23:07 +00:00
Stefan Agner 229d0bdc77 Update Home Assistant base image to 2025.09.0 (#151582) 2025-09-03 11:12:18 +02:00
Erik Montnemery 078425918e Improve migration to device registry version 1.10 (#151571) 2025-09-03 10:22:29 +02:00
Erik Montnemery da2f154111 Improve migration to entity registry version 1.18 (#151570) 2025-09-03 10:08:59 +02:00
yufeng 270a9a5a98 Add support for new power sensor entities for ZNDB (smart energy meter) devices in the Tuya integration (#151554) 2025-09-03 09:22:20 +02:00
Lucas Mindêllo de Andrade 9f953c2e35 Tuya add missing sensors for Metering_3PN_ZB (dlq) device (#151601) 2025-09-03 09:13:24 +02:00
Artur Pragacz 8f16b09751 Accept None directly in the selector schemas (#151510)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-03 08:37:43 +02:00
dependabot[bot] 73ab041051 Bump github/codeql-action from 3.29.11 to 3.30.0 (#151600)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-03 08:10:07 +02:00
Paul Bottein 4bb76c6d94 Update frontend to 20250902.1 (#151593) 2025-09-02 22:55:03 -03:00
Brandon Rothweiler 7378d3607c Update py-aosmith to 1.0.14 (#151597) 2025-09-02 22:34:37 +01:00
Florian von Garrel 7d1e36af7f Raise paperless to platinum (#151588) 2025-09-02 22:27:56 +01:00
Petar Petrov 8b03a23ed8 Add option descriptions to Z-Wave reconfigure flow (#151558)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-09-02 22:06:07 +01:00
Michael Hansen a023dfc013 Add required features to vacuum intents (#151581) 2025-09-02 14:10:31 -05:00
J. Nick Koston fa0f707872 Add bluetooth websocket_api to subscribe to scanner state (#151452)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-02 15:17:27 -03:00
Joost Lekkerkerker a8f56e4b96 Fix Slide local tests (#151569)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-02 18:21:38 +02:00
Marc Mueller 61c904d225 Update pytest-rerunfailures to 16.0.1 (#151573) 2025-09-02 17:11:15 +01:00
Thomas D a8ff14ecb8 Bump volvocarsapi to v0.4.2 (#151579) 2025-09-02 17:09:21 +01:00
Michael Hansen 3909906823 Add required features for mowing intents (#151580) 2025-09-02 11:02:38 -05:00
Blear e0bf7749e6 Adjust Zhong_Hong climate set_fan_mode to lowercase (#151559) 2025-09-02 17:00:05 +02:00
Paul Bottein 72128e9708 Add start mowing and dock intents for lawn mower (#140525) 2025-09-02 09:49:24 -05:00
cdnninja 1b9acdc233 Convert Vesync to 3.X version of library (#148239)
Co-authored-by: SapuSeven <sapuseven@gmail.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2025-09-02 15:31:38 +02:00
Maciej Bieniek 0f530485d1 Record current IQS for NextDNS (#146895)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-02 15:07:25 +02:00
Christopher Fenner 0928e9a6ee Add sensor for DHW storage temperature in ViCare integration (#151128) 2025-09-02 13:24:42 +02:00
Marc Mueller 75d792207a Add missing pychromecast imports (#151544) 2025-09-02 13:24:00 +02:00
yufeng ceda62f6ea Add support for new energy sensor entities for TDQ (socket/outlet) devices in the Tuya integration (#151553) 2025-09-02 13:10:36 +02:00
Avi Miller 12ab84a5d9 Expose the transition field to the UI config of effect_colorloop (#151124)
Signed-off-by: Avi Miller <me@dje.li>
2025-09-02 13:07:48 +02:00
Simone Chemelli 8e85faf997 Update SamsungTV quality scale (#151552) 2025-09-02 13:06:33 +02:00
Simone Chemelli b514a14c10 Remove config entry from device instead of deleting in Uptime robot (#151557) 2025-09-02 13:06:07 +02:00
Erik Montnemery 6b609b019e Exclude non mowers from husqvarna_automower_ble discovery (#151507) 2025-09-02 12:57:39 +02:00
Erik Montnemery 10baae92a0 Revert "Improve migration to device registry version 1.11" (#151563) 2025-09-02 11:58:27 +02:00
Erik Montnemery 8e1ee32190 Revert "Improve migration to entity registry version 1.18" (#151561) 2025-09-02 11:54:37 +02:00
Abílio Costa 814b98c2a3 Add tests for hassfest triggers module (#151318) 2025-09-02 10:45:55 +02:00
Franck Nijhof ed9e46bbca Bump version to 2025.9.0b3 2025-09-02 08:42:14 +00:00
Abílio Costa ac4eef0571 Add back missing controller cleanup to Govee Light Local (#151541) 2025-09-02 08:42:08 +00:00
Abílio Costa 1039936f39 Filter out IPv6 addresses in Govee Light Local (#151540) 2025-09-02 08:42:06 +00:00
Lukas 9910df2b21 Remove mac address from Pooldose device (#151536)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2025-09-02 08:42:05 +00:00
Bram Kragten e57019a80b Update frontend to 20250901.0 (#151529) 2025-09-02 08:42:03 +00:00
Imeon-Energy 1f6853db28 Fix typo in const.py for Imeon inverter integration (#151515)
Co-authored-by: TheBushBoy <theodavid@icloud.com>
2025-09-02 08:42:02 +00:00
Andrew Jackson dc4d6ddbef Bump aiomealie to 0.10.2 (#151514) 2025-09-02 08:42:00 +00:00
Antoni Czaplicki 399286deae Remove the vulcan integration (#151504) 2025-09-02 08:41:59 +00:00
Joost Lekkerkerker 1a2898cc89 Update Pooldose quality scale (#151499) 2025-09-02 08:41:57 +00:00
Iskra kranj d9629affca Bump pyiskra to 0.1.26 (#151489) 2025-09-02 08:41:56 +00:00
Willem-Jan van Rootselaar 9581c705b9 Fix add checks for None values and check if DHW is available (#151376) 2025-09-02 08:41:55 +00:00
Andrea Turri e2a4a9393e Miele refrigerators cause index out of range errors when offline (#151299) 2025-09-02 08:41:53 +00:00
Norbert Rittel f32d12c519 Fix wrong description for numeric_state observation in bayesian (#151291) 2025-09-02 08:41:52 +00:00
Artur Pragacz 18ce6da4e6 Allow ignored Onkyo devices to be set up from the user flow (#150921) 2025-09-02 08:41:51 +00:00
Jozef Kruszynski 031ae3a921 Fix sort order in media browser for music assistant integration (#150910) 2025-09-02 08:41:49 +00:00
Artur Pragacz bbe66f5cea Improve unpair schema in homekit (#150235) 2025-09-02 08:41:48 +00:00
Phil Male 9f4369dc8b Use average color for Hue light group state (#149499) 2025-09-02 08:41:46 +00:00
Abílio Costa 243569f6b8 Add back missing controller cleanup to Govee Light Local (#151541) 2025-09-02 10:37:43 +02:00
Abílio Costa 4b7817f1df Filter out IPv6 addresses in Govee Light Local (#151540) 2025-09-02 10:27:38 +02:00
Antoni Czaplicki 180f898bfa Remove the vulcan integration (#151504) 2025-09-02 01:10:07 +02:00
Mathis Dirksen-Thedens e9dcde1bb5 Allow overriding default recipient in Signal messenger (#145654)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-09-01 23:20:26 +01:00
Bram Kragten f44b6a3a39 Update frontend to 20250901.0 (#151529) 2025-09-01 23:37:49 +02:00
Lukas 9b6b8003ec Remove mac address from Pooldose device (#151536)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2025-09-01 23:19:24 +02:00
Jan-Philipp Benecke 2503157282 Deprecate LANnouncer integration (#151531) 2025-09-01 22:31:25 +02:00
Sab44 7b2b3e9e33 Add Libre Hardware Monitor integration (#140449) 2025-09-01 22:12:12 +02:00
Abílio Costa 2d5f228308 Use MockConfigEntry.start_reauth_flow in Roborock's tests (#151528) 2025-09-01 21:28:42 +02:00
Nolan Stover 19f36fc630 Bump zabbix-utils to 2.0.3 (#149450)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-09-01 20:07:11 +01:00
Andrea Turri 6b6553dae3 Miele time sensors 2/3 - Provide consistent behavior with appliance status (#146053)
Co-authored-by: Robert Resch <robert@resch.dev>
2025-09-01 20:20:24 +02:00
Robert Resch 0865d3f749 Add support for stream orientation in go2rtc (#148832) 2025-09-01 19:06:01 +01:00
Ravaka Razafimanantsoa 095f73d84f Add Switchbot Cloud AC Off (#138648)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-09-01 19:52:43 +02:00
Andrea Turri 3b60961f02 Miele refrigerators cause index out of range errors when offline (#151299) 2025-09-01 19:28:08 +02:00
Yevhenii Vaskivskyi 0d9079ea72 Add model_id and serial_number to the device description (asuswrt) (#151516) 2025-09-01 18:08:53 +02:00
Andrew Jackson f17db80428 Bump aiomealie to 0.10.2 (#151514) 2025-09-01 18:07:36 +02:00
Imeon-Energy 2d4b2e822a Fix typo in const.py for Imeon inverter integration (#151515)
Co-authored-by: TheBushBoy <theodavid@icloud.com>
2025-09-01 17:54:16 +02:00
Yuxin Wang b08a72a53d Move APC UPS Daemon integration to platinum (#151335) 2025-09-01 17:26:31 +02:00
dontinelli 1e4fa40a77 Extend effect of invert_position to cover status for slide_local (#150418) 2025-09-01 17:25:59 +02:00
Jan Bouwhuis ac0ff96f26 Sort MQTT test cases for subentry config flow (#151426) 2025-09-01 17:23:27 +02:00
Jan Bouwhuis 2e50cee555 Sort globals and helpers in MQTT config flow (#151419) 2025-09-01 17:22:58 +02:00
Artur Pragacz 51c6c1b0d2 Allow ignored Onkyo devices to be set up from the user flow (#150921) 2025-09-01 17:04:06 +02:00
Artur Pragacz c4fce1c793 Improve unpair schema in homekit (#150235) 2025-09-01 09:57:24 -05:00
Willem-Jan van Rootselaar 581f8a9378 Fix add checks for None values and check if DHW is available (#151376) 2025-09-01 16:47:59 +02:00
Artur Pragacz d7e6f84d28 Fix empty selector validation (#151340) 2025-09-01 16:22:41 +02:00
Artur Pragacz 5e22533fc0 Code quality improvements of the selector helper (#151505) 2025-09-01 16:18:17 +02:00
Fabian Leutgeb ecae074dd7 Homekit valve duration properties (#150273)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-09-01 08:24:50 -05:00
Franck Nijhof 249dbf976f Bump version to 2025.9.0b2 2025-09-01 10:36:21 +00:00
Imeon-Energy 8d1a45bb8b Missing state for inverter state sensor in Imeon inverter (#151493)
Co-authored-by: TheBushBoy <theodavid@icloud.com>
2025-09-01 10:36:02 +00:00
Joost Lekkerkerker e3d08d5f26 Set Aladdin Connect integration type to hub (#151491) 2025-09-01 10:36:00 +00:00
Marc Mueller a67919fd7c Fix backup manager delete backup error filter (#151490) 2025-09-01 10:35:59 +00:00
Denis Shulyaka 5edb786aad Allow structure field of ai_task.generate_data for non-advanced users (#151481) 2025-09-01 10:35:57 +00:00
J. Nick Koston bfa3b53409 Bump bluetooth-adapters to 2.1.0 and habluetooth to 5.3.0 (#151465) 2025-09-01 10:35:56 +00:00
tronikos 0050626d8c Bump opower to 0.15.4 (#151443) 2025-09-01 10:35:54 +00:00
Brett Adams 74c91e46f2 Fix history startup failures (#151439) 2025-09-01 10:35:52 +00:00
J. Nick Koston d00bf4b014 Fix Yale Access Bluetooth key discovery timing issues (#151433)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-01 10:34:52 +00:00
Thomas55555 fbab53bd0c Bump aioautomower to 2.2.1 (#151427) 2025-09-01 10:29:59 +00:00
Maciej Bieniek 66442f1714 Allow integration to initialize when BraviaTV is offline (#151415) 2025-09-01 10:29:56 +00:00
Aaron Bach 281bf2f308 Bump aiopurpleair to 2025.08.1 (#151398) 2025-09-01 10:29:54 +00:00
Michael Hansen d9af4f1b3c Bump intents to 2025.8.29 (#151397) 2025-09-01 10:28:53 +00:00
Russell VanderMey b86c37f556 Avoid blocking IO in TRIGGERcmd (#151396) 2025-09-01 10:27:25 +00:00
karwosts 94081e011b Fix play media example data (#151394) 2025-09-01 10:27:23 +00:00
J. Nick Koston 5428c6fc23 Bump habluetooth to 5.2.1 (#151391) 2025-09-01 10:27:22 +00:00
Paul Bottein 737ee51b53 Update frontend to 20250829.0 (#151390) 2025-09-01 10:26:33 +00:00
J. Nick Koston 9d0e222671 Reduce log spam from unauthenticated websocket connections (#151388) 2025-09-01 10:25:29 +00:00
Arjan a972c1e0b0 Fix typo in Meteo France mappings (#151344) 2025-09-01 10:25:27 +00:00
Simone Chemelli aea39133d0 Change sounds list source for Alexa Devices (#151317) 2025-09-01 10:25:26 +00:00
jan iversen 12c9f6bea9 modbus: Do not modify registers (return wrong data). (#151131) 2025-09-01 10:25:25 +00:00
Yevhenii Vaskivskyi afdb004aa0 Fix bug with the wrong temperature scale on new router firmware (asuswrt) (#151011) 2025-09-01 10:25:23 +00:00
Franck Nijhof 3ea0e9ee88 Bump version to 2025.9.0b1 2025-08-29 15:17:32 +00:00
Erik Montnemery bec8cf3ea8 Fix restoring disabled_by flag of deleted devices (#151313) 2025-08-29 15:16:24 +00:00
J. Nick Koston e21c2fa08b Bump aioesphomeapi to 39.0.1 (#151385) 2025-08-29 15:12:34 +00:00
Marc Mueller 900b59d148 Pin pytest-rerunfailures to 15.1 (#151383) 2025-08-29 15:12:33 +00:00
J. Nick Koston 0a9203e241 Bump bleak-esphome to 3.2.0 (#151380) 2025-08-29 15:12:31 +00:00
J. Nick Koston c69c3e7d85 Bump nexia to 2.11.1 (#151379) 2025-08-29 15:12:30 +00:00
starkillerOG a938a33e98 Bump reolink-aio to 0.15.0 (#151367)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-08-29 15:12:29 +00:00
Tom 2d62c5f8d6 Bump airOS to 0.4.4 (#151345) 2025-08-29 15:12:27 +00:00
J. Nick Koston da4ec7b3dd Bump bleak-retry-connector to 4.4.3 (#151341) 2025-08-29 15:12:26 +00:00
J. Nick Koston 1ffc0560c5 Bump habluetooth to 5.2.0 (#151333) 2025-08-29 15:12:25 +00:00
Robert Resch 68ec41c43a Bump deebot-client to 13.7.0 (#151327) 2025-08-29 15:12:23 +00:00
Paul Bottein 24017a9555 Update frontend to 20250828.0 (#151321) 2025-08-29 15:12:22 +00:00
J. Nick Koston 6f17c1653c Bump nexia to 2.11.0 (#151319) 2025-08-29 15:12:21 +00:00
Erik Montnemery f49ce2a77a Improve migration to device registry version 1.11 (#151315)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-08-29 15:12:19 +00:00
Yevhenii Vaskivskyi 282ec58c4e Bump asusrouter to 1.20.1 (#151311) 2025-08-29 15:07:34 +00:00
Erik Montnemery 32cbd2a239 Improve migration to entity registry version 1.18 (#151308)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-08-29 15:07:33 +00:00
Martin Hjelmare 12b161e154 Fix Z-Wave duplicate notification binary sensors (#151304) 2025-08-29 15:07:32 +00:00
starkillerOG d0866704ba Fix Reolink duplicates due to wrong merge (#151298) 2025-08-29 15:07:30 +00:00
Simone Chemelli b23bf164f1 Add missing state class to Alexa Devices sensors (#151296) 2025-08-29 15:07:29 +00:00
Simone Chemelli 894fb6ee66 Fix exception countries migration for Alexa Devices (#151292) 2025-08-29 15:07:28 +00:00
Arjan d5e9d2b9dc Adding missing: Averses de grèle (#151288) 2025-08-29 15:07:27 +00:00
Felipe Santos 2de572ea11 Fix ONVIF not displaying sensor and binary_sensor entity names (#151285) 2025-08-29 15:07:25 +00:00
Jamie Magee def27ab705 Remove uv.lock (#151282) 2025-08-29 15:07:24 +00:00
Andrew Jackson ab7c5bf8d9 Fix endpoint deprecation warning in Mastodon (#151275) 2025-08-29 15:07:22 +00:00
G Johansson a57d77899a Fix spelling in bayesian strings (#151265) 2025-08-29 15:07:21 +00:00
Florent Thoumie e2ca439a3a Iaqualink: create parent device manually and link entities (#151215) 2025-08-29 15:07:20 +00:00
Manu 5d64dae3a0 Fix direct message notifiers in PlayStation Network (#150548) 2025-08-29 15:07:18 +00:00
Manu 821577dc21 Ignore errors when PlayStation Network group fetch is blocked by parental controls (#150364) 2025-08-29 15:07:17 +00:00
Ian Tewksbury 0eaf8c6946 Add multiple NICs in govee_light_local (#128123) 2025-08-29 15:07:15 +00:00
Franck Nijhof f955dec1ba Bump version to 2025.9.0b0 2025-08-27 18:06:45 +00:00
1823 changed files with 107363 additions and 20535 deletions
@@ -0,0 +1,77 @@
---
name: quality-scale-rule-verifier
description: |
Use this agent when you need to verify that a Home Assistant integration follows a specific quality scale rule. This includes checking if the integration implements required patterns, configurations, or code structures defined by the quality scale system.
<example>
Context: The user wants to verify if an integration follows a specific quality scale rule.
user: "Check if the peblar integration follows the config-flow rule"
assistant: "I'll use the quality scale rule verifier to check if the peblar integration properly implements the config-flow rule."
<commentary>
Since the user is asking to verify a quality scale rule implementation, use the quality-scale-rule-verifier agent.
</commentary>
</example>
<example>
Context: The user is reviewing if an integration reaches a specific quality scale level.
user: "Verify that this integration reaches the bronze quality scale"
assistant: "Let me use the quality scale rule verifier to check the bronze quality scale implementation."
<commentary>
The user wants to verify the integration has reached a certain quality level, so use multiple quality-scale-rule-verifier agents to verify each bronze rule.
</commentary>
</example>
model: inherit
color: yellow
tools: Read, Bash, Grep, Glob, WebFetch
---
You are an expert Home Assistant integration quality scale auditor specializing in verifying compliance with specific quality scale rules. You have deep knowledge of Home Assistant's architecture, best practices, and the quality scale system that ensures integration consistency and reliability.
You will verify if an integration follows a specific quality scale rule by:
1. **Fetching Rule Documentation**: Retrieve the official rule documentation from:
`https://raw.githubusercontent.com/home-assistant/developers.home-assistant/refs/heads/master/docs/core/integration-quality-scale/rules/{rule_name}.md`
where `{rule_name}` is the rule identifier (e.g., 'config-flow', 'entity-unique-id', 'parallel-updates')
2. **Understanding Rule Requirements**: Parse the rule documentation to identify:
- Core requirements and mandatory implementations
- Specific code patterns or configurations required
- Common violations and anti-patterns
- Exemption criteria (when a rule might not apply)
- The quality tier this rule belongs to (Bronze, Silver, Gold, Platinum)
3. **Analyzing Integration Code**: Examine the integration's codebase at `homeassistant/components/<integration domain>` focusing on:
- `manifest.json` for quality scale declaration and configuration
- `quality_scale.yaml` for rule status (done, todo, exempt)
- Relevant Python modules based on the rule requirements
- Configuration files and service definitions as needed
4. **Verification Process**:
- Check if the rule is marked as 'done', 'todo', or 'exempt' in quality_scale.yaml
- If marked 'exempt', verify the exemption reason is valid
- If marked 'done', verify the actual implementation matches requirements
- Identify specific files and code sections that demonstrate compliance or violations
- Consider the integration's declared quality tier when applying rules
- To fetch the integration docs, use WebFetch to fetch from `https://raw.githubusercontent.com/home-assistant/home-assistant.io/refs/heads/current/source/_integrations/<integration domain>.markdown`
- To fetch information about a PyPI package, use the URL `https://pypi.org/pypi/<package>/json`
5. **Reporting Findings**: Provide a comprehensive verification report that includes:
- **Rule Summary**: Brief description of what the rule requires
- **Compliance Status**: Clear pass/fail/exempt determination
- **Evidence**: Specific code examples showing compliance or violations
- **Issues Found**: Detailed list of any non-compliance issues with file locations
- **Recommendations**: Actionable steps to achieve compliance if needed
- **Exemption Analysis**: If applicable, whether the exemption is justified
When examining code, you will:
- Look for exact implementation patterns specified in the rule
- Verify all required components are present and properly configured
- Check for common mistakes and anti-patterns
- Consider edge cases and error handling requirements
- Validate that implementations follow Home Assistant conventions
You will be thorough but focused, examining only the aspects relevant to the specific rule being verified. You will provide clear, actionable feedback that helps developers understand both what needs to be fixed and why it matters for integration quality.
If you cannot access the rule documentation or find the integration code, clearly state what information is missing and what you would need to complete the verification.
Remember that quality scale rules are cumulative - Bronze rules apply to all integrations with a quality scale, Silver rules apply to Silver+ integrations, and so on. Always consider the integration's target quality level when determining which rules should be enforced.
+1
View File
@@ -58,6 +58,7 @@ base_platforms: &base_platforms
# Extra components that trigger the full suite
components: &components
- homeassistant/components/alexa/**
- homeassistant/components/analytics/**
- homeassistant/components/application_credentials/**
- homeassistant/components/assist_pipeline/**
- homeassistant/components/auth/**
+2
View File
@@ -8,6 +8,8 @@
"PYTHONASYNCIODEBUG": "1"
},
"features": {
// Node feature required for Claude Code until fixed https://github.com/anthropics/devcontainer-features/issues/28
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
+5
View File
@@ -55,8 +55,12 @@
creating the PR. If you're unsure about any of them, don't hesitate to ask.
We're here to help! This is simply a reminder of what we are going to look
for before merging your code.
AI tools are welcome, but contributors are responsible for *fully*
understanding the code before submitting a PR.
-->
- [ ] I understand the code I am submitting and can explain how it works.
- [ ] The code change is tested and works locally.
- [ ] Local tests pass. **Your PR cannot be merged unless tests pass**
- [ ] There is no commented out code in this PR.
@@ -64,6 +68,7 @@
- [ ] I have followed the [perfect PR recommendations][perfect-pr]
- [ ] The code has been formatted using Ruff (`ruff format homeassistant tests`)
- [ ] Tests have been added to verify that the new code works.
- [ ] Any generated code has been carefully reviewed for correctness and compliance with project standards.
If user exposed functionality or configuration variables are added/changed:
+24 -22
View File
@@ -27,12 +27,12 @@ jobs:
publish: ${{ steps.version.outputs.publish }}
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -69,7 +69,7 @@ jobs:
run: find ./homeassistant/components/*/translations -name "*.json" | tar zcvf translations.tar.gz -T -
- name: Upload translations
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: translations
path: translations.tar.gz
@@ -90,11 +90,11 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Download nightly wheels of frontend
if: needs.init.outputs.channel == 'dev'
uses: dawidd6/action-download-artifact@v11
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11
with:
github_token: ${{secrets.GITHUB_TOKEN}}
repo: home-assistant/frontend
@@ -105,7 +105,7 @@ jobs:
- name: Download nightly wheels of intents
if: needs.init.outputs.channel == 'dev'
uses: dawidd6/action-download-artifact@v11
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11
with:
github_token: ${{secrets.GITHUB_TOKEN}}
repo: OHF-Voice/intents-package
@@ -116,7 +116,7 @@ jobs:
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
if: needs.init.outputs.channel == 'dev'
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -175,7 +175,7 @@ jobs:
sed -i "s|pykrakenapi|# pykrakenapi|g" requirements_all.txt
- name: Download translations
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: translations
@@ -190,14 +190,15 @@ jobs:
echo "${{ github.sha }};${{ github.ref }};${{ github.event_name }};${{ github.actor }}" > rootfs/OFFICIAL_IMAGE
- name: Login to GitHub Container Registry
uses: docker/login-action@v3.5.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
# home-assistant/builder doesn't support sha pinning
- name: Build base image
uses: home-assistant/builder@2025.03.0
uses: home-assistant/builder@2025.09.0
with:
args: |
$BUILD_ARGS \
@@ -242,7 +243,7 @@ jobs:
- green
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set build additional args
run: |
@@ -256,14 +257,15 @@ jobs:
fi
- name: Login to GitHub Container Registry
uses: docker/login-action@v3.5.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
# home-assistant/builder doesn't support sha pinning
- name: Build base image
uses: home-assistant/builder@2025.03.0
uses: home-assistant/builder@2025.09.0
with:
args: |
$BUILD_ARGS \
@@ -279,7 +281,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Initialize git
uses: home-assistant/actions/helpers/git-init@master
@@ -321,23 +323,23 @@ jobs:
registry: ["ghcr.io/home-assistant", "docker.io/homeassistant"]
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install Cosign
uses: sigstore/cosign-installer@v3.9.2
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
with:
cosign-release: "v2.2.3"
- name: Login to DockerHub
if: matrix.registry == 'docker.io/homeassistant'
uses: docker/login-action@v3.5.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
if: matrix.registry == 'ghcr.io/home-assistant'
uses: docker/login-action@v3.5.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
@@ -454,15 +456,15 @@ jobs:
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Download translations
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: translations
@@ -480,7 +482,7 @@ jobs:
python -m build
- name: Upload package to PyPI
uses: pypa/gh-action-pypi-publish@v1.12.4
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with:
skip-existing: true
+222 -94
View File
@@ -37,10 +37,10 @@ on:
type: boolean
env:
CACHE_VERSION: 7
CACHE_VERSION: 8
UV_CACHE_VERSION: 1
MYPY_CACHE_VERSION: 1
HA_SHORT_VERSION: "2025.10"
HA_SHORT_VERSION: "2025.11"
DEFAULT_PYTHON: "3.13"
ALL_PYTHON_VERSIONS: "['3.13']"
# 10.3 is the oldest supported version
@@ -61,6 +61,9 @@ env:
POSTGRESQL_VERSIONS: "['postgres:12.14','postgres:15.2']"
PRE_COMMIT_CACHE: ~/.cache/pre-commit
UV_CACHE_DIR: /tmp/uv-cache
APT_CACHE_BASE: /home/runner/work/apt
APT_CACHE_DIR: /home/runner/work/apt/cache
APT_LIST_CACHE_DIR: /home/runner/work/apt/lists
SQLALCHEMY_WARN_20: 1
PYTHONASYNCIODEBUG: 1
HASS_CI: 1
@@ -78,6 +81,7 @@ jobs:
core: ${{ steps.core.outputs.changes }}
integrations_glob: ${{ steps.info.outputs.integrations_glob }}
integrations: ${{ steps.integrations.outputs.changes }}
apt_cache_key: ${{ steps.generate_apt_cache_key.outputs.key }}
pre-commit_cache_key: ${{ steps.generate_pre-commit_cache_key.outputs.key }}
python_cache_key: ${{ steps.generate_python_cache_key.outputs.key }}
requirements: ${{ steps.core.outputs.requirements }}
@@ -94,7 +98,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Generate partial Python venv restore key
id: generate_python_cache_key
run: |
@@ -111,8 +115,12 @@ jobs:
run: >-
echo "key=pre-commit-${{ env.CACHE_VERSION }}-${{
hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
- name: Generate partial apt restore key
id: generate_apt_cache_key
run: |
echo "key=$(lsb_release -rs)-apt-${{ env.CACHE_VERSION }}-${{ env.HA_SHORT_VERSION }}" >> $GITHUB_OUTPUT
- name: Filter for core changes
uses: dorny/paths-filter@v3.0.2
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: core
with:
filters: .core_files.yaml
@@ -127,7 +135,7 @@ jobs:
echo "Result:"
cat .integration_paths.yaml
- name: Filter for integration changes
uses: dorny/paths-filter@v3.0.2
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: integrations
with:
filters: .integration_paths.yaml
@@ -246,16 +254,16 @@ jobs:
- info
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v4.2.4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
key: >-
@@ -271,7 +279,7 @@ jobs:
uv pip install "$(cat requirements_test.txt | grep pre-commit)"
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v4.2.4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ env.PRE_COMMIT_CACHE }}
lookup-only: true
@@ -292,16 +300,16 @@ jobs:
- pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -310,7 +318,7 @@ jobs:
needs.info.outputs.pre-commit_cache_key }}
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ env.PRE_COMMIT_CACHE }}
fail-on-cache-miss: true
@@ -332,16 +340,16 @@ jobs:
- pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -350,7 +358,7 @@ jobs:
needs.info.outputs.pre-commit_cache_key }}
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ env.PRE_COMMIT_CACHE }}
fail-on-cache-miss: true
@@ -372,16 +380,16 @@ jobs:
- pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -390,7 +398,7 @@ jobs:
needs.info.outputs.pre-commit_cache_key }}
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ env.PRE_COMMIT_CACHE }}
fail-on-cache-miss: true
@@ -462,7 +470,7 @@ jobs:
- script/hassfest/docker/Dockerfile
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Register hadolint problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/hadolint.json"
@@ -481,10 +489,10 @@ jobs:
python-version: ${{ fromJSON(needs.info.outputs.python_versions) }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
@@ -497,7 +505,7 @@ jobs:
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v4.2.4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
key: >-
@@ -505,7 +513,7 @@ jobs:
needs.info.outputs.python_cache_key }}
- name: Restore uv wheel cache
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache@v4.2.4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ env.UV_CACHE_DIR }}
key: >-
@@ -515,15 +523,38 @@ jobs:
${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-uv-${{
env.UV_CACHE_VERSION }}-${{ steps.generate-uv-key.outputs.version }}-${{
env.HA_SHORT_VERSION }}-
- name: Check if apt cache exists
id: cache-apt-check
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
lookup-only: ${{ steps.cache-venv.outputs.cache-hit == 'true' }}
path: |
${{ env.APT_CACHE_DIR }}
${{ env.APT_LIST_CACHE_DIR }}
key: >-
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
- name: Install additional OS dependencies
if: steps.cache-venv.outputs.cache-hit != 'true'
if: |
steps.cache-venv.outputs.cache-hit != 'true'
|| steps.cache-apt-check.outputs.cache-hit != 'true'
timeout-minutes: 10
run: |
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get update
if [[ "${{ steps.cache-apt-check.outputs.cache-hit }}" != 'true' ]]; then
mkdir -p ${{ env.APT_CACHE_DIR }}
mkdir -p ${{ env.APT_LIST_CACHE_DIR }}
fi
sudo apt-get update \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }}
sudo apt-get -y install \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }} \
bluez \
ffmpeg \
libturbojpeg \
libxml2-utils \
libavcodec-dev \
libavdevice-dev \
libavfilter-dev \
@@ -533,6 +564,19 @@ jobs:
libswresample-dev \
libswscale-dev \
libudev-dev
if [[ "${{ steps.cache-apt-check.outputs.cache-hit }}" != 'true' ]]; then
sudo chmod -R 755 ${{ env.APT_CACHE_BASE }}
fi
- name: Save apt cache
if: steps.cache-apt-check.outputs.cache-hit != 'true'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: |
${{ env.APT_CACHE_DIR }}
${{ env.APT_LIST_CACHE_DIR }}
key: >-
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
@@ -552,7 +596,7 @@ jobs:
python --version
uv pip freeze >> pip_freeze.txt
- name: Upload pip_freeze artifact
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pip-freeze-${{ matrix.python-version }}
path: pip_freeze.txt
@@ -577,23 +621,37 @@ jobs:
- info
- base
steps:
- name: Restore apt cache
uses: actions/cache/restore@v4.3.0
with:
path: |
${{ env.APT_CACHE_DIR }}
${{ env.APT_LIST_CACHE_DIR }}
fail-on-cache-miss: true
key: >-
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
- name: Install additional OS dependencies
timeout-minutes: 10
run: |
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get update
sudo apt-get update \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }}
sudo apt-get -y install \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }} \
libturbojpeg
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -617,16 +675,16 @@ jobs:
- base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -651,9 +709,9 @@ jobs:
&& github.event_name == 'pull_request'
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Dependency review
uses: actions/dependency-review-action@v4.7.3
uses: actions/dependency-review-action@595b5aeba73380359d98a5e087f648dbb0edce1b # v4.7.3
with:
license-check: false # We use our own license audit checks
@@ -674,16 +732,16 @@ jobs:
python-version: ${{ fromJson(needs.info.outputs.python_versions) }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -695,7 +753,7 @@ jobs:
. venv/bin/activate
python -m script.licenses extract --output-file=licenses-${{ matrix.python-version }}.json
- name: Upload licenses
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: licenses-${{ github.run_number }}-${{ matrix.python-version }}
path: licenses-${{ matrix.python-version }}.json
@@ -717,16 +775,16 @@ jobs:
- base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -764,16 +822,16 @@ jobs:
- base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -809,10 +867,10 @@ jobs:
- base
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
@@ -825,7 +883,7 @@ jobs:
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -833,7 +891,7 @@ jobs:
${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-${{
needs.info.outputs.python_cache_key }}
- name: Restore mypy cache
uses: actions/cache@v4.2.4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: .mypy_cache
key: >-
@@ -876,26 +934,40 @@ jobs:
- mypy
name: Split tests for full run
steps:
- name: Restore apt cache
uses: actions/cache/restore@v4.3.0
with:
path: |
${{ env.APT_CACHE_DIR }}
${{ env.APT_LIST_CACHE_DIR }}
fail-on-cache-miss: true
key: >-
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
- name: Install additional OS dependencies
timeout-minutes: 10
run: |
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get update
sudo apt-get update \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }}
sudo apt-get -y install \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }} \
bluez \
ffmpeg \
libturbojpeg \
libgammu-dev
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -907,7 +979,7 @@ jobs:
. venv/bin/activate
python -m script.split_tests ${{ needs.info.outputs.test_group_count }} tests
- name: Upload pytest_buckets
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pytest_buckets
path: pytest_buckets.txt
@@ -936,27 +1008,41 @@ jobs:
name: >-
Run tests Python ${{ matrix.python-version }} (${{ matrix.group }})
steps:
- name: Restore apt cache
uses: actions/cache/restore@v4.3.0
with:
path: |
${{ env.APT_CACHE_DIR }}
${{ env.APT_LIST_CACHE_DIR }}
fail-on-cache-miss: true
key: >-
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
- name: Install additional OS dependencies
timeout-minutes: 10
run: |
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get update
sudo apt-get update \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }}
sudo apt-get -y install \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }} \
bluez \
ffmpeg \
libturbojpeg \
libgammu-dev \
libxml2-utils
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -970,7 +1056,7 @@ jobs:
run: |
echo "::add-matcher::.github/workflows/matchers/pytest-slow.json"
- name: Download pytest_buckets
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: pytest_buckets
- name: Compile English translations
@@ -1009,14 +1095,14 @@ jobs:
2>&1 | tee pytest-${{ matrix.python-version }}-${{ matrix.group }}.txt
- name: Upload pytest output
if: success() || failure() && steps.pytest-full.conclusion == 'failure'
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{ matrix.group }}
path: pytest-*.txt
overwrite: true
- name: Upload coverage artifact
if: needs.info.outputs.skip_coverage != 'true'
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
path: coverage.xml
@@ -1029,7 +1115,7 @@ jobs:
mv "junit.xml-tmp" "junit.xml"
- name: Upload test results artifact
if: needs.info.outputs.skip_coverage != 'true' && !cancelled()
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: test-results-full-${{ matrix.python-version }}-${{ matrix.group }}
path: junit.xml
@@ -1069,27 +1155,41 @@ jobs:
name: >-
Run ${{ matrix.mariadb-group }} tests Python ${{ matrix.python-version }}
steps:
- name: Restore apt cache
uses: actions/cache/restore@v4.3.0
with:
path: |
${{ env.APT_CACHE_DIR }}
${{ env.APT_LIST_CACHE_DIR }}
fail-on-cache-miss: true
key: >-
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
- name: Install additional OS dependencies
timeout-minutes: 10
run: |
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get update
sudo apt-get update \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }}
sudo apt-get -y install \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }} \
bluez \
ffmpeg \
libturbojpeg \
libmariadb-dev-compat \
libxml2-utils
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -1148,7 +1248,7 @@ jobs:
2>&1 | tee pytest-${{ matrix.python-version }}-${mariadb}.txt
- name: Upload pytest output
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{
steps.pytest-partial.outputs.mariadb }}
@@ -1156,7 +1256,7 @@ jobs:
overwrite: true
- name: Upload coverage artifact
if: needs.info.outputs.skip_coverage != 'true'
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: coverage-${{ matrix.python-version }}-${{
steps.pytest-partial.outputs.mariadb }}
@@ -1170,7 +1270,7 @@ jobs:
mv "junit.xml-tmp" "junit.xml"
- name: Upload test results artifact
if: needs.info.outputs.skip_coverage != 'true' && !cancelled()
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: test-results-mariadb-${{ matrix.python-version }}-${{
steps.pytest-partial.outputs.mariadb }}
@@ -1209,11 +1309,25 @@ jobs:
name: >-
Run ${{ matrix.postgresql-group }} tests Python ${{ matrix.python-version }}
steps:
- name: Restore apt cache
uses: actions/cache/restore@v4.3.0
with:
path: |
${{ env.APT_CACHE_DIR }}
${{ env.APT_LIST_CACHE_DIR }}
fail-on-cache-miss: true
key: >-
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
- name: Install additional OS dependencies
timeout-minutes: 10
run: |
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get update
sudo apt-get update \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }}
sudo apt-get -y install \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }} \
bluez \
ffmpeg \
libturbojpeg \
@@ -1222,16 +1336,16 @@ jobs:
sudo apt-get -y install \
postgresql-server-dev-14
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -1291,7 +1405,7 @@ jobs:
2>&1 | tee pytest-${{ matrix.python-version }}-${postgresql}.txt
- name: Upload pytest output
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{
steps.pytest-partial.outputs.postgresql }}
@@ -1299,7 +1413,7 @@ jobs:
overwrite: true
- name: Upload coverage artifact
if: needs.info.outputs.skip_coverage != 'true'
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: coverage-${{ matrix.python-version }}-${{
steps.pytest-partial.outputs.postgresql }}
@@ -1313,7 +1427,7 @@ jobs:
mv "junit.xml-tmp" "junit.xml"
- name: Upload test results artifact
if: needs.info.outputs.skip_coverage != 'true' && !cancelled()
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: test-results-postgres-${{ matrix.python-version }}-${{
steps.pytest-partial.outputs.postgresql }}
@@ -1334,14 +1448,14 @@ jobs:
timeout-minutes: 10
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Download all coverage artifacts
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
pattern: coverage-*
- name: Upload coverage to Codecov
if: needs.info.outputs.test_full_suite == 'true'
uses: codecov/codecov-action@v5.5.0
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
with:
fail_ci_if_error: true
flags: full-suite
@@ -1370,27 +1484,41 @@ jobs:
name: >-
Run tests Python ${{ matrix.python-version }} (${{ matrix.group }})
steps:
- name: Restore apt cache
uses: actions/cache/restore@v4.3.0
with:
path: |
${{ env.APT_CACHE_DIR }}
${{ env.APT_LIST_CACHE_DIR }}
fail-on-cache-miss: true
key: >-
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
- name: Install additional OS dependencies
timeout-minutes: 10
run: |
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get update
sudo apt-get update \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }}
sudo apt-get -y install \
-o Dir::Cache=${{ env.APT_CACHE_DIR }} \
-o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }} \
bluez \
ffmpeg \
libturbojpeg \
libgammu-dev \
libxml2-utils
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: venv
fail-on-cache-miss: true
@@ -1446,14 +1574,14 @@ jobs:
2>&1 | tee pytest-${{ matrix.python-version }}-${{ matrix.group }}.txt
- name: Upload pytest output
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{ matrix.group }}
path: pytest-*.txt
overwrite: true
- name: Upload coverage artifact
if: needs.info.outputs.skip_coverage != 'true'
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
path: coverage.xml
@@ -1466,7 +1594,7 @@ jobs:
mv "junit.xml-tmp" "junit.xml"
- name: Upload test results artifact
if: needs.info.outputs.skip_coverage != 'true' && !cancelled()
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: test-results-partial-${{ matrix.python-version }}-${{ matrix.group }}
path: junit.xml
@@ -1484,14 +1612,14 @@ jobs:
timeout-minutes: 10
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Download all coverage artifacts
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
pattern: coverage-*
- name: Upload coverage to Codecov
if: needs.info.outputs.test_full_suite == 'false'
uses: codecov/codecov-action@v5.5.0
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
@@ -1511,11 +1639,11 @@ jobs:
timeout-minutes: 10
steps:
- name: Download all coverage artifacts
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
pattern: test-results-*
- name: Upload test results to Codecov
uses: codecov/test-results-action@v1
uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1
with:
fail_ci_if_error: true
verbose: true
+3 -3
View File
@@ -21,14 +21,14 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Initialize CodeQL
uses: github/codeql-action/init@v3.29.11
uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
with:
languages: python
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3.29.11
uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
with:
category: "/language:python"
@@ -16,7 +16,7 @@ jobs:
steps:
- name: Check if integration label was added and extract details
id: extract
uses: actions/github-script@v7.0.1
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
// Debug: Log the event payload
@@ -113,7 +113,7 @@ jobs:
- name: Fetch similar issues
id: fetch_similar
if: steps.extract.outputs.should_continue == 'true'
uses: actions/github-script@v7.0.1
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
INTEGRATION_LABELS: ${{ steps.extract.outputs.integration_labels }}
CURRENT_NUMBER: ${{ steps.extract.outputs.current_number }}
@@ -231,7 +231,7 @@ jobs:
- name: Detect duplicates using AI
id: ai_detection
if: steps.extract.outputs.should_continue == 'true' && steps.fetch_similar.outputs.has_similar == 'true'
uses: actions/ai-inference@v2.0.1
uses: actions/ai-inference@a1c11829223a786afe3b5663db904a3aa1eac3a2 # v2.0.1
with:
model: openai/gpt-4o
system-prompt: |
@@ -280,7 +280,7 @@ jobs:
- name: Post duplicate detection results
id: post_results
if: steps.extract.outputs.should_continue == 'true' && steps.fetch_similar.outputs.has_similar == 'true'
uses: actions/github-script@v7.0.1
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
AI_RESPONSE: ${{ steps.ai_detection.outputs.response }}
SIMILAR_ISSUES: ${{ steps.fetch_similar.outputs.similar_issues }}
@@ -16,7 +16,7 @@ jobs:
steps:
- name: Check issue language
id: detect_language
uses: actions/github-script@v7.0.1
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_TITLE: ${{ github.event.issue.title }}
@@ -57,7 +57,7 @@ jobs:
- name: Detect language using AI
id: ai_language_detection
if: steps.detect_language.outputs.should_continue == 'true'
uses: actions/ai-inference@v2.0.1
uses: actions/ai-inference@a1c11829223a786afe3b5663db904a3aa1eac3a2 # v2.0.1
with:
model: openai/gpt-4o-mini
system-prompt: |
@@ -90,7 +90,7 @@ jobs:
- name: Process non-English issues
if: steps.detect_language.outputs.should_continue == 'true'
uses: actions/github-script@v7.0.1
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
AI_RESPONSE: ${{ steps.ai_language_detection.outputs.response }}
ISSUE_NUMBER: ${{ steps.detect_language.outputs.issue_number }}
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
if: github.repository_owner == 'home-assistant'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5.0.1
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
with:
github-token: ${{ github.token }}
issue-inactive-days: "30"
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
if: github.event.issue.type.name == 'Task'
steps:
- name: Check if user is authorized
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const issueAuthor = context.payload.issue.user.login;
+3 -3
View File
@@ -17,7 +17,7 @@ jobs:
# - No PRs marked as no-stale
# - No issues (-1)
- name: 60 days stale PRs policy
uses: actions/stale@v9.1.0
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 60
@@ -57,7 +57,7 @@ jobs:
# - No issues marked as no-stale or help-wanted
# - No PRs (-1)
- name: 90 days stale issues
uses: actions/stale@v9.1.0
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
with:
repo-token: ${{ steps.token.outputs.token }}
days-before-stale: 90
@@ -87,7 +87,7 @@ jobs:
# - No Issues marked as no-stale or help-wanted
# - No PRs (-1)
- name: Needs more information stale issues policy
uses: actions/stale@v9.1.0
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
with:
repo-token: ${{ steps.token.outputs.token }}
only-labels: "needs-more-information"
+2 -2
View File
@@ -19,10 +19,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
+19 -17
View File
@@ -32,11 +32,11 @@ jobs:
architectures: ${{ steps.info.outputs.architectures }}
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
@@ -91,7 +91,7 @@ jobs:
) > build_constraints.txt
- name: Upload env_file
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: env_file
path: ./.env_file
@@ -99,14 +99,14 @@ jobs:
overwrite: true
- name: Upload build_constraints
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: build_constraints
path: ./build_constraints.txt
overwrite: true
- name: Upload requirements_diff
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: requirements_diff
path: ./requirements_diff.txt
@@ -118,7 +118,7 @@ jobs:
python -m script.gen_requirements_all ci
- name: Upload requirements_all_wheels
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: requirements_all_wheels
path: ./requirements_all_wheels_*.txt
@@ -135,20 +135,20 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Download env_file
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: env_file
- name: Download build_constraints
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: build_constraints
- name: Download requirements_diff
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: requirements_diff
@@ -158,8 +158,9 @@ jobs:
sed -i "/uv/d" requirements.txt
sed -i "/uv/d" requirements_diff.txt
# home-assistant/wheels doesn't support sha pinning
- name: Build wheels
uses: home-assistant/wheels@2025.07.0
uses: home-assistant/wheels@2025.09.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
@@ -184,25 +185,25 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Download env_file
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: env_file
- name: Download build_constraints
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: build_constraints
- name: Download requirements_diff
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: requirements_diff
- name: Download requirements_all_wheels
uses: actions/download-artifact@v5.0.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: requirements_all_wheels
@@ -218,8 +219,9 @@ jobs:
sed -i "/uv/d" requirements.txt
sed -i "/uv/d" requirements_diff.txt
# home-assistant/wheels doesn't support sha pinning
- name: Build wheels
uses: home-assistant/wheels@2025.07.0
uses: home-assistant/wheels@2025.09.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
+1 -1
View File
@@ -140,5 +140,5 @@ tmp_cache
pytest_buckets.txt
# AI tooling
.claude
.claude/settings.local.json
+1 -1
View File
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.1
rev: v0.13.0
hooks:
- id: ruff-check
args:
+7
View File
@@ -142,6 +142,7 @@ homeassistant.components.cloud.*
homeassistant.components.co2signal.*
homeassistant.components.comelit.*
homeassistant.components.command_line.*
homeassistant.components.compit.*
homeassistant.components.config.*
homeassistant.components.configurator.*
homeassistant.components.cookidoo.*
@@ -169,6 +170,7 @@ homeassistant.components.dnsip.*
homeassistant.components.doorbird.*
homeassistant.components.dormakaba_dkey.*
homeassistant.components.downloader.*
homeassistant.components.droplet.*
homeassistant.components.dsmr.*
homeassistant.components.duckdns.*
homeassistant.components.dunehd.*
@@ -307,6 +309,7 @@ homeassistant.components.ld2410_ble.*
homeassistant.components.led_ble.*
homeassistant.components.lektrico.*
homeassistant.components.letpot.*
homeassistant.components.libre_hardware_monitor.*
homeassistant.components.lidarr.*
homeassistant.components.lifx.*
homeassistant.components.light.*
@@ -382,6 +385,7 @@ homeassistant.components.openai_conversation.*
homeassistant.components.openexchangerates.*
homeassistant.components.opensky.*
homeassistant.components.openuv.*
homeassistant.components.opnsense.*
homeassistant.components.opower.*
homeassistant.components.oralb.*
homeassistant.components.otbr.*
@@ -399,6 +403,7 @@ homeassistant.components.person.*
homeassistant.components.pi_hole.*
homeassistant.components.ping.*
homeassistant.components.plugwise.*
homeassistant.components.portainer.*
homeassistant.components.powerfox.*
homeassistant.components.powerwall.*
homeassistant.components.private_ble_device.*
@@ -438,6 +443,7 @@ homeassistant.components.rituals_perfume_genie.*
homeassistant.components.roborock.*
homeassistant.components.roku.*
homeassistant.components.romy.*
homeassistant.components.route_b_smart_meter.*
homeassistant.components.rpi_power.*
homeassistant.components.rss_feed_template.*
homeassistant.components.russound_rio.*
@@ -458,6 +464,7 @@ homeassistant.components.sensorpush_cloud.*
homeassistant.components.sensoterra.*
homeassistant.components.senz.*
homeassistant.components.sfr_box.*
homeassistant.components.sftp_storage.*
homeassistant.components.shell_command.*
homeassistant.components.shelly.*
homeassistant.components.shopping_list.*
Generated
+58 -41
View File
@@ -107,8 +107,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/ambient_station/ @bachya
/tests/components/ambient_station/ @bachya
/homeassistant/components/amcrest/ @flacjacket
/homeassistant/components/analytics/ @home-assistant/core @ludeeus
/tests/components/analytics/ @home-assistant/core @ludeeus
/homeassistant/components/analytics/ @home-assistant/core
/tests/components/analytics/ @home-assistant/core
/homeassistant/components/analytics_insights/ @joostlek
/tests/components/analytics_insights/ @joostlek
/homeassistant/components/android_ip_webcam/ @engrbm87
@@ -154,10 +154,10 @@ build.json @home-assistant/supervisor
/tests/components/arve/ @ikalnyi
/homeassistant/components/aseko_pool_live/ @milanmeu
/tests/components/aseko_pool_live/ @milanmeu
/homeassistant/components/assist_pipeline/ @balloob @synesthesiam
/tests/components/assist_pipeline/ @balloob @synesthesiam
/homeassistant/components/assist_satellite/ @home-assistant/core @synesthesiam
/tests/components/assist_satellite/ @home-assistant/core @synesthesiam
/homeassistant/components/assist_pipeline/ @synesthesiam @arturpragacz
/tests/components/assist_pipeline/ @synesthesiam @arturpragacz
/homeassistant/components/assist_satellite/ @home-assistant/core @synesthesiam @arturpragacz
/tests/components/assist_satellite/ @home-assistant/core @synesthesiam @arturpragacz
/homeassistant/components/asuswrt/ @kennedyshead @ollo69 @Vaskivskyi
/tests/components/asuswrt/ @kennedyshead @ollo69 @Vaskivskyi
/homeassistant/components/atag/ @MatsNL
@@ -292,14 +292,16 @@ build.json @home-assistant/supervisor
/tests/components/command_line/ @gjohansson-ST
/homeassistant/components/compensation/ @Petro31
/tests/components/compensation/ @Petro31
/homeassistant/components/compit/ @Przemko92
/tests/components/compit/ @Przemko92
/homeassistant/components/config/ @home-assistant/core
/tests/components/config/ @home-assistant/core
/homeassistant/components/configurator/ @home-assistant/core
/tests/components/configurator/ @home-assistant/core
/homeassistant/components/control4/ @lawtancool
/tests/components/control4/ @lawtancool
/homeassistant/components/conversation/ @home-assistant/core @synesthesiam
/tests/components/conversation/ @home-assistant/core @synesthesiam
/homeassistant/components/conversation/ @home-assistant/core @synesthesiam @arturpragacz
/tests/components/conversation/ @home-assistant/core @synesthesiam @arturpragacz
/homeassistant/components/cookidoo/ @miaucl
/tests/components/cookidoo/ @miaucl
/homeassistant/components/coolmaster/ @OnFreund
@@ -314,6 +316,8 @@ build.json @home-assistant/supervisor
/tests/components/crownstone/ @Crownstone @RicArch97
/homeassistant/components/cups/ @fabaff
/tests/components/cups/ @fabaff
/homeassistant/components/cync/ @Kinachi249
/tests/components/cync/ @Kinachi249
/homeassistant/components/daikin/ @fredrike
/tests/components/daikin/ @fredrike
/homeassistant/components/date/ @home-assistant/core
@@ -377,6 +381,8 @@ build.json @home-assistant/supervisor
/tests/components/dremel_3d_printer/ @tkdrob
/homeassistant/components/drop_connect/ @ChandlerSystems @pfrazer
/tests/components/drop_connect/ @ChandlerSystems @pfrazer
/homeassistant/components/droplet/ @sarahseidman
/tests/components/droplet/ @sarahseidman
/homeassistant/components/dsmr/ @Robbie1221
/tests/components/dsmr/ @Robbie1221
/homeassistant/components/dsmr_reader/ @sorted-bits @glodenox @erwindouna
@@ -406,6 +412,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/egardia/ @jeroenterheerdt
/homeassistant/components/eheimdigital/ @autinerd
/tests/components/eheimdigital/ @autinerd
/homeassistant/components/ekeybionyx/ @richardpolzer
/tests/components/ekeybionyx/ @richardpolzer
/homeassistant/components/electrasmart/ @jafar-atili
/tests/components/electrasmart/ @jafar-atili
/homeassistant/components/electric_kiwi/ @mikey0000
@@ -440,8 +448,6 @@ build.json @home-assistant/supervisor
/tests/components/energyzero/ @klaasnicolaas
/homeassistant/components/enigma2/ @autinerd
/tests/components/enigma2/ @autinerd
/homeassistant/components/enocean/ @bdurrer
/tests/components/enocean/ @bdurrer
/homeassistant/components/enphase_envoy/ @bdraco @cgarwood @catsmanac
/tests/components/enphase_envoy/ @bdraco @cgarwood @catsmanac
/homeassistant/components/entur_public_transport/ @hfurubotten
@@ -464,8 +470,6 @@ build.json @home-assistant/supervisor
/tests/components/eufylife_ble/ @bdr99
/homeassistant/components/event/ @home-assistant/core
/tests/components/event/ @home-assistant/core
/homeassistant/components/evil_genius_labs/ @balloob
/tests/components/evil_genius_labs/ @balloob
/homeassistant/components/evohome/ @zxdavb
/tests/components/evohome/ @zxdavb
/homeassistant/components/ezviz/ @RenierM26
@@ -650,6 +654,8 @@ build.json @home-assistant/supervisor
/tests/components/homeassistant/ @home-assistant/core
/homeassistant/components/homeassistant_alerts/ @home-assistant/core
/tests/components/homeassistant_alerts/ @home-assistant/core
/homeassistant/components/homeassistant_connect_zbt2/ @home-assistant/core
/tests/components/homeassistant_connect_zbt2/ @home-assistant/core
/homeassistant/components/homeassistant_green/ @home-assistant/core
/tests/components/homeassistant_green/ @home-assistant/core
/homeassistant/components/homeassistant_hardware/ @home-assistant/core
@@ -678,8 +684,8 @@ build.json @home-assistant/supervisor
/tests/components/http/ @home-assistant/core
/homeassistant/components/huawei_lte/ @scop @fphammerle
/tests/components/huawei_lte/ @scop @fphammerle
/homeassistant/components/hue/ @balloob @marcelveldt
/tests/components/hue/ @balloob @marcelveldt
/homeassistant/components/hue/ @marcelveldt
/tests/components/hue/ @marcelveldt
/homeassistant/components/huisbaasje/ @dennisschroer
/tests/components/huisbaasje/ @dennisschroer
/homeassistant/components/humidifier/ @home-assistant/core @Shulyaka
@@ -751,8 +757,8 @@ build.json @home-assistant/supervisor
/tests/components/integration/ @dgomes
/homeassistant/components/intellifire/ @jeeftor
/tests/components/intellifire/ @jeeftor
/homeassistant/components/intent/ @home-assistant/core @synesthesiam
/tests/components/intent/ @home-assistant/core @synesthesiam
/homeassistant/components/intent/ @home-assistant/core @synesthesiam @arturpragacz
/tests/components/intent/ @home-assistant/core @synesthesiam @arturpragacz
/homeassistant/components/intesishome/ @jnimmo
/homeassistant/components/iometer/ @MaestroOnICe
/tests/components/iometer/ @MaestroOnICe
@@ -770,6 +776,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/iqvia/ @bachya
/tests/components/iqvia/ @bachya
/homeassistant/components/irish_rail_transport/ @ttroy50
/homeassistant/components/irm_kmi/ @jdejaegh
/tests/components/irm_kmi/ @jdejaegh
/homeassistant/components/iron_os/ @tr4nt0r
/tests/components/iron_os/ @tr4nt0r
/homeassistant/components/isal/ @bdraco
@@ -860,6 +868,8 @@ build.json @home-assistant/supervisor
/tests/components/lg_netcast/ @Drafteed @splinter98
/homeassistant/components/lg_thinq/ @LG-ThinQ-Integration
/tests/components/lg_thinq/ @LG-ThinQ-Integration
/homeassistant/components/libre_hardware_monitor/ @Sab44
/tests/components/libre_hardware_monitor/ @Sab44
/homeassistant/components/lidarr/ @tkdrob
/tests/components/lidarr/ @tkdrob
/homeassistant/components/lifx/ @Djelibeybi
@@ -1013,7 +1023,8 @@ build.json @home-assistant/supervisor
/tests/components/nanoleaf/ @milanmeu @joostlek
/homeassistant/components/nasweb/ @nasWebio
/tests/components/nasweb/ @nasWebio
/homeassistant/components/nederlandse_spoorwegen/ @YarmoM
/homeassistant/components/nederlandse_spoorwegen/ @YarmoM @heindrichpaul
/tests/components/nederlandse_spoorwegen/ @YarmoM @heindrichpaul
/homeassistant/components/ness_alarm/ @nickw444
/tests/components/ness_alarm/ @nickw444
/homeassistant/components/nest/ @allenporter
@@ -1108,8 +1119,6 @@ build.json @home-assistant/supervisor
/tests/components/open_meteo/ @frenck
/homeassistant/components/open_router/ @joostlek
/tests/components/open_router/ @joostlek
/homeassistant/components/openai_conversation/ @balloob
/tests/components/openai_conversation/ @balloob
/homeassistant/components/openerz/ @misialq
/tests/components/openerz/ @misialq
/homeassistant/components/openexchangerates/ @MartinHjelmare
@@ -1189,6 +1198,8 @@ build.json @home-assistant/supervisor
/tests/components/pooldose/ @lmaertin
/homeassistant/components/poolsense/ @haemishkyd
/tests/components/poolsense/ @haemishkyd
/homeassistant/components/portainer/ @erwindouna
/tests/components/portainer/ @erwindouna
/homeassistant/components/powerfox/ @klaasnicolaas
/tests/components/powerfox/ @klaasnicolaas
/homeassistant/components/powerwall/ @bdraco @jrester @daniel-simpson
@@ -1208,8 +1219,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/proximity/ @mib1185
/tests/components/proximity/ @mib1185
/homeassistant/components/proxmoxve/ @jhollowe @Corbeno
/homeassistant/components/prusalink/ @balloob
/tests/components/prusalink/ @balloob
/homeassistant/components/ps4/ @ktnrg45
/tests/components/ps4/ @ktnrg45
/homeassistant/components/pterodactyl/ @elmurato
@@ -1303,8 +1312,8 @@ build.json @home-assistant/supervisor
/tests/components/rflink/ @javicalle
/homeassistant/components/rfxtrx/ @danielhiversen @elupus @RobBie1221
/tests/components/rfxtrx/ @danielhiversen @elupus @RobBie1221
/homeassistant/components/rhasspy/ @balloob @synesthesiam
/tests/components/rhasspy/ @balloob @synesthesiam
/homeassistant/components/rhasspy/ @synesthesiam
/tests/components/rhasspy/ @synesthesiam
/homeassistant/components/ridwell/ @bachya
/tests/components/ridwell/ @bachya
/homeassistant/components/ring/ @sdb9696
@@ -1325,6 +1334,8 @@ build.json @home-assistant/supervisor
/tests/components/roomba/ @pschmitt @cyr-ius @shenxn @Orhideous
/homeassistant/components/roon/ @pavoni
/tests/components/roon/ @pavoni
/homeassistant/components/route_b_smart_meter/ @SeraphicRav
/tests/components/route_b_smart_meter/ @SeraphicRav
/homeassistant/components/rpi_power/ @shenxn @swetoast
/tests/components/rpi_power/ @shenxn @swetoast
/homeassistant/components/rss_feed_template/ @home-assistant/core
@@ -1347,6 +1358,8 @@ build.json @home-assistant/supervisor
/tests/components/samsungtv/ @chemelli74 @epenet
/homeassistant/components/sanix/ @tomaszsluszniak
/tests/components/sanix/ @tomaszsluszniak
/homeassistant/components/satel_integra/ @Tommatheussen
/tests/components/satel_integra/ @Tommatheussen
/homeassistant/components/scene/ @home-assistant/core
/tests/components/scene/ @home-assistant/core
/homeassistant/components/schedule/ @home-assistant/core
@@ -1392,12 +1405,14 @@ build.json @home-assistant/supervisor
/tests/components/seventeentrack/ @shaiu
/homeassistant/components/sfr_box/ @epenet
/tests/components/sfr_box/ @epenet
/homeassistant/components/sftp_storage/ @maretodoric
/tests/components/sftp_storage/ @maretodoric
/homeassistant/components/sharkiq/ @JeffResc @funkybunch
/tests/components/sharkiq/ @JeffResc @funkybunch
/homeassistant/components/shell_command/ @home-assistant/core
/tests/components/shell_command/ @home-assistant/core
/homeassistant/components/shelly/ @balloob @bieniu @thecode @chemelli74 @bdraco
/tests/components/shelly/ @balloob @bieniu @thecode @chemelli74 @bdraco
/homeassistant/components/shelly/ @bieniu @thecode @chemelli74 @bdraco
/tests/components/shelly/ @bieniu @thecode @chemelli74 @bdraco
/homeassistant/components/shodan/ @fabaff
/homeassistant/components/sia/ @eavanvalkenburg
/tests/components/sia/ @eavanvalkenburg
@@ -1526,8 +1541,8 @@ build.json @home-assistant/supervisor
/tests/components/switchbee/ @jafar-atili
/homeassistant/components/switchbot/ @danielhiversen @RenierM26 @murtas @Eloston @dsypniewski @zerzhang
/tests/components/switchbot/ @danielhiversen @RenierM26 @murtas @Eloston @dsypniewski @zerzhang
/homeassistant/components/switchbot_cloud/ @SeraphicRav @laurence-presland @Gigatrappeur
/tests/components/switchbot_cloud/ @SeraphicRav @laurence-presland @Gigatrappeur
/homeassistant/components/switchbot_cloud/ @SeraphicRav @laurence-presland @Gigatrappeur @XiaoLing-git
/tests/components/switchbot_cloud/ @SeraphicRav @laurence-presland @Gigatrappeur @XiaoLing-git
/homeassistant/components/switcher_kis/ @thecode @YogevBokobza
/tests/components/switcher_kis/ @thecode @YogevBokobza
/homeassistant/components/switchmate/ @danielhiversen @qiz-li
@@ -1544,8 +1559,8 @@ build.json @home-assistant/supervisor
/tests/components/systemmonitor/ @gjohansson-ST
/homeassistant/components/tado/ @erwindouna
/tests/components/tado/ @erwindouna
/homeassistant/components/tag/ @balloob @dmulcahey
/tests/components/tag/ @balloob @dmulcahey
/homeassistant/components/tag/ @home-assistant/core
/tests/components/tag/ @home-assistant/core
/homeassistant/components/tailscale/ @frenck
/tests/components/tailscale/ @frenck
/homeassistant/components/tailwind/ @frenck
@@ -1672,6 +1687,8 @@ build.json @home-assistant/supervisor
/tests/components/uptime_kuma/ @tr4nt0r
/homeassistant/components/uptimerobot/ @ludeeus @chemelli74
/tests/components/uptimerobot/ @ludeeus @chemelli74
/homeassistant/components/usage_prediction/ @home-assistant/core
/tests/components/usage_prediction/ @home-assistant/core
/homeassistant/components/usb/ @bdraco
/tests/components/usb/ @bdraco
/homeassistant/components/usgs_earthquakes_feed/ @exxamalte
@@ -1690,17 +1707,19 @@ build.json @home-assistant/supervisor
/tests/components/vegehub/ @ghowevege
/homeassistant/components/velbus/ @Cereal2nd @brefra
/tests/components/velbus/ @Cereal2nd @brefra
/homeassistant/components/velux/ @Julius2342 @DeerMaximum @pawlizio
/tests/components/velux/ @Julius2342 @DeerMaximum @pawlizio
/homeassistant/components/velux/ @Julius2342 @DeerMaximum @pawlizio @wollew
/tests/components/velux/ @Julius2342 @DeerMaximum @pawlizio @wollew
/homeassistant/components/venstar/ @garbled1 @jhollowe
/tests/components/venstar/ @garbled1 @jhollowe
/homeassistant/components/versasense/ @imstevenxyz
/homeassistant/components/version/ @ludeeus
/tests/components/version/ @ludeeus
/homeassistant/components/vesync/ @markperdue @webdjoe @thegardenmonkey @cdnninja @iprak
/tests/components/vesync/ @markperdue @webdjoe @thegardenmonkey @cdnninja @iprak
/homeassistant/components/vesync/ @markperdue @webdjoe @thegardenmonkey @cdnninja @iprak @sapuseven
/tests/components/vesync/ @markperdue @webdjoe @thegardenmonkey @cdnninja @iprak @sapuseven
/homeassistant/components/vicare/ @CFenner
/tests/components/vicare/ @CFenner
/homeassistant/components/victron_remote_monitoring/ @AndyTempel
/tests/components/victron_remote_monitoring/ @AndyTempel
/homeassistant/components/vilfo/ @ManneW
/tests/components/vilfo/ @ManneW
/homeassistant/components/vivotek/ @HarlemSquirrel
@@ -1710,16 +1729,14 @@ build.json @home-assistant/supervisor
/tests/components/vlc_telnet/ @rodripf @MartinHjelmare
/homeassistant/components/vodafone_station/ @paoloantinori @chemelli74
/tests/components/vodafone_station/ @paoloantinori @chemelli74
/homeassistant/components/voip/ @balloob @synesthesiam @jaminh
/tests/components/voip/ @balloob @synesthesiam @jaminh
/homeassistant/components/voip/ @synesthesiam @jaminh
/tests/components/voip/ @synesthesiam @jaminh
/homeassistant/components/volumio/ @OnFreund
/tests/components/volumio/ @OnFreund
/homeassistant/components/volvo/ @thomasddn
/tests/components/volvo/ @thomasddn
/homeassistant/components/volvooncall/ @molobrakos
/tests/components/volvooncall/ @molobrakos
/homeassistant/components/vulcan/ @Antoni-Czaplicki
/tests/components/vulcan/ @Antoni-Czaplicki
/homeassistant/components/volvooncall/ @molobrakos @svrooij
/tests/components/volvooncall/ @molobrakos @svrooij
/homeassistant/components/wake_on_lan/ @ntilley905
/tests/components/wake_on_lan/ @ntilley905
/homeassistant/components/wake_word/ @home-assistant/core @synesthesiam
@@ -1784,8 +1801,8 @@ build.json @home-assistant/supervisor
/tests/components/worldclock/ @fabaff
/homeassistant/components/ws66i/ @ssaenger
/tests/components/ws66i/ @ssaenger
/homeassistant/components/wyoming/ @balloob @synesthesiam
/tests/components/wyoming/ @balloob @synesthesiam
/homeassistant/components/wyoming/ @synesthesiam
/tests/components/wyoming/ @synesthesiam
/homeassistant/components/xbox/ @hunterjm
/tests/components/xbox/ @hunterjm
/homeassistant/components/xiaomi_aqara/ @danielhiversen @syssi
+1 -2
View File
@@ -3,8 +3,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/base:debian
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& apt-get update \
apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
# Additional library needed by some tests and accordingly by VScode Tests Discovery
bluez \
+5 -5
View File
@@ -1,10 +1,10 @@
image: ghcr.io/home-assistant/{arch}-homeassistant
build_from:
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2025.05.0
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2025.05.0
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2025.05.0
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2025.05.0
i386: ghcr.io/home-assistant/i386-homeassistant-base:2025.05.0
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2025.09.1
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2025.09.1
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2025.09.1
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2025.09.1
i386: ghcr.io/home-assistant/i386-homeassistant-base:2025.09.1
codenotary:
signer: notary@home-assistant.io
base_image: notary@home-assistant.io
+31 -25
View File
@@ -187,36 +187,42 @@ def main() -> int:
from . import config, runner # noqa: PLC0415
safe_mode = config.safe_mode_enabled(config_dir)
# Ensure only one instance runs per config directory
with runner.ensure_single_execution(config_dir) as single_execution_lock:
# Check if another instance is already running
if single_execution_lock.exit_code is not None:
return single_execution_lock.exit_code
runtime_conf = runner.RuntimeConfig(
config_dir=config_dir,
verbose=args.verbose,
log_rotate_days=args.log_rotate_days,
log_file=args.log_file,
log_no_color=args.log_no_color,
skip_pip=args.skip_pip,
skip_pip_packages=args.skip_pip_packages,
recovery_mode=args.recovery_mode,
debug=args.debug,
open_ui=args.open_ui,
safe_mode=safe_mode,
)
safe_mode = config.safe_mode_enabled(config_dir)
fault_file_name = os.path.join(config_dir, FAULT_LOG_FILENAME)
with open(fault_file_name, mode="a", encoding="utf8") as fault_file:
faulthandler.enable(fault_file)
exit_code = runner.run(runtime_conf)
faulthandler.disable()
runtime_conf = runner.RuntimeConfig(
config_dir=config_dir,
verbose=args.verbose,
log_rotate_days=args.log_rotate_days,
log_file=args.log_file,
log_no_color=args.log_no_color,
skip_pip=args.skip_pip,
skip_pip_packages=args.skip_pip_packages,
recovery_mode=args.recovery_mode,
debug=args.debug,
open_ui=args.open_ui,
safe_mode=safe_mode,
)
# It's possible for the fault file to disappear, so suppress obvious errors
with suppress(FileNotFoundError):
if os.path.getsize(fault_file_name) == 0:
os.remove(fault_file_name)
fault_file_name = os.path.join(config_dir, FAULT_LOG_FILENAME)
with open(fault_file_name, mode="a", encoding="utf8") as fault_file:
faulthandler.enable(fault_file)
exit_code = runner.run(runtime_conf)
faulthandler.disable()
check_threads()
# It's possible for the fault file to disappear, so suppress obvious errors
with suppress(FileNotFoundError):
if os.path.getsize(fault_file_name) == 0:
os.remove(fault_file_name)
return exit_code
check_threads()
return exit_code
if __name__ == "__main__":
+1 -1
View File
@@ -27,7 +27,7 @@ from . import (
SetupFlow,
)
REQUIREMENTS = ["pyotp==2.8.0"]
REQUIREMENTS = ["pyotp==2.9.0"]
CONF_MESSAGE = "message"
+1 -1
View File
@@ -20,7 +20,7 @@ from . import (
SetupFlow,
)
REQUIREMENTS = ["pyotp==2.8.0", "PyQRCode==1.2.1"]
REQUIREMENTS = ["pyotp==2.9.0", "PyQRCode==1.2.1"]
CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({}, extra=vol.PREVENT_EXTRA)
-1
View File
@@ -6,7 +6,6 @@
"google_assistant_sdk",
"google_cloud",
"google_drive",
"google_gemini",
"google_generative_ai_conversation",
"google_mail",
"google_maps",
@@ -8,6 +8,7 @@ import logging
from aioacaia.acaiascale import AcaiaScale
from aioacaia.exceptions import AcaiaDeviceNotFound, AcaiaError
from homeassistant.components.bluetooth import async_get_scanner
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ADDRESS
from homeassistant.core import HomeAssistant
@@ -42,6 +43,7 @@ class AcaiaCoordinator(DataUpdateCoordinator[None]):
name=entry.title,
is_new_style_scale=entry.data[CONF_IS_NEW_STYLE_SCALE],
notify_callback=self.async_update_listeners,
scanner=async_get_scanner(hass),
)
@property
+1 -1
View File
@@ -26,5 +26,5 @@
"iot_class": "local_push",
"loggers": ["aioacaia"],
"quality_scale": "platinum",
"requirements": ["aioacaia==0.1.14"]
"requirements": ["aioacaia==0.1.17"]
}
@@ -2,21 +2,23 @@
from __future__ import annotations
import asyncio
import logging
from accuweather import AccuWeather
from homeassistant.components.sensor import DOMAIN as SENSOR_PLATFORM
from homeassistant.const import CONF_API_KEY, CONF_NAME, Platform
from homeassistant.const import CONF_API_KEY, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN, UPDATE_INTERVAL_DAILY_FORECAST, UPDATE_INTERVAL_OBSERVATION
from .const import DOMAIN
from .coordinator import (
AccuWeatherConfigEntry,
AccuWeatherDailyForecastDataUpdateCoordinator,
AccuWeatherData,
AccuWeatherHourlyForecastDataUpdateCoordinator,
AccuWeatherObservationDataUpdateCoordinator,
)
@@ -28,7 +30,6 @@ PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
async def async_setup_entry(hass: HomeAssistant, entry: AccuWeatherConfigEntry) -> bool:
"""Set up AccuWeather as config entry."""
api_key: str = entry.data[CONF_API_KEY]
name: str = entry.data[CONF_NAME]
location_key = entry.unique_id
@@ -41,26 +42,28 @@ async def async_setup_entry(hass: HomeAssistant, entry: AccuWeatherConfigEntry)
hass,
entry,
accuweather,
name,
"observation",
UPDATE_INTERVAL_OBSERVATION,
)
coordinator_daily_forecast = AccuWeatherDailyForecastDataUpdateCoordinator(
hass,
entry,
accuweather,
name,
"daily forecast",
UPDATE_INTERVAL_DAILY_FORECAST,
)
coordinator_hourly_forecast = AccuWeatherHourlyForecastDataUpdateCoordinator(
hass,
entry,
accuweather,
)
await coordinator_observation.async_config_entry_first_refresh()
await coordinator_daily_forecast.async_config_entry_first_refresh()
await asyncio.gather(
coordinator_observation.async_config_entry_first_refresh(),
coordinator_daily_forecast.async_config_entry_first_refresh(),
coordinator_hourly_forecast.async_config_entry_first_refresh(),
)
entry.runtime_data = AccuWeatherData(
coordinator_observation=coordinator_observation,
coordinator_daily_forecast=coordinator_daily_forecast,
coordinator_hourly_forecast=coordinator_hourly_forecast,
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
@@ -3,6 +3,7 @@
from __future__ import annotations
from asyncio import timeout
from collections.abc import Mapping
from typing import Any
from accuweather import AccuWeather, ApiError, InvalidApiKeyError, RequestsExceededError
@@ -22,6 +23,8 @@ class AccuWeatherFlowHandler(ConfigFlow, domain=DOMAIN):
"""Config flow for AccuWeather."""
VERSION = 1
_latitude: float | None = None
_longitude: float | None = None
async def async_step_user(
self, user_input: dict[str, Any] | None = None
@@ -50,6 +53,7 @@ class AccuWeatherFlowHandler(ConfigFlow, domain=DOMAIN):
await self.async_set_unique_id(
accuweather.location_key, raise_on_progress=False
)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=user_input[CONF_NAME], data=user_input
@@ -73,3 +77,46 @@ class AccuWeatherFlowHandler(ConfigFlow, domain=DOMAIN):
),
errors=errors,
)
async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle configuration by re-auth."""
self._latitude = entry_data[CONF_LATITUDE]
self._longitude = entry_data[CONF_LONGITUDE]
return await self.async_step_reauth_confirm()
async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Dialog that informs the user that reauth is required."""
errors: dict[str, str] = {}
if user_input is not None:
websession = async_get_clientsession(self.hass)
try:
async with timeout(10):
accuweather = AccuWeather(
user_input[CONF_API_KEY],
websession,
latitude=self._latitude,
longitude=self._longitude,
)
await accuweather.async_get_location()
except (ApiError, ClientConnectorError, TimeoutError, ClientError):
errors["base"] = "cannot_connect"
except InvalidApiKeyError:
errors["base"] = "invalid_api_key"
except RequestsExceededError:
errors["base"] = "requests_exceeded"
else:
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)
return self.async_show_form(
step_id="reauth_confirm",
data_schema=vol.Schema({vol.Required(CONF_API_KEY): str}),
errors=errors,
)
@@ -69,5 +69,6 @@ POLLEN_CATEGORY_MAP = {
4: "very_high",
5: "extreme",
}
UPDATE_INTERVAL_OBSERVATION = timedelta(minutes=40)
UPDATE_INTERVAL_OBSERVATION = timedelta(minutes=10)
UPDATE_INTERVAL_DAILY_FORECAST = timedelta(hours=6)
UPDATE_INTERVAL_HOURLY_FORECAST = timedelta(hours=30)
@@ -3,6 +3,7 @@
from __future__ import annotations
from asyncio import timeout
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from datetime import timedelta
import logging
@@ -12,7 +13,9 @@ from accuweather import AccuWeather, ApiError, InvalidApiKeyError, RequestsExcee
from aiohttp.client_exceptions import ClientConnectorError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.update_coordinator import (
DataUpdateCoordinator,
@@ -20,9 +23,15 @@ from homeassistant.helpers.update_coordinator import (
UpdateFailed,
)
from .const import DOMAIN, MANUFACTURER
from .const import (
DOMAIN,
MANUFACTURER,
UPDATE_INTERVAL_DAILY_FORECAST,
UPDATE_INTERVAL_HOURLY_FORECAST,
UPDATE_INTERVAL_OBSERVATION,
)
EXCEPTIONS = (ApiError, ClientConnectorError, InvalidApiKeyError, RequestsExceededError)
EXCEPTIONS = (ApiError, ClientConnectorError, RequestsExceededError)
_LOGGER = logging.getLogger(__name__)
@@ -33,6 +42,7 @@ class AccuWeatherData:
coordinator_observation: AccuWeatherObservationDataUpdateCoordinator
coordinator_daily_forecast: AccuWeatherDailyForecastDataUpdateCoordinator
coordinator_hourly_forecast: AccuWeatherHourlyForecastDataUpdateCoordinator
type AccuWeatherConfigEntry = ConfigEntry[AccuWeatherData]
@@ -43,18 +53,18 @@ class AccuWeatherObservationDataUpdateCoordinator(
):
"""Class to manage fetching AccuWeather data API."""
config_entry: AccuWeatherConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: AccuWeatherConfigEntry,
accuweather: AccuWeather,
name: str,
coordinator_type: str,
update_interval: timedelta,
) -> None:
"""Initialize."""
self.accuweather = accuweather
self.location_key = accuweather.location_key
name = config_entry.data[CONF_NAME]
if TYPE_CHECKING:
assert self.location_key is not None
@@ -65,8 +75,8 @@ class AccuWeatherObservationDataUpdateCoordinator(
hass,
_LOGGER,
config_entry=config_entry,
name=f"{name} ({coordinator_type})",
update_interval=update_interval,
name=f"{name} (observation)",
update_interval=UPDATE_INTERVAL_OBSERVATION,
)
async def _async_update_data(self) -> dict[str, Any]:
@@ -80,29 +90,39 @@ class AccuWeatherObservationDataUpdateCoordinator(
translation_key="current_conditions_update_error",
translation_placeholders={"error": repr(error)},
) from error
except InvalidApiKeyError as err:
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
translation_key="auth_error",
translation_placeholders={"entry": self.config_entry.title},
) from err
_LOGGER.debug("Requests remaining: %d", self.accuweather.requests_remaining)
return result
class AccuWeatherDailyForecastDataUpdateCoordinator(
class AccuWeatherForecastDataUpdateCoordinator(
TimestampDataUpdateCoordinator[list[dict[str, Any]]]
):
"""Class to manage fetching AccuWeather data API."""
"""Base class for AccuWeather forecast."""
config_entry: AccuWeatherConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: AccuWeatherConfigEntry,
accuweather: AccuWeather,
name: str,
coordinator_type: str,
update_interval: timedelta,
fetch_method: Callable[..., Awaitable[list[dict[str, Any]]]],
) -> None:
"""Initialize."""
self.accuweather = accuweather
self.location_key = accuweather.location_key
self._fetch_method = fetch_method
name = config_entry.data[CONF_NAME]
if TYPE_CHECKING:
assert self.location_key is not None
@@ -118,24 +138,71 @@ class AccuWeatherDailyForecastDataUpdateCoordinator(
)
async def _async_update_data(self) -> list[dict[str, Any]]:
"""Update data via library."""
"""Update forecast data via library."""
try:
async with timeout(10):
result = await self.accuweather.async_get_daily_forecast(
language=self.hass.config.language
)
result = await self._fetch_method(language=self.hass.config.language)
except EXCEPTIONS as error:
raise UpdateFailed(
translation_domain=DOMAIN,
translation_key="forecast_update_error",
translation_placeholders={"error": repr(error)},
) from error
except InvalidApiKeyError as err:
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
translation_key="auth_error",
translation_placeholders={"entry": self.config_entry.title},
) from err
_LOGGER.debug("Requests remaining: %d", self.accuweather.requests_remaining)
return result
class AccuWeatherDailyForecastDataUpdateCoordinator(
AccuWeatherForecastDataUpdateCoordinator
):
"""Coordinator for daily forecast."""
def __init__(
self,
hass: HomeAssistant,
config_entry: AccuWeatherConfigEntry,
accuweather: AccuWeather,
) -> None:
"""Initialize."""
super().__init__(
hass,
config_entry,
accuweather,
"daily forecast",
UPDATE_INTERVAL_DAILY_FORECAST,
fetch_method=accuweather.async_get_daily_forecast,
)
class AccuWeatherHourlyForecastDataUpdateCoordinator(
AccuWeatherForecastDataUpdateCoordinator
):
"""Coordinator for hourly forecast."""
def __init__(
self,
hass: HomeAssistant,
config_entry: AccuWeatherConfigEntry,
accuweather: AccuWeather,
) -> None:
"""Initialize."""
super().__init__(
hass,
config_entry,
accuweather,
"hourly forecast",
UPDATE_INTERVAL_HOURLY_FORECAST,
fetch_method=accuweather.async_get_hourly_forecast,
)
def _get_device_info(location_key: str, name: str) -> DeviceInfo:
"""Get device info."""
return DeviceInfo(
@@ -7,6 +7,5 @@
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["accuweather"],
"requirements": ["accuweather==4.2.0"],
"single_config_entry": true
"requirements": ["accuweather==4.2.1"]
}
@@ -7,6 +7,17 @@
"api_key": "[%key:common::config_flow::data::api_key%]",
"latitude": "[%key:common::config_flow::data::latitude%]",
"longitude": "[%key:common::config_flow::data::longitude%]"
},
"data_description": {
"api_key": "API key generated in the AccuWeather APIs portal."
}
},
"reauth_confirm": {
"data": {
"api_key": "[%key:common::config_flow::data::api_key%]"
},
"data_description": {
"api_key": "[%key:component::accuweather::config::step::user::data_description::api_key%]"
}
}
},
@@ -17,6 +28,10 @@
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_api_key": "[%key:common::config_flow::error::invalid_api_key%]",
"requests_exceeded": "The allowed number of requests to the AccuWeather API has been exceeded. You have to wait or change the API key."
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_location%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
}
},
"entity": {
@@ -236,6 +251,9 @@
}
},
"exceptions": {
"auth_error": {
"message": "Authentication failed for {entry}, please update your API key"
},
"current_conditions_update_error": {
"message": "An error occurred while retrieving weather current conditions data from the AccuWeather API: {error}"
},
@@ -45,6 +45,7 @@ from .coordinator import (
AccuWeatherConfigEntry,
AccuWeatherDailyForecastDataUpdateCoordinator,
AccuWeatherData,
AccuWeatherHourlyForecastDataUpdateCoordinator,
AccuWeatherObservationDataUpdateCoordinator,
)
@@ -64,6 +65,7 @@ class AccuWeatherEntity(
CoordinatorWeatherEntity[
AccuWeatherObservationDataUpdateCoordinator,
AccuWeatherDailyForecastDataUpdateCoordinator,
AccuWeatherHourlyForecastDataUpdateCoordinator,
]
):
"""Define an AccuWeather entity."""
@@ -76,6 +78,7 @@ class AccuWeatherEntity(
super().__init__(
observation_coordinator=accuweather_data.coordinator_observation,
daily_coordinator=accuweather_data.coordinator_daily_forecast,
hourly_coordinator=accuweather_data.coordinator_hourly_forecast,
)
self._attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS
@@ -86,10 +89,13 @@ class AccuWeatherEntity(
self._attr_unique_id = accuweather_data.coordinator_observation.location_key
self._attr_attribution = ATTRIBUTION
self._attr_device_info = accuweather_data.coordinator_observation.device_info
self._attr_supported_features = WeatherEntityFeature.FORECAST_DAILY
self._attr_supported_features = (
WeatherEntityFeature.FORECAST_DAILY | WeatherEntityFeature.FORECAST_HOURLY
)
self.observation_coordinator = accuweather_data.coordinator_observation
self.daily_coordinator = accuweather_data.coordinator_daily_forecast
self.hourly_coordinator = accuweather_data.coordinator_hourly_forecast
@property
def condition(self) -> str | None:
@@ -207,3 +213,32 @@ class AccuWeatherEntity(
}
for item in self.daily_coordinator.data
]
@callback
def _async_forecast_hourly(self) -> list[Forecast] | None:
"""Return the hourly forecast in native units."""
return [
{
ATTR_FORECAST_TIME: utc_from_timestamp(
item["EpochDateTime"]
).isoformat(),
ATTR_FORECAST_CLOUD_COVERAGE: item["CloudCover"],
ATTR_FORECAST_HUMIDITY: item["RelativeHumidity"],
ATTR_FORECAST_NATIVE_TEMP: item["Temperature"][ATTR_VALUE],
ATTR_FORECAST_NATIVE_APPARENT_TEMP: item["RealFeelTemperature"][
ATTR_VALUE
],
ATTR_FORECAST_NATIVE_PRECIPITATION: item["TotalLiquid"][ATTR_VALUE],
ATTR_FORECAST_PRECIPITATION_PROBABILITY: item[
"PrecipitationProbability"
],
ATTR_FORECAST_NATIVE_WIND_SPEED: item["Wind"][ATTR_SPEED][ATTR_VALUE],
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED: item["WindGust"][ATTR_SPEED][
ATTR_VALUE
],
ATTR_FORECAST_UV_INDEX: item["UVIndex"],
ATTR_FORECAST_WIND_BEARING: item["Wind"][ATTR_DIRECTION]["Degrees"],
ATTR_FORECAST_CONDITION: CONDITION_MAP.get(item["WeatherIcon"]),
}
for item in self.hourly_coordinator.data
]
+9 -37
View File
@@ -3,10 +3,8 @@
import logging
from typing import Any
from aiohttp import web
import voluptuous as vol
from homeassistant.components.http import KEY_HASS, HomeAssistantView
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ENTITY_ID, CONF_DESCRIPTION, CONF_SELECTOR
from homeassistant.core import (
@@ -28,7 +26,6 @@ from .const import (
ATTR_STRUCTURE,
ATTR_TASK_NAME,
DATA_COMPONENT,
DATA_IMAGES,
DATA_PREFERENCES,
DOMAIN,
SERVICE_GENERATE_DATA,
@@ -42,7 +39,6 @@ from .task import (
GenDataTaskResult,
GenImageTask,
GenImageTaskResult,
ImageData,
async_generate_data,
async_generate_image,
)
@@ -55,7 +51,6 @@ __all__ = [
"GenDataTaskResult",
"GenImageTask",
"GenImageTaskResult",
"ImageData",
"async_generate_data",
"async_generate_image",
"async_setup",
@@ -94,10 +89,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
entity_component = EntityComponent[AITaskEntity](_LOGGER, DOMAIN, hass)
hass.data[DATA_COMPONENT] = entity_component
hass.data[DATA_PREFERENCES] = AITaskPreferences(hass)
hass.data[DATA_IMAGES] = {}
await hass.data[DATA_PREFERENCES].async_load()
async_setup_http(hass)
hass.http.register_view(ImageView)
hass.services.async_register(
DOMAIN,
SERVICE_GENERATE_DATA,
@@ -126,7 +119,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
schema=vol.Schema(
{
vol.Required(ATTR_TASK_NAME): cv.string,
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
vol.Optional(ATTR_ENTITY_ID): cv.entity_id,
vol.Required(ATTR_INSTRUCTIONS): cv.string,
vol.Optional(ATTR_ATTACHMENTS): vol.All(
cv.ensure_list, [selector.MediaSelector({"accept": ["*/*"]})]
@@ -163,9 +156,10 @@ async def async_service_generate_image(call: ServiceCall) -> ServiceResponse:
class AITaskPreferences:
"""AI Task preferences."""
KEYS = ("gen_data_entity_id",)
KEYS = ("gen_data_entity_id", "gen_image_entity_id")
gen_data_entity_id: str | None = None
gen_image_entity_id: str | None = None
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize the preferences."""
@@ -179,17 +173,21 @@ class AITaskPreferences:
if data is None:
return
for key in self.KEYS:
setattr(self, key, data[key])
setattr(self, key, data.get(key))
@callback
def async_set_preferences(
self,
*,
gen_data_entity_id: str | None | UndefinedType = UNDEFINED,
gen_image_entity_id: str | None | UndefinedType = UNDEFINED,
) -> None:
"""Set the preferences."""
changed = False
for key, value in (("gen_data_entity_id", gen_data_entity_id),):
for key, value in (
("gen_data_entity_id", gen_data_entity_id),
("gen_image_entity_id", gen_image_entity_id),
):
if value is not UNDEFINED:
if getattr(self, key) != value:
setattr(self, key, value)
@@ -204,29 +202,3 @@ class AITaskPreferences:
def as_dict(self) -> dict[str, str | None]:
"""Get the current preferences."""
return {key: getattr(self, key) for key in self.KEYS}
class ImageView(HomeAssistantView):
"""View to generated images."""
url = f"/api/{DOMAIN}/images/{{filename}}"
name = f"api:{DOMAIN}/images"
requires_auth = False
async def get(
self,
request: web.Request,
filename: str,
) -> web.Response:
"""Serve image."""
hass = request.app[KEY_HASS]
image_storage = hass.data[DATA_IMAGES]
image_data = image_storage.get(filename)
if image_data is None:
raise web.HTTPNotFound
return web.Response(
body=image_data.data,
content_type=image_data.mime_type,
)
+3 -3
View File
@@ -8,19 +8,19 @@ from typing import TYPE_CHECKING, Final
from homeassistant.util.hass_dict import HassKey
if TYPE_CHECKING:
from homeassistant.components.media_source import local_source
from homeassistant.helpers.entity_component import EntityComponent
from . import AITaskPreferences
from .entity import AITaskEntity
from .task import ImageData
DOMAIN = "ai_task"
DATA_COMPONENT: HassKey[EntityComponent[AITaskEntity]] = HassKey(DOMAIN)
DATA_PREFERENCES: HassKey[AITaskPreferences] = HassKey(f"{DOMAIN}_preferences")
DATA_IMAGES: HassKey[dict[str, ImageData]] = HassKey(f"{DOMAIN}_images")
DATA_MEDIA_SOURCE: HassKey[local_source.LocalSource] = HassKey(f"{DOMAIN}_media_source")
IMAGE_DIR: Final = "image"
IMAGE_EXPIRY_TIME = 60 * 60 # 1 hour
MAX_IMAGES = 20
SERVICE_GENERATE_DATA = "generate_data"
SERVICE_GENERATE_IMAGE = "generate_image"
@@ -60,6 +60,10 @@ class AITaskEntity(RestoreEntity):
task: GenDataTask | GenImageTask,
) -> AsyncGenerator[ChatLog]:
"""Context manager used to manage the ChatLog used during an AI Task."""
user_llm_hass_api: llm.API | None = None
if isinstance(task, GenDataTask):
user_llm_hass_api = task.llm_api
# pylint: disable-next=contextmanager-generator-missing-cleanup
with (
async_get_chat_log(
@@ -77,6 +81,7 @@ class AITaskEntity(RestoreEntity):
device_id=None,
),
user_llm_prompt=DEFAULT_SYSTEM_PROMPT,
user_llm_hass_api=user_llm_hass_api,
)
chat_log.async_add_user_content(
+1
View File
@@ -37,6 +37,7 @@ def websocket_get_preferences(
{
vol.Required("type"): "ai_task/preferences/set",
vol.Optional("gen_data_entity_id"): vol.Any(str, None),
vol.Optional("gen_image_entity_id"): vol.Any(str, None),
}
)
@websocket_api.require_admin
@@ -1,7 +1,7 @@
{
"domain": "ai_task",
"name": "AI Task",
"after_dependencies": ["camera", "http"],
"after_dependencies": ["camera"],
"codeowners": ["@home-assistant/core"],
"dependencies": ["conversation", "media_source"],
"documentation": "https://www.home-assistant.io/integrations/ai_task",
@@ -2,80 +2,31 @@
from __future__ import annotations
import logging
from pathlib import Path
from homeassistant.components.media_player import BrowseError, MediaClass
from homeassistant.components.media_source import (
BrowseMediaSource,
MediaSource,
MediaSourceItem,
PlayMedia,
Unresolvable,
)
from homeassistant.components.media_source import MediaSource, local_source
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from .const import DATA_IMAGES, DOMAIN
_LOGGER = logging.getLogger(__name__)
from .const import DATA_MEDIA_SOURCE, DOMAIN, IMAGE_DIR
async def async_get_media_source(hass: HomeAssistant) -> ImageMediaSource:
"""Set up image media source."""
_LOGGER.debug("Setting up image media source")
return ImageMediaSource(hass)
async def async_get_media_source(hass: HomeAssistant) -> MediaSource:
"""Set up local media source."""
media_dirs = list(hass.config.media_dirs.values())
class ImageMediaSource(MediaSource):
"""Provide images as media sources."""
name: str = "AI Generated Images"
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize ImageMediaSource."""
super().__init__(DOMAIN)
self.hass = hass
async def async_resolve_media(self, item: MediaSourceItem) -> PlayMedia:
"""Resolve media to a url."""
image_storage = self.hass.data[DATA_IMAGES]
image = image_storage.get(item.identifier)
if image is None:
raise Unresolvable(f"Could not resolve media item: {item.identifier}")
return PlayMedia(f"/api/{DOMAIN}/images/{item.identifier}", image.mime_type)
async def async_browse_media(
self,
item: MediaSourceItem,
) -> BrowseMediaSource:
"""Return media."""
if item.identifier:
raise BrowseError("Unknown item")
image_storage = self.hass.data[DATA_IMAGES]
children = [
BrowseMediaSource(
domain=DOMAIN,
identifier=filename,
media_class=MediaClass.IMAGE,
media_content_type=image.mime_type,
title=image.title or filename,
can_play=True,
can_expand=False,
)
for filename, image in image_storage.items()
]
return BrowseMediaSource(
domain=DOMAIN,
identifier=None,
media_class=MediaClass.APP,
media_content_type="",
title="AI Generated Images",
can_play=False,
can_expand=True,
children_media_class=MediaClass.IMAGE,
children=children,
if not media_dirs:
raise HomeAssistantError(
"AI Task media source requires at least one media directory configured"
)
media_dir = Path(media_dirs[0]) / DOMAIN / IMAGE_DIR
hass.data[DATA_MEDIA_SOURCE] = source = local_source.LocalSource(
hass,
DOMAIN,
"AI Generated Images",
{IMAGE_DIR: str(media_dir)},
f"/{DOMAIN}",
)
return source
+58 -70
View File
@@ -3,8 +3,8 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from functools import partial
from datetime import datetime, timedelta
import io
import mimetypes
from pathlib import Path
import tempfile
@@ -12,33 +12,33 @@ from typing import Any
import voluptuous as vol
from homeassistant.components import camera, conversation, media_source
from homeassistant.components import camera, conversation, image, media_source
from homeassistant.components.http.auth import async_sign_path
from homeassistant.core import HomeAssistant, ServiceResponse, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import llm
from homeassistant.helpers.chat_session import ChatSession, async_get_chat_session
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.network import get_url
from homeassistant.util import RE_SANITIZE_FILENAME, slugify
from .const import (
DATA_COMPONENT,
DATA_IMAGES,
DATA_MEDIA_SOURCE,
DATA_PREFERENCES,
DOMAIN,
IMAGE_DIR,
IMAGE_EXPIRY_TIME,
MAX_IMAGES,
AITaskEntityFeature,
)
def _save_camera_snapshot(image: camera.Image) -> Path:
def _save_camera_snapshot(image_data: camera.Image | image.Image) -> Path:
"""Save camera snapshot to temp file."""
with tempfile.NamedTemporaryFile(
mode="wb",
suffix=mimetypes.guess_extension(image.content_type, False),
suffix=mimetypes.guess_extension(image_data.content_type, False),
delete=False,
) as temp_file:
temp_file.write(image.content)
temp_file.write(image_data.content)
return Path(temp_file.name)
@@ -54,26 +54,31 @@ async def _resolve_attachments(
for attachment in attachments or []:
media_content_id = attachment["media_content_id"]
# Special case for camera media sources
if media_content_id.startswith("media-source://camera/"):
# Extract entity_id from the media content ID
entity_id = media_content_id.removeprefix("media-source://camera/")
# Special case for certain media sources
for integration in camera, image:
media_source_prefix = f"media-source://{integration.DOMAIN}/"
if not media_content_id.startswith(media_source_prefix):
continue
# Get snapshot from camera
image = await camera.async_get_image(hass, entity_id)
# Extract entity_id from the media content ID
entity_id = media_content_id.removeprefix(media_source_prefix)
# Get snapshot from entity
image_data = await integration.async_get_image(hass, entity_id)
temp_filename = await hass.async_add_executor_job(
_save_camera_snapshot, image
_save_camera_snapshot, image_data
)
created_files.append(temp_filename)
resolved_attachments.append(
conversation.Attachment(
media_content_id=media_content_id,
mime_type=image.content_type,
mime_type=image_data.content_type,
path=temp_filename,
)
)
break
else:
# Handle regular media sources
media = await media_source.async_resolve_media(hass, media_content_id, None)
@@ -115,6 +120,7 @@ async def async_generate_data(
instructions: str,
structure: vol.Schema | None = None,
attachments: list[dict] | None = None,
llm_api: llm.API | None = None,
) -> GenDataTaskResult:
"""Run a data generation task in the AI Task integration."""
if entity_id is None:
@@ -150,37 +156,26 @@ async def async_generate_data(
instructions=instructions,
structure=structure,
attachments=resolved_attachments or None,
llm_api=llm_api,
),
)
def _cleanup_images(image_storage: dict[str, ImageData], num_to_remove: int) -> None:
"""Remove old images to keep the storage size under the limit."""
if num_to_remove <= 0:
return
if num_to_remove >= len(image_storage):
image_storage.clear()
return
sorted_images = sorted(
image_storage.items(),
key=lambda item: item[1].timestamp,
)
for filename, _ in sorted_images[:num_to_remove]:
image_storage.pop(filename, None)
async def async_generate_image(
hass: HomeAssistant,
*,
task_name: str,
entity_id: str,
entity_id: str | None = None,
instructions: str,
attachments: list[dict] | None = None,
) -> ServiceResponse:
"""Run an image generation task in the AI Task integration."""
if entity_id is None:
entity_id = hass.data[DATA_PREFERENCES].gen_image_entity_id
if entity_id is None:
raise HomeAssistantError("No entity_id provided and no preferred entity set")
entity = hass.data[DATA_COMPONENT].get_entity(entity_id)
if entity is None:
raise HomeAssistantError(f"AI Task entity {entity_id} not found")
@@ -215,32 +210,34 @@ async def async_generate_image(
if service_result.get("revised_prompt") is None:
service_result["revised_prompt"] = instructions
image_storage = hass.data[DATA_IMAGES]
if len(image_storage) + 1 > MAX_IMAGES:
_cleanup_images(image_storage, len(image_storage) + 1 - MAX_IMAGES)
source = hass.data[DATA_MEDIA_SOURCE]
current_time = datetime.now()
ext = mimetypes.guess_extension(task_result.mime_type, False) or ".png"
sanitized_task_name = RE_SANITIZE_FILENAME.sub("", slugify(task_name))
filename = f"{current_time.strftime('%Y-%m-%d_%H%M%S')}_{sanitized_task_name}{ext}"
image_storage[filename] = ImageData(
data=image_data,
timestamp=int(current_time.timestamp()),
mime_type=task_result.mime_type,
title=service_result["revised_prompt"],
image_file = ImageData(
filename=f"{current_time.strftime('%Y-%m-%d_%H%M%S')}_{sanitized_task_name}{ext}",
file=io.BytesIO(image_data),
content_type=task_result.mime_type,
)
def _purge_image(filename: str, now: datetime) -> None:
"""Remove image from storage."""
image_storage.pop(filename, None)
target_folder = media_source.MediaSourceItem.from_uri(
hass, f"media-source://{DOMAIN}/{IMAGE_DIR}", None
)
if IMAGE_EXPIRY_TIME > 0:
async_call_later(hass, IMAGE_EXPIRY_TIME, partial(_purge_image, filename))
service_result["media_source_id"] = await source.async_upload_media(
target_folder, image_file
)
service_result["url"] = get_url(hass) + f"/api/{DOMAIN}/images/{filename}"
service_result["media_source_id"] = f"media-source://{DOMAIN}/images/{filename}"
item = media_source.MediaSourceItem.from_uri(
hass, service_result["media_source_id"], None
)
service_result["url"] = async_sign_path(
hass,
(await source.async_resolve_media(item)).url,
timedelta(seconds=IMAGE_EXPIRY_TIME),
)
return service_result
@@ -261,6 +258,9 @@ class GenDataTask:
attachments: list[conversation.Attachment] | None = None
"""List of attachments to go along the instructions."""
llm_api: llm.API | None = None
"""API to provide to the LLM."""
def __str__(self) -> str:
"""Return task as a string."""
return f"<GenDataTask {self.name}: {id(self)}>"
@@ -342,20 +342,8 @@ class GenImageTaskResult:
@dataclass(slots=True)
class ImageData:
"""Image data for stored generated images."""
"""Implementation of media_source.local_source.UploadedFile protocol."""
data: bytes
"""Raw image data."""
timestamp: int
"""Timestamp when the image was generated, as a Unix timestamp."""
mime_type: str
"""MIME type of the image."""
title: str
"""Title of the image, usually the prompt used to generate it."""
def __str__(self) -> str:
"""Return image data as a string."""
return f"<ImageData {self.title}: {id(self)}>"
filename: str
file: io.IOBase
content_type: str
@@ -11,5 +11,5 @@
"documentation": "https://www.home-assistant.io/integrations/airzone",
"iot_class": "local_polling",
"loggers": ["aioairzone"],
"requirements": ["aioairzone==1.0.0"]
"requirements": ["aioairzone==1.0.1"]
}
+19 -1
View File
@@ -6,17 +6,19 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, Final
from aioairzone.common import GrilleAngle, OperationMode, SleepTimeout
from aioairzone.common import GrilleAngle, OperationMode, QAdapt, SleepTimeout
from aioairzone.const import (
API_COLD_ANGLE,
API_HEAT_ANGLE,
API_MODE,
API_Q_ADAPT,
API_SLEEP,
AZD_COLD_ANGLE,
AZD_HEAT_ANGLE,
AZD_MASTER,
AZD_MODE,
AZD_MODES,
AZD_Q_ADAPT,
AZD_SLEEP,
AZD_ZONES,
)
@@ -65,6 +67,14 @@ SLEEP_DICT: Final[dict[str, int]] = {
"90m": SleepTimeout.SLEEP_90,
}
Q_ADAPT_DICT: Final[dict[str, int]] = {
"standard": QAdapt.STANDARD,
"power": QAdapt.POWER,
"silence": QAdapt.SILENCE,
"minimum": QAdapt.MINIMUM,
"maximum": QAdapt.MAXIMUM,
}
def main_zone_options(
zone_data: dict[str, Any],
@@ -83,6 +93,14 @@ MAIN_ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = (
options_fn=main_zone_options,
translation_key="modes",
),
AirzoneSelectDescription(
api_param=API_Q_ADAPT,
entity_category=EntityCategory.CONFIG,
key=AZD_Q_ADAPT,
options=list(Q_ADAPT_DICT),
options_dict=Q_ADAPT_DICT,
translation_key="q_adapt",
),
)
@@ -63,6 +63,16 @@
"stop": "Stop"
}
},
"q_adapt": {
"name": "Q-Adapt",
"state": {
"standard": "Standard",
"power": "Power",
"silence": "Silence",
"minimum": "Minimum",
"maximum": "Maximum"
}
},
"sleep_times": {
"name": "Sleep",
"state": {
@@ -3,7 +3,6 @@
from __future__ import annotations
from genie_partner_sdk.client import AladdinConnectClient
from genie_partner_sdk.model import GarageDoor
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
@@ -36,22 +35,7 @@ async def async_setup_entry(
api.AsyncConfigEntryAuth(aiohttp_client.async_get_clientsession(hass), session)
)
sdk_doors = await client.get_doors()
# Convert SDK GarageDoor objects to integration GarageDoor objects
doors = [
GarageDoor(
{
"device_id": door.device_id,
"door_number": door.door_number,
"name": door.name,
"status": door.status,
"link_status": door.link_status,
"battery_level": door.battery_level,
}
)
for door in sdk_doors
]
doors = await client.get_doors()
entry.runtime_data = {
door.unique_id: AladdinConnectCoordinator(hass, entry, client, door)
@@ -41,4 +41,10 @@ class AladdinConnectCoordinator(DataUpdateCoordinator[GarageDoor]):
async def _async_update_data(self) -> GarageDoor:
"""Fetch data from the Aladdin Connect API."""
await self.client.update_door(self.data.device_id, self.data.door_number)
self.data.status = self.client.get_door_status(
self.data.device_id, self.data.door_number
)
self.data.battery_level = self.client.get_battery_status(
self.data.device_id, self.data.door_number
)
return self.data
@@ -49,7 +49,9 @@ class AladdinCoverEntity(AladdinConnectEntity, CoverEntity):
@property
def is_closed(self) -> bool | None:
"""Update is closed attribute."""
return self.coordinator.data.status == "closed"
if (status := self.coordinator.data.status) is None:
return None
return status == "closed"
@property
def is_closing(self) -> bool | None:
@@ -4,8 +4,13 @@
"codeowners": ["@swcloudgenie"],
"config_flow": true,
"dependencies": ["application_credentials"],
"dhcp": [
{
"hostname": "gdocntl-*"
}
],
"documentation": "https://www.home-assistant.io/integrations/aladdin_connect",
"integration_type": "hub",
"iot_class": "cloud_polling",
"requirements": ["genie-partner-sdk==1.0.10"]
"requirements": ["genie-partner-sdk==1.0.11"]
}
@@ -7,6 +7,9 @@
"reauth_confirm": {
"title": "[%key:common::config_flow::title::reauth%]",
"description": "Aladdin Connect needs to re-authenticate your account"
},
"oauth_discovery": {
"description": "Home Assistant has found an Aladdin Connect device on your network. Press **Submit** to continue setting up Aladdin Connect."
}
},
"abort": {
@@ -61,7 +61,7 @@ ALARM_SERVICE_SCHEMA: Final = make_entity_service_schema(
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Track states and offer events for sensors."""
"""Set up the alarm control panel component."""
component = hass.data[DATA_COMPONENT] = EntityComponent[AlarmControlPanelEntity](
_LOGGER, DOMAIN, hass, SCAN_INTERVAL
)
@@ -5,7 +5,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import aiohttp_client, config_validation as cv
from homeassistant.helpers.typing import ConfigType
from .const import _LOGGER, CONF_LOGIN_DATA, COUNTRY_DOMAINS, DOMAIN
from .const import _LOGGER, CONF_LOGIN_DATA, CONF_SITE, COUNTRY_DOMAINS, DOMAIN
from .coordinator import AmazonConfigEntry, AmazonDevicesCoordinator
from .services import async_setup_services
@@ -42,7 +42,23 @@ async def async_setup_entry(hass: HomeAssistant, entry: AmazonConfigEntry) -> bo
async def async_migrate_entry(hass: HomeAssistant, entry: AmazonConfigEntry) -> bool:
"""Migrate old entry."""
if entry.version == 1 and entry.minor_version == 1:
if entry.version == 1 and entry.minor_version < 3:
if CONF_SITE in entry.data:
# Site in data (wrong place), just move to login data
new_data = entry.data.copy()
new_data[CONF_LOGIN_DATA][CONF_SITE] = new_data[CONF_SITE]
new_data.pop(CONF_SITE)
hass.config_entries.async_update_entry(
entry, data=new_data, version=1, minor_version=3
)
return True
if CONF_SITE in entry.data[CONF_LOGIN_DATA]:
# Site is there, just update version to avoid future migrations
hass.config_entries.async_update_entry(entry, version=1, minor_version=3)
return True
_LOGGER.debug(
"Migrating from version %s.%s", entry.version, entry.minor_version
)
@@ -53,10 +69,10 @@ async def async_migrate_entry(hass: HomeAssistant, entry: AmazonConfigEntry) ->
# Add site to login data
new_data = entry.data.copy()
new_data[CONF_LOGIN_DATA]["site"] = f"https://www.amazon.{domain}"
new_data[CONF_LOGIN_DATA][CONF_SITE] = f"https://www.amazon.{domain}"
hass.config_entries.async_update_entry(
entry, data=new_data, version=1, minor_version=2
entry, data=new_data, version=1, minor_version=3
)
_LOGGER.info(
@@ -94,12 +94,24 @@ async def async_setup_entry(
coordinator = entry.runtime_data
async_add_entities(
AmazonBinarySensorEntity(coordinator, serial_num, sensor_desc)
for sensor_desc in BINARY_SENSORS
for serial_num in coordinator.data
if sensor_desc.is_supported(coordinator.data[serial_num], sensor_desc.key)
)
known_devices: set[str] = set()
def _check_device() -> None:
current_devices = set(coordinator.data)
new_devices = current_devices - known_devices
if new_devices:
known_devices.update(new_devices)
async_add_entities(
AmazonBinarySensorEntity(coordinator, serial_num, sensor_desc)
for sensor_desc in BINARY_SENSORS
for serial_num in new_devices
if sensor_desc.is_supported(
coordinator.data[serial_num], sensor_desc.key
)
)
_check_device()
entry.async_on_unload(coordinator.async_add_listener(_check_device))
class AmazonBinarySensorEntity(AmazonEntity, BinarySensorEntity):
@@ -52,7 +52,7 @@ class AmazonDevicesConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Alexa Devices."""
VERSION = 1
MINOR_VERSION = 2
MINOR_VERSION = 3
async def async_step_user(
self, user_input: dict[str, Any] | None = None
@@ -107,7 +107,9 @@ class AmazonDevicesConfigFlow(ConfigFlow, domain=DOMAIN):
if user_input is not None:
try:
await validate_input(self.hass, {**reauth_entry.data, **user_input})
data = await validate_input(
self.hass, {**reauth_entry.data, **user_input}
)
except CannotConnect:
errors["base"] = "cannot_connect"
except (CannotAuthenticate, TypeError):
@@ -119,8 +121,9 @@ class AmazonDevicesConfigFlow(ConfigFlow, domain=DOMAIN):
reauth_entry,
data={
CONF_USERNAME: entry_data[CONF_USERNAME],
CONF_PASSWORD: entry_data[CONF_PASSWORD],
CONF_PASSWORD: user_input[CONF_PASSWORD],
CONF_CODE: user_input[CONF_CODE],
CONF_LOGIN_DATA: data,
},
)
@@ -6,6 +6,7 @@ _LOGGER = logging.getLogger(__package__)
DOMAIN = "alexa_devices"
CONF_LOGIN_DATA = "login_data"
CONF_SITE = "site"
DEFAULT_DOMAIN = "com"
COUNTRY_DOMAINS = {
@@ -14,6 +14,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import _LOGGER, CONF_LOGIN_DATA, DOMAIN
@@ -48,12 +49,13 @@ class AmazonDevicesCoordinator(DataUpdateCoordinator[dict[str, AmazonDevice]]):
entry.data[CONF_PASSWORD],
entry.data[CONF_LOGIN_DATA],
)
self.previous_devices: set[str] = set()
async def _async_update_data(self) -> dict[str, AmazonDevice]:
"""Update device data."""
try:
await self.api.login_mode_stored_data()
return await self.api.get_devices_data()
data = await self.api.get_devices_data()
except CannotConnect as err:
raise UpdateFailed(
translation_domain=DOMAIN,
@@ -72,3 +74,31 @@ class AmazonDevicesCoordinator(DataUpdateCoordinator[dict[str, AmazonDevice]]):
translation_key="invalid_auth",
translation_placeholders={"error": repr(err)},
) from err
else:
current_devices = set(data.keys())
if stale_devices := self.previous_devices - current_devices:
await self._async_remove_device_stale(stale_devices)
self.previous_devices = current_devices
return data
async def _async_remove_device_stale(
self,
stale_devices: set[str],
) -> None:
"""Remove stale device."""
device_registry = dr.async_get(self.hass)
for serial_num in stale_devices:
_LOGGER.debug(
"Detected change in devices: serial %s removed",
serial_num,
)
device = device_registry.async_get_device(
identifiers={(DOMAIN, serial_num)}
)
if device:
device_registry.async_update_device(
device_id=device.id,
remove_config_entry_id=self.config_entry.entry_id,
)
@@ -7,6 +7,6 @@
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["aioamazondevices"],
"quality_scale": "silver",
"quality_scale": "platinum",
"requirements": ["aioamazondevices==6.0.0"]
}
@@ -57,13 +57,23 @@ async def async_setup_entry(
coordinator = entry.runtime_data
async_add_entities(
AmazonNotifyEntity(coordinator, serial_num, sensor_desc)
for sensor_desc in NOTIFY
for serial_num in coordinator.data
if sensor_desc.subkey in coordinator.data[serial_num].capabilities
and sensor_desc.is_supported(coordinator.data[serial_num])
)
known_devices: set[str] = set()
def _check_device() -> None:
current_devices = set(coordinator.data)
new_devices = current_devices - known_devices
if new_devices:
known_devices.update(new_devices)
async_add_entities(
AmazonNotifyEntity(coordinator, serial_num, sensor_desc)
for sensor_desc in NOTIFY
for serial_num in new_devices
if sensor_desc.subkey in coordinator.data[serial_num].capabilities
and sensor_desc.is_supported(coordinator.data[serial_num])
)
_check_device()
entry.async_on_unload(coordinator.async_add_listener(_check_device))
class AmazonNotifyEntity(AmazonEntity, NotifyEntity):
@@ -53,7 +53,7 @@ rules:
docs-supported-functions: done
docs-troubleshooting: done
docs-use-cases: done
dynamic-devices: todo
dynamic-devices: done
entity-category: done
entity-device-class: done
entity-disabled-by-default: done
@@ -64,9 +64,7 @@ rules:
repair-issues:
status: exempt
comment: no known use cases for repair issues or flows, yet
stale-devices:
status: todo
comment: automate the cleanup process
stale-devices: done
# Platinum
async-dependency: done
@@ -62,12 +62,22 @@ async def async_setup_entry(
coordinator = entry.runtime_data
async_add_entities(
AmazonSensorEntity(coordinator, serial_num, sensor_desc)
for sensor_desc in SENSORS
for serial_num in coordinator.data
if coordinator.data[serial_num].sensors.get(sensor_desc.key) is not None
)
known_devices: set[str] = set()
def _check_device() -> None:
current_devices = set(coordinator.data)
new_devices = current_devices - known_devices
if new_devices:
known_devices.update(new_devices)
async_add_entities(
AmazonSensorEntity(coordinator, serial_num, sensor_desc)
for sensor_desc in SENSORS
for serial_num in new_devices
if coordinator.data[serial_num].sensors.get(sensor_desc.key) is not None
)
_check_device()
entry.async_on_unload(coordinator.async_add_listener(_check_device))
class AmazonSensorEntity(AmazonEntity, SensorEntity):
@@ -104,10 +104,6 @@
"sound": {
"name": "Alexa Skill sound file",
"description": "The sound file to play."
},
"sound_variant": {
"name": "Sound variant",
"description": "The variant of the sound to play."
}
}
},
@@ -48,12 +48,22 @@ async def async_setup_entry(
coordinator = entry.runtime_data
async_add_entities(
AmazonSwitchEntity(coordinator, serial_num, switch_desc)
for switch_desc in SWITCHES
for serial_num in coordinator.data
if switch_desc.subkey in coordinator.data[serial_num].capabilities
)
known_devices: set[str] = set()
def _check_device() -> None:
current_devices = set(coordinator.data)
new_devices = current_devices - known_devices
if new_devices:
known_devices.update(new_devices)
async_add_entities(
AmazonSwitchEntity(coordinator, serial_num, switch_desc)
for switch_desc in SWITCHES
for serial_num in new_devices
if switch_desc.subkey in coordinator.data[serial_num].capabilities
)
_check_device()
entry.async_on_unload(coordinator.async_add_listener(_check_device))
class AmazonSwitchEntity(AmazonEntity, SwitchEntity):
+1 -1
View File
@@ -41,7 +41,7 @@ def async_setup_services(hass: HomeAssistant) -> None:
if call.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_NONE:
return []
call_ids = await async_extract_entity_ids(hass, call)
call_ids = await async_extract_entity_ids(call)
entity_ids = []
for entity_id in hass.data[DATA_AMCREST][CAMERAS]:
if entity_id not in call_ids:
+16 -1
View File
@@ -12,10 +12,25 @@ from homeassistant.helpers.event import async_call_later, async_track_time_inter
from homeassistant.helpers.typing import ConfigType
from homeassistant.util.hass_dict import HassKey
from .analytics import Analytics
from .analytics import (
Analytics,
AnalyticsInput,
AnalyticsModifications,
DeviceAnalyticsModifications,
EntityAnalyticsModifications,
async_devices_payload,
)
from .const import ATTR_ONBOARDED, ATTR_PREFERENCES, DOMAIN, INTERVAL, PREFERENCE_SCHEMA
from .http import AnalyticsDevicesView
__all__ = [
"AnalyticsInput",
"AnalyticsModifications",
"DeviceAnalyticsModifications",
"EntityAnalyticsModifications",
"async_devices_payload",
]
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
DATA_COMPONENT: HassKey[Analytics] = HassKey(DOMAIN)
+294 -41
View File
@@ -4,9 +4,10 @@ from __future__ import annotations
import asyncio
from asyncio import timeout
from dataclasses import asdict as dataclass_asdict, dataclass
from collections.abc import Awaitable, Callable, Iterable, Mapping
from dataclasses import asdict as dataclass_asdict, dataclass, field
from datetime import datetime
from typing import Any
from typing import Any, Protocol
import uuid
import aiohttp
@@ -24,17 +25,25 @@ from homeassistant.components.recorder import (
get_instance as get_recorder_instance,
)
from homeassistant.config_entries import SOURCE_IGNORE
from homeassistant.const import ATTR_DOMAIN, BASE_PLATFORMS, __version__ as HA_VERSION
from homeassistant.const import (
ATTR_ASSUMED_STATE,
ATTR_DOMAIN,
BASE_PLATFORMS,
__version__ as HA_VERSION,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.hassio import is_hassio
from homeassistant.helpers.singleton import singleton
from homeassistant.helpers.storage import Store
from homeassistant.helpers.system_info import async_get_system_info
from homeassistant.helpers.typing import UNDEFINED
from homeassistant.loader import (
Integration,
IntegrationNotFound,
async_get_integration,
async_get_integrations,
)
from homeassistant.setup import async_get_loaded_integrations
@@ -70,12 +79,115 @@ from .const import (
ATTR_USER_COUNT,
ATTR_UUID,
ATTR_VERSION,
DOMAIN,
LOGGER,
PREFERENCE_SCHEMA,
STORAGE_KEY,
STORAGE_VERSION,
)
DATA_ANALYTICS_MODIFIERS = "analytics_modifiers"
type AnalyticsModifier = Callable[
[HomeAssistant, AnalyticsInput], Awaitable[AnalyticsModifications]
]
@singleton(DATA_ANALYTICS_MODIFIERS)
def _async_get_modifiers(
hass: HomeAssistant,
) -> dict[str, AnalyticsModifier | None]:
"""Return the analytics modifiers."""
return {}
@dataclass
class AnalyticsInput:
"""Analytics input for a single integration.
This is sent to integrations that implement the platform.
"""
device_ids: Iterable[str] = field(default_factory=list)
entity_ids: Iterable[str] = field(default_factory=list)
@dataclass
class AnalyticsModifications:
"""Analytics config for a single integration.
This is used by integrations that implement the platform.
"""
remove: bool = False
devices: Mapping[str, DeviceAnalyticsModifications] | None = None
entities: Mapping[str, EntityAnalyticsModifications] | None = None
@dataclass
class DeviceAnalyticsModifications:
"""Analytics config for a single device.
This is used by integrations that implement the platform.
"""
remove: bool = False
@dataclass
class EntityAnalyticsModifications:
"""Analytics config for a single entity.
This is used by integrations that implement the platform.
"""
remove: bool = False
class AnalyticsPlatformProtocol(Protocol):
"""Define the format of analytics platforms."""
async def async_modify_analytics(
self,
hass: HomeAssistant,
analytics_input: AnalyticsInput,
) -> AnalyticsModifications:
"""Modify the analytics."""
async def _async_get_analytics_platform(
hass: HomeAssistant, domain: str
) -> AnalyticsPlatformProtocol | None:
"""Get analytics platform."""
try:
integration = await async_get_integration(hass, domain)
except IntegrationNotFound:
return None
try:
return await integration.async_get_platform(DOMAIN)
except ImportError:
return None
async def _async_get_modifier(
hass: HomeAssistant, domain: str
) -> AnalyticsModifier | None:
"""Get analytics modifier."""
modifiers = _async_get_modifiers(hass)
modifier = modifiers.get(domain, UNDEFINED)
if modifier is not UNDEFINED:
return modifier
platform = await _async_get_analytics_platform(hass, domain)
if platform is None:
modifiers[domain] = None
return None
modifier = getattr(platform, "async_modify_analytics", None)
modifiers[domain] = modifier
return modifier
def gen_uuid() -> str:
"""Generate a new UUID."""
@@ -388,67 +500,208 @@ def _domains_from_yaml_config(yaml_configuration: dict[str, Any]) -> set[str]:
return domains
DEFAULT_ANALYTICS_CONFIG = AnalyticsModifications()
DEFAULT_DEVICE_ANALYTICS_CONFIG = DeviceAnalyticsModifications()
DEFAULT_ENTITY_ANALYTICS_CONFIG = EntityAnalyticsModifications()
async def async_devices_payload(hass: HomeAssistant) -> dict:
"""Return the devices payload."""
devices: list[dict[str, Any]] = []
"""Return detailed information about entities and devices."""
dev_reg = dr.async_get(hass)
# Devices that need via device info set
new_indexes: dict[str, int] = {}
via_devices: dict[str, str] = {}
ent_reg = er.async_get(hass)
seen_integrations = set()
integration_inputs: dict[str, tuple[list[str], list[str]]] = {}
integration_configs: dict[str, AnalyticsModifications] = {}
for device in dev_reg.devices.values():
if not device.primary_config_entry:
# Get device list
for device_entry in dev_reg.devices.values():
if not device_entry.primary_config_entry:
continue
config_entry = hass.config_entries.async_get_entry(device.primary_config_entry)
config_entry = hass.config_entries.async_get_entry(
device_entry.primary_config_entry
)
if config_entry is None:
continue
seen_integrations.add(config_entry.domain)
integration_domain = config_entry.domain
new_indexes[device.id] = len(devices)
devices.append(
{
"integration": config_entry.domain,
"manufacturer": device.manufacturer,
"model_id": device.model_id,
"model": device.model,
"sw_version": device.sw_version,
"hw_version": device.hw_version,
"has_configuration_url": device.configuration_url is not None,
"via_device": None,
"entry_type": device.entry_type.value if device.entry_type else None,
}
)
integration_input = integration_inputs.setdefault(integration_domain, ([], []))
integration_input[0].append(device_entry.id)
if device.via_device_id:
via_devices[device.id] = device.via_device_id
# Get entity list
for entity_entry in ent_reg.entities.values():
integration_domain = entity_entry.platform
for from_device, via_device in via_devices.items():
if via_device not in new_indexes:
continue
devices[new_indexes[from_device]]["via_device"] = new_indexes[via_device]
integration_input = integration_inputs.setdefault(integration_domain, ([], []))
integration_input[1].append(entity_entry.entity_id)
integrations = {
domain: integration
for domain, integration in (
await async_get_integrations(hass, seen_integrations)
await async_get_integrations(hass, integration_inputs.keys())
).items()
if isinstance(integration, Integration)
}
for device_info in devices:
if integration := integrations.get(device_info["integration"]):
device_info["is_custom_integration"] = not integration.is_built_in
# Include version for custom integrations
if not integration.is_built_in and integration.version:
device_info["custom_integration_version"] = str(integration.version)
# Filter out custom integrations and integrations that are not device or hub type
integration_inputs = {
domain: integration_info
for domain, integration_info in integration_inputs.items()
if (integration := integrations.get(domain)) is not None
and integration.is_built_in
and integration.integration_type in ("device", "hub")
}
# Call integrations that implement the analytics platform
for integration_domain, integration_input in integration_inputs.items():
if (
modifier := await _async_get_modifier(hass, integration_domain)
) is not None:
try:
integration_config = await modifier(
hass, AnalyticsInput(*integration_input)
)
except Exception as err: # noqa: BLE001
LOGGER.exception(
"Calling async_modify_analytics for integration '%s' failed: %s",
integration_domain,
err,
)
integration_configs[integration_domain] = AnalyticsModifications(
remove=True
)
continue
if not isinstance(integration_config, AnalyticsModifications):
LOGGER.error( # type: ignore[unreachable]
"Calling async_modify_analytics for integration '%s' did not return an AnalyticsConfig",
integration_domain,
)
integration_configs[integration_domain] = AnalyticsModifications(
remove=True
)
continue
integration_configs[integration_domain] = integration_config
integrations_info: dict[str, dict[str, Any]] = {}
# We need to refer to other devices, for example in `via_device` field.
# We don't however send the original device ids outside of Home Assistant,
# instead we refer to devices by (integration_domain, index_in_integration_device_list).
device_id_mapping: dict[str, tuple[str, int]] = {}
# Fill out information about devices
for integration_domain, integration_input in integration_inputs.items():
integration_config = integration_configs.get(
integration_domain, DEFAULT_ANALYTICS_CONFIG
)
if integration_config.remove:
continue
integration_info = integrations_info.setdefault(
integration_domain, {"devices": [], "entities": []}
)
devices_info = integration_info["devices"]
for device_id in integration_input[0]:
device_config = DEFAULT_DEVICE_ANALYTICS_CONFIG
if integration_config.devices is not None:
device_config = integration_config.devices.get(device_id, device_config)
if device_config.remove:
continue
device_entry = dev_reg.devices[device_id]
device_id_mapping[device_entry.id] = (integration_domain, len(devices_info))
devices_info.append(
{
"entities": [],
"entry_type": device_entry.entry_type,
"has_configuration_url": device_entry.configuration_url is not None,
"hw_version": device_entry.hw_version,
"manufacturer": device_entry.manufacturer,
"model": device_entry.model,
"model_id": device_entry.model_id,
"sw_version": device_entry.sw_version,
"via_device": device_entry.via_device_id,
}
)
# Fill out via_device with new device ids
for integration_info in integrations_info.values():
for device_info in integration_info["devices"]:
if device_info["via_device"] is None:
continue
device_info["via_device"] = device_id_mapping.get(device_info["via_device"])
# Fill out information about entities
for integration_domain, integration_input in integration_inputs.items():
integration_config = integration_configs.get(
integration_domain, DEFAULT_ANALYTICS_CONFIG
)
if integration_config.remove:
continue
integration_info = integrations_info.setdefault(
integration_domain, {"devices": [], "entities": []}
)
devices_info = integration_info["devices"]
entities_info = integration_info["entities"]
for entity_id in integration_input[1]:
entity_config = DEFAULT_ENTITY_ANALYTICS_CONFIG
if integration_config.entities is not None:
entity_config = integration_config.entities.get(
entity_id, entity_config
)
if entity_config.remove:
continue
entity_entry = ent_reg.entities[entity_id]
entity_state = hass.states.get(entity_entry.entity_id)
entity_info = {
# LIMITATION: `assumed_state` can be overridden by users;
# we should replace it with the original value in the future.
# It is also not present, if entity is not in the state machine,
# which can happen for disabled entities.
"assumed_state": (
entity_state.attributes.get(ATTR_ASSUMED_STATE, False)
if entity_state is not None
else None
),
"domain": entity_entry.domain,
"entity_category": entity_entry.entity_category,
"has_entity_name": entity_entry.has_entity_name,
"original_device_class": entity_entry.original_device_class,
# LIMITATION: `unit_of_measurement` can be overridden by users;
# we should replace it with the original value in the future.
"unit_of_measurement": entity_entry.unit_of_measurement,
}
if (
((device_id_ := entity_entry.device_id) is not None)
and ((new_device_id := device_id_mapping.get(device_id_)) is not None)
and (new_device_id[0] == integration_domain)
):
device_info = devices_info[new_device_id[1]]
device_info["entities"].append(entity_info)
else:
entities_info.append(entity_info)
return {
"version": "home-assistant:1",
"home_assistant": HA_VERSION,
"devices": devices,
"integrations": integrations_info,
}
@@ -2,7 +2,7 @@
"domain": "analytics",
"name": "Analytics",
"after_dependencies": ["energy", "hassio", "recorder"],
"codeowners": ["@home-assistant/core", "@ludeeus"],
"codeowners": ["@home-assistant/core"],
"dependencies": ["api", "websocket_api", "http"],
"documentation": "https://www.home-assistant.io/integrations/analytics",
"integration_type": "system",
@@ -33,9 +33,11 @@ from homeassistant.const import (
)
from homeassistant.core import Event, HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.device_registry import format_mac
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.storage import STORAGE_DIR
from homeassistant.helpers.typing import ConfigType
from .const import (
CONF_ADB_SERVER_IP,
@@ -46,10 +48,12 @@ from .const import (
DEFAULT_ADB_SERVER_PORT,
DEVICE_ANDROIDTV,
DEVICE_FIRETV,
DOMAIN,
PROP_ETHMAC,
PROP_WIFIMAC,
SIGNAL_CONFIG_ENTITY,
)
from .services import async_setup_services
ADB_PYTHON_EXCEPTIONS: tuple = (
AdbTimeoutError,
@@ -63,6 +67,8 @@ ADB_PYTHON_EXCEPTIONS: tuple = (
)
ADB_TCP_EXCEPTIONS: tuple = (ConnectionResetError, RuntimeError)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
PLATFORMS = [Platform.MEDIA_PLAYER, Platform.REMOTE]
RELOAD_OPTIONS = [CONF_STATE_DETECTION_RULES]
@@ -188,6 +194,12 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Android TV / Fire TV integration."""
async_setup_services(hass)
return True
async def async_setup_entry(hass: HomeAssistant, entry: AndroidTVConfigEntry) -> bool:
"""Set up Android Debug Bridge platform."""
@@ -8,7 +8,6 @@ import logging
from androidtv.constants import APPS, KEYS
from androidtv.setup_async import AndroidTVAsync, FireTVAsync
import voluptuous as vol
from homeassistant.components import persistent_notification
from homeassistant.components.media_player import (
@@ -17,9 +16,7 @@ from homeassistant.components.media_player import (
MediaPlayerEntityFeature,
MediaPlayerState,
)
from homeassistant.const import ATTR_COMMAND
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util.dt import utcnow
@@ -39,19 +36,10 @@ from .const import (
SIGNAL_CONFIG_ENTITY,
)
from .entity import AndroidTVEntity, adb_decorator
from .services import ATTR_ADB_RESPONSE, ATTR_HDMI_INPUT, SERVICE_LEARN_SENDEVENT
_LOGGER = logging.getLogger(__name__)
ATTR_ADB_RESPONSE = "adb_response"
ATTR_DEVICE_PATH = "device_path"
ATTR_HDMI_INPUT = "hdmi_input"
ATTR_LOCAL_PATH = "local_path"
SERVICE_ADB_COMMAND = "adb_command"
SERVICE_DOWNLOAD = "download"
SERVICE_LEARN_SENDEVENT = "learn_sendevent"
SERVICE_UPLOAD = "upload"
# Translate from `AndroidTV` / `FireTV` reported state to HA state.
ANDROIDTV_STATES = {
"off": MediaPlayerState.OFF,
@@ -77,32 +65,6 @@ async def async_setup_entry(
]
)
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_ADB_COMMAND,
{vol.Required(ATTR_COMMAND): cv.string},
"adb_command",
)
platform.async_register_entity_service(
SERVICE_LEARN_SENDEVENT, None, "learn_sendevent"
)
platform.async_register_entity_service(
SERVICE_DOWNLOAD,
{
vol.Required(ATTR_DEVICE_PATH): cv.string,
vol.Required(ATTR_LOCAL_PATH): cv.string,
},
"service_download",
)
platform.async_register_entity_service(
SERVICE_UPLOAD,
{
vol.Required(ATTR_DEVICE_PATH): cv.string,
vol.Required(ATTR_LOCAL_PATH): cv.string,
},
"service_upload",
)
class ADBDevice(AndroidTVEntity, MediaPlayerEntity):
"""Representation of an Android or Fire TV device."""
@@ -0,0 +1,66 @@
"""Services for Android/Fire TV devices."""
from __future__ import annotations
import voluptuous as vol
from homeassistant.components.media_player import DOMAIN as MEDIA_PLAYER_DOMAIN
from homeassistant.const import ATTR_COMMAND
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, service
from .const import DOMAIN
ATTR_ADB_RESPONSE = "adb_response"
ATTR_DEVICE_PATH = "device_path"
ATTR_HDMI_INPUT = "hdmi_input"
ATTR_LOCAL_PATH = "local_path"
SERVICE_ADB_COMMAND = "adb_command"
SERVICE_DOWNLOAD = "download"
SERVICE_LEARN_SENDEVENT = "learn_sendevent"
SERVICE_UPLOAD = "upload"
@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Register the Android TV / Fire TV services."""
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_ADB_COMMAND,
entity_domain=MEDIA_PLAYER_DOMAIN,
schema={vol.Required(ATTR_COMMAND): cv.string},
func="adb_command",
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_LEARN_SENDEVENT,
entity_domain=MEDIA_PLAYER_DOMAIN,
schema=None,
func="learn_sendevent",
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_DOWNLOAD,
entity_domain=MEDIA_PLAYER_DOMAIN,
schema={
vol.Required(ATTR_DEVICE_PATH): cv.string,
vol.Required(ATTR_LOCAL_PATH): cv.string,
},
func="service_download",
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_UPLOAD,
entity_domain=MEDIA_PLAYER_DOMAIN,
schema={
vol.Required(ATTR_DEVICE_PATH): cv.string,
vol.Required(ATTR_LOCAL_PATH): cv.string,
},
func="service_upload",
)
@@ -37,7 +37,7 @@ from .helpers import AndroidTVRemoteConfigEntry, create_api, get_enable_ime
_LOGGER = logging.getLogger(__name__)
APPS_NEW_ID = "NewApp"
APPS_NEW_ID = "add_new"
CONF_APP_DELETE = "app_delete"
CONF_APP_ID = "app_id"
@@ -66,9 +66,14 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
if user_input is not None:
self.host = user_input[CONF_HOST]
api = create_api(self.hass, self.host, enable_ime=False)
await api.async_generate_cert_if_missing()
try:
await api.async_generate_cert_if_missing()
self.name, self.mac = await api.async_get_name_and_mac()
except CannotConnect:
# Likely invalid IP address or device is network unreachable. Stay
# in the user step allowing the user to enter a different host.
errors["base"] = "cannot_connect"
else:
await self.async_set_unique_id(format_mac(self.mac))
if self.source == SOURCE_RECONFIGURE:
self._abort_if_unique_id_mismatch()
@@ -81,11 +86,10 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
},
)
self._abort_if_unique_id_configured(updates={CONF_HOST: self.host})
return await self._async_start_pair()
except (CannotConnect, ConnectionClosed):
# Likely invalid IP address or device is network unreachable. Stay
# in the user step allowing the user to enter a different host.
errors["base"] = "cannot_connect"
try:
return await self._async_start_pair()
except (CannotConnect, ConnectionClosed):
errors["base"] = "cannot_connect"
else:
user_input = {}
default_host = user_input.get(CONF_HOST, vol.UNDEFINED)
@@ -112,22 +116,9 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle the pair step."""
errors: dict[str, str] = {}
if user_input is not None:
pin = user_input["pin"]
try:
pin = user_input["pin"]
await self.api.async_finish_pairing(pin)
if self.source == SOURCE_REAUTH:
return self.async_update_reload_and_abort(
self._get_reauth_entry(), reload_even_if_entry_is_unchanged=True
)
return self.async_create_entry(
title=self.name,
data={
CONF_HOST: self.host,
CONF_NAME: self.name,
CONF_MAC: self.mac,
},
)
except InvalidAuth:
# Invalid PIN. Stay in the pair step allowing the user to enter
# a different PIN.
@@ -145,6 +136,20 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
# them to enter a new IP address but we cannot do that for the zeroconf
# flow. Simpler to abort for both flows.
return self.async_abort(reason="cannot_connect")
else:
if self.source == SOURCE_REAUTH:
return self.async_update_reload_and_abort(
self._get_reauth_entry(), reload_even_if_entry_is_unchanged=True
)
return self.async_create_entry(
title=self.name,
data={
CONF_HOST: self.host,
CONF_NAME: self.name,
CONF_MAC: self.mac,
},
)
return self.async_show_form(
step_id="pair",
data_schema=STEP_PAIR_DATA_SCHEMA,
@@ -282,7 +287,9 @@ class AndroidTVRemoteOptionsFlowHandler(OptionsFlowWithReload):
{
vol.Optional(CONF_APPS): SelectSelector(
SelectSelectorConfig(
options=apps, mode=SelectSelectorMode.DROPDOWN
options=apps,
mode=SelectSelectorMode.DROPDOWN,
translation_key="apps",
)
),
vol.Required(
@@ -6,7 +6,7 @@ from typing import Any
from androidtvremote2 import AndroidTVRemote, ConnectionClosed
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME
from homeassistant.const import CONF_MAC, CONF_NAME
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
@@ -28,8 +28,6 @@ class AndroidTVRemoteBaseEntity(Entity):
) -> None:
"""Initialize the entity."""
self._api = api
self._host = config_entry.data[CONF_HOST]
self._name = config_entry.data[CONF_NAME]
self._apps: dict[str, Any] = config_entry.options.get(CONF_APPS, {})
self._attr_unique_id = config_entry.unique_id
self._attr_is_on = api.is_on
@@ -39,7 +37,7 @@ class AndroidTVRemoteBaseEntity(Entity):
self._attr_device_info = DeviceInfo(
connections={(CONNECTION_NETWORK_MAC, config_entry.data[CONF_MAC])},
identifiers={(DOMAIN, config_entry.unique_id)},
name=self._name,
name=config_entry.data[CONF_NAME],
manufacturer=device_info["manufacturer"],
model=device_info["model"],
)
@@ -7,6 +7,7 @@
"integration_type": "device",
"iot_class": "local_push",
"loggers": ["androidtvremote2"],
"quality_scale": "platinum",
"requirements": ["androidtvremote2==0.2.3"],
"zeroconf": ["_androidtvremote2._tcp.local."]
}
@@ -175,7 +175,11 @@ class AndroidTVRemoteMediaPlayerEntity(AndroidTVRemoteBaseEntity, MediaPlayerEnt
"""Play a piece of media."""
if media_type == MediaType.CHANNEL:
if not media_id.isnumeric():
raise ValueError(f"Channel must be numeric: {media_id}")
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="invalid_channel",
translation_placeholders={"media_id": media_id},
)
if self._channel_set_task:
self._channel_set_task.cancel()
self._channel_set_task = asyncio.create_task(
@@ -188,7 +192,11 @@ class AndroidTVRemoteMediaPlayerEntity(AndroidTVRemoteBaseEntity, MediaPlayerEnt
self._send_launch_app_command(media_id)
return
raise ValueError(f"Invalid media type: {media_type}")
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="invalid_media_type",
translation_placeholders={"media_type": media_type},
)
async def async_browse_media(
self,
@@ -0,0 +1,78 @@
rules:
# Bronze
action-setup:
status: exempt
comment: No integration-specific service actions are defined.
appropriate-polling:
status: exempt
comment: This is a push-based integration.
brands: done
common-modules: done
config-flow-test-coverage: done
config-flow: done
dependency-transparency: done
docs-actions: done
docs-high-level-description: done
docs-installation-instructions: done
docs-removal-instructions: done
entity-event-setup: done
entity-unique-id: done
has-entity-name: done
runtime-data: done
test-before-configure: done
test-before-setup: done
unique-config-entry: done
# Silver
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters: done
docs-installation-parameters: done
entity-unavailable: done
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: done
test-coverage: done
# Gold
devices: done
diagnostics: done
discovery-update-info: done
discovery: done
docs-data-update: done
docs-examples: done
docs-known-limitations: done
docs-supported-devices: done
docs-supported-functions: done
docs-troubleshooting: done
docs-use-cases: done
dynamic-devices:
status: exempt
comment: The integration is configured on a per-device basis, so there are no dynamic devices to add.
entity-category:
status: exempt
comment: All entities are primary and do not require a specific category.
entity-device-class: done
entity-disabled-by-default:
status: exempt
comment: The integration provides only primary entities that should be enabled.
entity-translations: done
exception-translations: done
icon-translations:
status: exempt
comment: Icons are provided by the entity's device class, and no state-based icons are needed.
reconfiguration-flow: done
repair-issues:
status: exempt
comment: The integration uses the reauth flow for authentication issues, and no other repairable issues have been identified.
stale-devices:
status: exempt
comment: The integration manages a single device per config entry. Stale device removal is handled by removing the config entry.
# Platinum
async-dependency: done
inject-websession:
status: exempt
comment: The underlying library does not use HTTP for communication.
strict-typing: done
@@ -22,7 +22,7 @@
},
"zeroconf_confirm": {
"title": "Discovered Android TV",
"description": "Do you want to add the Android TV ({name}) to Home Assistant? It will turn on and a pairing code will be displayed on it that you will need to enter in the next screen."
"description": "Do you want to add the Android TV ({name}) to Home Assistant? It will turn on and a pairing code will be displayed on it that you will need to enter in the next screen."
},
"pair": {
"description": "Enter the pairing code displayed on the Android TV ({name}).",
@@ -85,6 +85,19 @@
"exceptions": {
"connection_closed": {
"message": "Connection to the Android TV device is closed"
},
"invalid_channel": {
"message": "Channel must be numeric: {media_id}"
},
"invalid_media_type": {
"message": "Invalid media type: {media_type}"
}
},
"selector": {
"apps": {
"options": {
"add_new": "Add new"
}
}
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ from .coordinator import (
AOSmithStatusCoordinator,
)
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.WATER_HEATER]
PLATFORMS: list[Platform] = [Platform.SELECT, Platform.SENSOR, Platform.WATER_HEATER]
async def async_setup_entry(hass: HomeAssistant, entry: AOSmithConfigEntry) -> bool:
@@ -1,5 +1,10 @@
{
"entity": {
"select": {
"hot_water_plus_level": {
"default": "mdi:water-plus"
}
},
"sensor": {
"hot_water_availability": {
"default": "mdi:water-thermometer"
@@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/aosmith",
"iot_class": "cloud_polling",
"requirements": ["py-aosmith==1.0.12"]
"requirements": ["py-aosmith==1.0.14"]
}
@@ -0,0 +1,70 @@
"""The select platform for the A. O. Smith integration."""
from homeassistant.components.select import SelectEntity
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import AOSmithConfigEntry
from .coordinator import AOSmithStatusCoordinator
from .entity import AOSmithStatusEntity
HWP_LEVEL_HA_TO_AOSMITH = {
"off": 0,
"level1": 1,
"level2": 2,
"level3": 3,
}
HWP_LEVEL_AOSMITH_TO_HA = {value: key for key, value in HWP_LEVEL_HA_TO_AOSMITH.items()}
async def async_setup_entry(
hass: HomeAssistant,
entry: AOSmithConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up A. O. Smith select platform."""
data = entry.runtime_data
async_add_entities(
AOSmithHotWaterPlusSelectEntity(data.status_coordinator, device.junction_id)
for device in data.status_coordinator.data.values()
if device.supports_hot_water_plus
)
class AOSmithHotWaterPlusSelectEntity(AOSmithStatusEntity, SelectEntity):
"""Class for the Hot Water+ select entity."""
_attr_translation_key = "hot_water_plus_level"
_attr_options = list(HWP_LEVEL_HA_TO_AOSMITH)
def __init__(self, coordinator: AOSmithStatusCoordinator, junction_id: str) -> None:
"""Initialize the entity."""
super().__init__(coordinator, junction_id)
self._attr_unique_id = f"hot_water_plus_level_{junction_id}"
@property
def suggested_object_id(self) -> str | None:
"""Override the suggested object id to make '+' get converted to 'plus' in the entity id."""
return "hot_water_plus_level"
@property
def current_option(self) -> str | None:
"""Return the current Hot Water+ mode."""
hot_water_plus_level = self.device.status.hot_water_plus_level
return (
None
if hot_water_plus_level is None
else HWP_LEVEL_AOSMITH_TO_HA.get(hot_water_plus_level)
)
async def async_select_option(self, option: str) -> None:
"""Set the Hot Water+ mode."""
aosmith_hwp_level = HWP_LEVEL_HA_TO_AOSMITH[option]
await self.client.update_mode(
junction_id=self.junction_id,
mode=self.device.status.current_mode,
hot_water_plus_level=aosmith_hwp_level,
)
await self.coordinator.async_request_refresh()
@@ -26,6 +26,17 @@
}
},
"entity": {
"select": {
"hot_water_plus_level": {
"name": "Hot Water+ level",
"state": {
"off": "[%key:common::state::off%]",
"level1": "Level 1",
"level2": "Level 2",
"level3": "Level 3"
}
}
},
"sensor": {
"hot_water_availability": {
"name": "Hot water availability"
@@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/apcupsd",
"iot_class": "local_polling",
"loggers": ["apcaccess"],
"quality_scale": "bronze",
"requirements": ["aioapcaccess==0.4.2"]
"quality_scale": "platinum",
"requirements": ["aioapcaccess==1.0.0"]
}
@@ -43,10 +43,7 @@ rules:
status: exempt
comment: |
The integration does not require authentication.
test-coverage:
status: todo
comment: |
Patch `aioapcaccess.request_status` where we use it.
test-coverage: done
# Gold
devices: done
diagnostics: done
+5 -1
View File
@@ -395,6 +395,7 @@ SENSORS: dict[str, SensorEntityDescription] = {
"upsmode": SensorEntityDescription(
key="upsmode",
translation_key="ups_mode",
entity_category=EntityCategory.DIAGNOSTIC,
),
"upsname": SensorEntityDescription(
key="upsname",
@@ -466,7 +467,10 @@ async def async_setup_entry(
# periodical (or manual) self test since last daemon restart. It might not be available
# when we set up the integration, and we do not know if it would ever be available. Here we
# add it anyway and mark it as unknown initially.
for resource in available_resources | {LAST_S_TEST}:
#
# We also sort the resources to ensure the order of entities created is deterministic since
# "APCMODEL" and "MODEL" resources map to the same "Model" name.
for resource in sorted(available_resources | {LAST_S_TEST}):
if resource not in SENSORS:
_LOGGER.warning("Invalid resource from APCUPSd: %s", resource.upper())
continue
@@ -103,6 +103,7 @@ async def async_pipeline_from_audio_stream(
wake_word_settings: WakeWordSettings | None = None,
audio_settings: AudioSettings | None = None,
device_id: str | None = None,
satellite_id: str | None = None,
start_stage: PipelineStage = PipelineStage.STT,
end_stage: PipelineStage = PipelineStage.TTS,
conversation_extra_system_prompt: str | None = None,
@@ -115,6 +116,7 @@ async def async_pipeline_from_audio_stream(
pipeline_input = PipelineInput(
session=session,
device_id=device_id,
satellite_id=satellite_id,
stt_metadata=stt_metadata,
stt_stream=stt_stream,
wake_word_phrase=wake_word_phrase,
@@ -1,5 +1,7 @@
"""Constants for the Assist pipeline integration."""
from pathlib import Path
DOMAIN = "assist_pipeline"
DATA_CONFIG = f"{DOMAIN}.config"
@@ -23,3 +25,5 @@ SAMPLES_PER_CHUNK = SAMPLE_RATE // (1000 // MS_PER_CHUNK) # 10 ms @ 16Khz
BYTES_PER_CHUNK = SAMPLES_PER_CHUNK * SAMPLE_WIDTH * SAMPLE_CHANNELS # 16-bit
OPTION_PREFERRED = "preferred"
ACKNOWLEDGE_PATH = Path(__file__).parent / "acknowledge.mp3"
@@ -2,7 +2,7 @@
"domain": "assist_pipeline",
"name": "Assist pipeline",
"after_dependencies": ["repairs"],
"codeowners": ["@balloob", "@synesthesiam"],
"codeowners": ["@synesthesiam", "@arturpragacz"],
"dependencies": ["conversation", "stt", "tts", "wake_word"],
"documentation": "https://www.home-assistant.io/integrations/assist_pipeline",
"integration_type": "system",
@@ -23,7 +23,12 @@ from homeassistant.components import conversation, stt, tts, wake_word, websocke
from homeassistant.const import ATTR_SUPPORTED_FEATURES, MATCH_ALL
from homeassistant.core import Context, HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import chat_session, intent
from homeassistant.helpers import (
chat_session,
device_registry as dr,
entity_registry as er,
intent,
)
from homeassistant.helpers.collection import (
CHANGE_UPDATED,
CollectionError,
@@ -45,6 +50,7 @@ from homeassistant.util.limited_size_dict import LimitedSizeDict
from .audio_enhancer import AudioEnhancer, EnhancedAudioChunk, MicroVadSpeexEnhancer
from .const import (
ACKNOWLEDGE_PATH,
BYTES_PER_CHUNK,
CONF_DEBUG_RECORDING_DIR,
DATA_CONFIG,
@@ -113,6 +119,7 @@ PIPELINE_FIELDS: VolDictType = {
vol.Required("wake_word_entity"): vol.Any(str, None),
vol.Required("wake_word_id"): vol.Any(str, None),
vol.Optional("prefer_local_intents"): bool,
vol.Optional("acknowledge_media_id"): str,
}
STORED_PIPELINE_RUNS = 10
@@ -583,6 +590,9 @@ class PipelineRun:
_device_id: str | None = None
"""Optional device id set during run start."""
_satellite_id: str | None = None
"""Optional satellite id set during run start."""
_conversation_data: PipelineConversationData | None = None
"""Data tied to the conversation ID."""
@@ -636,9 +646,12 @@ class PipelineRun:
return
pipeline_data.pipeline_debug[self.pipeline.id][self.id].events.append(event)
def start(self, conversation_id: str, device_id: str | None) -> None:
def start(
self, conversation_id: str, device_id: str | None, satellite_id: str | None
) -> None:
"""Emit run start event."""
self._device_id = device_id
self._satellite_id = satellite_id
self._start_debug_recording_thread()
data: dict[str, Any] = {
@@ -646,6 +659,8 @@ class PipelineRun:
"language": self.language,
"conversation_id": conversation_id,
}
if satellite_id is not None:
data["satellite_id"] = satellite_id
if self.runner_data is not None:
data["runner_data"] = self.runner_data
if self.tts_stream:
@@ -1057,10 +1072,12 @@ class PipelineRun:
self,
intent_input: str,
conversation_id: str,
device_id: str | None,
conversation_extra_system_prompt: str | None,
) -> str:
"""Run intent recognition portion of pipeline. Returns text to speak."""
) -> tuple[str, bool]:
"""Run intent recognition portion of pipeline.
Returns (speech, all_targets_in_satellite_area).
"""
if self.intent_agent is None or self._conversation_data is None:
raise RuntimeError("Recognize intent was not prepared")
@@ -1088,7 +1105,8 @@ class PipelineRun:
"language": input_language,
"intent_input": intent_input,
"conversation_id": conversation_id,
"device_id": device_id,
"device_id": self._device_id,
"satellite_id": self._satellite_id,
"prefer_local_intents": self.pipeline.prefer_local_intents,
},
)
@@ -1099,7 +1117,8 @@ class PipelineRun:
text=intent_input,
context=self.context,
conversation_id=conversation_id,
device_id=device_id,
device_id=self._device_id,
satellite_id=self._satellite_id,
language=input_language,
agent_id=self.intent_agent.id,
extra_system_prompt=conversation_extra_system_prompt,
@@ -1107,6 +1126,7 @@ class PipelineRun:
agent_id = self.intent_agent.id
processed_locally = agent_id == conversation.HOME_ASSISTANT_AGENT
all_targets_in_satellite_area = False
intent_response: intent.IntentResponse | None = None
if not processed_locally and not self._intent_agent_only:
# Sentence triggers override conversation agent
@@ -1269,6 +1289,7 @@ class PipelineRun:
text=user_input.text,
conversation_id=user_input.conversation_id,
device_id=user_input.device_id,
satellite_id=user_input.satellite_id,
context=user_input.context,
language=user_input.language,
agent_id=user_input.agent_id,
@@ -1280,6 +1301,17 @@ class PipelineRun:
if tts_input_stream and self._streamed_response_text:
tts_input_stream.put_nowait(None)
if agent_id == conversation.HOME_ASSISTANT_AGENT:
# Check if all targeted entities were in the same area as
# the satellite device.
# If so, the satellite should respond with an acknowledge beep
# instead of a full response.
all_targets_in_satellite_area = (
self._get_all_targets_in_satellite_area(
conversation_result.response, self._device_id
)
)
except Exception as src_error:
_LOGGER.exception("Unexpected error during intent recognition")
raise IntentRecognitionError(
@@ -1302,7 +1334,45 @@ class PipelineRun:
if conversation_result.continue_conversation:
self._conversation_data.continue_conversation_agent = agent_id
return speech
return (speech, all_targets_in_satellite_area)
def _get_all_targets_in_satellite_area(
self, intent_response: intent.IntentResponse, device_id: str | None
) -> bool:
"""Return true if all targeted entities were in the same area as the device."""
if (
(intent_response.response_type != intent.IntentResponseType.ACTION_DONE)
or (not intent_response.matched_states)
or (not device_id)
):
return False
device_registry = dr.async_get(self.hass)
if (not (device := device_registry.async_get(device_id))) or (
not device.area_id
):
return False
entity_registry = er.async_get(self.hass)
for state in intent_response.matched_states:
entity = entity_registry.async_get(state.entity_id)
if not entity:
return False
if (entity_area_id := entity.area_id) is None:
if (entity.device_id is None) or (
(entity_device := device_registry.async_get(entity.device_id))
is None
):
return False
entity_area_id = entity_device.area_id
if entity_area_id != device.area_id:
return False
return True
async def prepare_text_to_speech(self) -> None:
"""Prepare text-to-speech."""
@@ -1340,7 +1410,9 @@ class PipelineRun:
),
) from err
async def text_to_speech(self, tts_input: str) -> None:
async def text_to_speech(
self, tts_input: str, override_media_path: Path | None = None
) -> None:
"""Run text-to-speech portion of pipeline."""
assert self.tts_stream is not None
@@ -1352,11 +1424,14 @@ class PipelineRun:
"language": self.pipeline.tts_language,
"voice": self.pipeline.tts_voice,
"tts_input": tts_input,
"acknowledge_override": override_media_path is not None,
},
)
)
if not self._streamed_response_text:
if override_media_path:
self.tts_stream.async_override_result(override_media_path)
elif not self._streamed_response_text:
self.tts_stream.async_set_message(tts_input)
tts_output = {
@@ -1567,10 +1642,15 @@ class PipelineInput:
device_id: str | None = None
"""Identifier of the device that is processing the input/output of the pipeline."""
satellite_id: str | None = None
"""Identifier of the satellite that is processing the input/output of the pipeline."""
async def execute(self) -> None:
"""Run pipeline."""
self.run.start(
conversation_id=self.session.conversation_id, device_id=self.device_id
conversation_id=self.session.conversation_id,
device_id=self.device_id,
satellite_id=self.satellite_id,
)
current_stage: PipelineStage | None = self.run.start_stage
stt_audio_buffer: list[EnhancedAudioChunk] = []
@@ -1649,17 +1729,20 @@ class PipelineInput:
if self.run.end_stage != PipelineStage.STT:
tts_input = self.tts_input
all_targets_in_satellite_area = False
if current_stage == PipelineStage.INTENT:
# intent-recognition
assert intent_input is not None
tts_input = await self.run.recognize_intent(
(
tts_input,
all_targets_in_satellite_area,
) = await self.run.recognize_intent(
intent_input,
self.session.conversation_id,
self.device_id,
self.conversation_extra_system_prompt,
)
if tts_input.strip():
if all_targets_in_satellite_area or tts_input.strip():
current_stage = PipelineStage.TTS
else:
# Skip TTS
@@ -1668,8 +1751,14 @@ class PipelineInput:
if self.run.end_stage != PipelineStage.INTENT:
# text-to-speech
if current_stage == PipelineStage.TTS:
assert tts_input is not None
await self.run.text_to_speech(tts_input)
if all_targets_in_satellite_area:
# Use acknowledge media instead of full response
await self.run.text_to_speech(
tts_input or "", override_media_path=ACKNOWLEDGE_PATH
)
else:
assert tts_input is not None
await self.run.text_to_speech(tts_input)
except PipelineError as err:
self.run.process_event(
@@ -3,6 +3,7 @@
from __future__ import annotations
from collections.abc import Iterable
from dataclasses import replace
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.const import EntityCategory, Platform
@@ -64,15 +65,36 @@ class AssistPipelineSelect(SelectEntity, restore_state.RestoreEntity):
translation_key="pipeline",
entity_category=EntityCategory.CONFIG,
)
_attr_should_poll = False
_attr_current_option = OPTION_PREFERRED
_attr_options = [OPTION_PREFERRED]
def __init__(self, hass: HomeAssistant, domain: str, unique_id_prefix: str) -> None:
def __init__(
self,
hass: HomeAssistant,
domain: str,
unique_id_prefix: str,
index: int = 0,
) -> None:
"""Initialize a pipeline selector."""
if index < 1:
# Keep compatibility
key_suffix = ""
placeholder = ""
else:
key_suffix = f"_{index + 1}"
placeholder = f" {index + 1}"
self.entity_description = replace(
self.entity_description,
key=f"pipeline{key_suffix}",
translation_placeholders={"index": placeholder},
)
self._domain = domain
self._unique_id_prefix = unique_id_prefix
self._attr_unique_id = f"{unique_id_prefix}-pipeline"
self._attr_unique_id = f"{unique_id_prefix}-{self.entity_description.key}"
self.hass = hass
self._update_options()
@@ -87,7 +109,7 @@ class AssistPipelineSelect(SelectEntity, restore_state.RestoreEntity):
)
state = await self.async_get_last_state()
if state is not None and state.state in self.options:
if (state is not None) and (state.state in self.options):
self._attr_current_option = state.state
if self.registry_entry and (device_id := self.registry_entry.device_id):
@@ -97,7 +119,7 @@ class AssistPipelineSelect(SelectEntity, restore_state.RestoreEntity):
def cleanup() -> None:
"""Clean up registered device."""
pipeline_data.pipeline_devices.pop(device_id)
pipeline_data.pipeline_devices.pop(device_id, None)
self.async_on_remove(cleanup)
@@ -7,7 +7,7 @@
},
"select": {
"pipeline": {
"name": "Assistant",
"name": "Assistant{index}",
"state": {
"preferred": "Preferred"
}
@@ -522,6 +522,7 @@ class AssistSatelliteEntity(entity.Entity):
pipeline_id=self._resolve_pipeline(),
conversation_id=session.conversation_id,
device_id=device_id,
satellite_id=self.entity_id,
tts_audio_output=self.tts_options,
wake_word_phrase=wake_word_phrase,
audio_settings=AudioSettings(
@@ -75,7 +75,6 @@ class BroadcastIntentHandler(intent.IntentHandler):
)
response = intent_obj.create_response()
response.response_type = intent.IntentResponseType.ACTION_DONE
response.async_set_results(
success_results=[
intent.IntentResponseTarget(
@@ -1,7 +1,7 @@
{
"domain": "assist_satellite",
"name": "Assist Satellite",
"codeowners": ["@home-assistant/core", "@synesthesiam"],
"codeowners": ["@home-assistant/core", "@synesthesiam", "@arturpragacz"],
"dependencies": ["assist_pipeline", "http", "stt", "tts"],
"documentation": "https://www.home-assistant.io/integrations/assist_satellite",
"integration_type": "entity",
@@ -120,10 +120,18 @@ class AsusWrtBridge(ABC):
def __init__(self, host: str) -> None:
"""Initialize Bridge."""
self._configuration_url = f"http://{host}"
self._host = host
self._firmware: str | None = None
self._label_mac: str | None = None
self._model: str | None = None
self._model_id: str | None = None
self._serial_number: str | None = None
@property
def configuration_url(self) -> str:
"""Return configuration URL."""
return self._configuration_url
@property
def host(self) -> str:
@@ -145,6 +153,16 @@ class AsusWrtBridge(ABC):
"""Return model information."""
return self._model
@property
def model_id(self) -> str | None:
"""Return model_id information."""
return self._model_id
@property
def serial_number(self) -> str | None:
"""Return serial number information."""
return self._serial_number
@property
@abstractmethod
def is_connected(self) -> bool:
@@ -359,8 +377,11 @@ class AsusWrtHttpBridge(AsusWrtBridge):
# get main router properties
if mac := _identity.mac:
self._label_mac = format_mac(mac)
self._configuration_url = self._api.webpanel
self._firmware = str(_identity.firmware)
self._model = _identity.model
self._model_id = _identity.product_id
self._serial_number = _identity.serial
async def async_disconnect(self) -> None:
"""Disconnect to the device."""
@@ -7,5 +7,5 @@
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["aioasuswrt", "asusrouter", "asyncssh"],
"requirements": ["aioasuswrt==1.4.0", "asusrouter==1.20.1"]
"requirements": ["aioasuswrt==1.4.0", "asusrouter==1.21.0"]
}
+3 -1
View File
@@ -388,11 +388,13 @@ class AsusWrtRouter:
def device_info(self) -> DeviceInfo:
"""Return the device information."""
info = DeviceInfo(
configuration_url=self._api.configuration_url,
identifiers={(DOMAIN, self._entry.unique_id or "AsusWRT")},
name=self.host,
model=self._api.model or "Asus Router",
model_id=self._api.model_id,
serial_number=self._api.serial_number,
manufacturer="Asus",
configuration_url=f"http://{self.host}",
)
if self._api.firmware:
info["sw_version"] = self._api.firmware
+13 -19
View File
@@ -2,13 +2,12 @@
from __future__ import annotations
from collections.abc import Callable, Coroutine
import logging
from typing import Any
from aiohttp import ClientResponseError
from yalexs.activity import ActivityType, ActivityTypes
from yalexs.lock import Lock, LockStatus
from yalexs.activity import ActivityType
from yalexs.lock import Lock, LockOperation, LockStatus
from yalexs.util import get_latest_activity, update_lock_detail_from_activity
from homeassistant.components.lock import ATTR_CHANGED_BY, LockEntity, LockEntityFeature
@@ -50,30 +49,25 @@ class AugustLock(AugustEntity, RestoreEntity, LockEntity):
async def async_lock(self, **kwargs: Any) -> None:
"""Lock the device."""
if self._data.push_updates_connected:
await self._data.async_lock_async(self._device_id, self._hyper_bridge)
return
await self._call_lock_operation(self._data.async_lock)
await self._perform_lock_operation(LockOperation.LOCK)
async def async_open(self, **kwargs: Any) -> None:
"""Open/unlatch the device."""
if self._data.push_updates_connected:
await self._data.async_unlatch_async(self._device_id, self._hyper_bridge)
return
await self._call_lock_operation(self._data.async_unlatch)
await self._perform_lock_operation(LockOperation.OPEN)
async def async_unlock(self, **kwargs: Any) -> None:
"""Unlock the device."""
if self._data.push_updates_connected:
await self._data.async_unlock_async(self._device_id, self._hyper_bridge)
return
await self._call_lock_operation(self._data.async_unlock)
await self._perform_lock_operation(LockOperation.UNLOCK)
async def _call_lock_operation(
self, lock_operation: Callable[[str], Coroutine[Any, Any, list[ActivityTypes]]]
) -> None:
async def _perform_lock_operation(self, operation: LockOperation) -> None:
"""Perform a lock operation."""
try:
activities = await lock_operation(self._device_id)
activities = await self._data.async_operate_lock(
self._device_id,
operation,
self._data.push_updates_connected,
self._hyper_bridge,
)
except ClientResponseError as err:
if err.status == LOCK_JAMMED_ERR:
self._detail.lock_status = LockStatus.JAMMED
@@ -29,5 +29,5 @@
"documentation": "https://www.home-assistant.io/integrations/august",
"iot_class": "cloud_push",
"loggers": ["pubnub", "yalexs"],
"requirements": ["yalexs==9.0.1", "yalexs-ble==3.1.2"]
"requirements": ["yalexs==9.2.0", "yalexs-ble==3.1.2"]
}
+15 -4
View File
@@ -92,7 +92,11 @@ from homeassistant.components.http.ban import (
from homeassistant.components.http.data_validator import RequestDataValidator
from homeassistant.components.http.view import HomeAssistantView
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.network import is_cloud_connection
from homeassistant.helpers.network import (
NoURLAvailableError,
get_url,
is_cloud_connection,
)
from homeassistant.util.network import is_local
from . import indieauth
@@ -125,11 +129,18 @@ class WellKnownOAuthInfoView(HomeAssistantView):
async def get(self, request: web.Request) -> web.Response:
"""Return the well known OAuth2 authorization info."""
hass = request.app[KEY_HASS]
# Some applications require absolute urls, so we prefer using the
# current requests url if possible, with fallback to a relative url.
try:
url_prefix = get_url(hass, require_current_request=True)
except NoURLAvailableError:
url_prefix = ""
return self.json(
{
"authorization_endpoint": "/auth/authorize",
"token_endpoint": "/auth/token",
"revocation_endpoint": "/auth/revoke",
"authorization_endpoint": f"{url_prefix}/auth/authorize",
"token_endpoint": f"{url_prefix}/auth/token",
"revocation_endpoint": f"{url_prefix}/auth/revoke",
"response_types_supported": ["code"],
"service_documentation": (
"https://developers.home-assistant.io/docs/auth_api"
+3 -2
View File
@@ -8,7 +8,7 @@ import threading
from typing import IO, cast
from aiohttp import BodyPartReader
from aiohttp.hdrs import CONTENT_DISPOSITION
from aiohttp.hdrs import CONTENT_DISPOSITION, CONTENT_TYPE
from aiohttp.web import FileResponse, Request, Response, StreamResponse
from multidict import istr
@@ -76,7 +76,8 @@ class DownloadBackupView(HomeAssistantView):
return Response(status=HTTPStatus.NOT_FOUND)
headers = {
CONTENT_DISPOSITION: f"attachment; filename={slugify(backup.name)}.tar"
CONTENT_DISPOSITION: f"attachment; filename={slugify(backup.name)}.tar",
CONTENT_TYPE: "application/x-tar",
}
try:
+3 -3
View File
@@ -14,15 +14,15 @@
},
"automatic_backup_failed_addons": {
"title": "Not all add-ons could be included in automatic backup",
"description": "Add-ons {failed_addons} could not be included in automatic backup. Please check the supervisor logs for more information. Another attempt will be made at the next scheduled time if a backup schedule is configured."
"description": "Add-ons {failed_addons} could not be included in automatic backup. Please check the Supervisor logs for more information. Another attempt will be made at the next scheduled time if a backup schedule is configured."
},
"automatic_backup_failed_agents_addons_folders": {
"title": "Automatic backup was created with errors",
"description": "The automatic backup was created with errors:\n* Locations which the backup could not be uploaded to: {failed_agents}\n* Add-ons which could not be backed up: {failed_addons}\n* Folders which could not be backed up: {failed_folders}\n\nPlease check the core and supervisor logs for more information. Another attempt will be made at the next scheduled time if a backup schedule is configured."
"description": "The automatic backup was created with errors:\n* Locations which the backup could not be uploaded to: {failed_agents}\n* Add-ons which could not be backed up: {failed_addons}\n* Folders which could not be backed up: {failed_folders}\n\nPlease check the Core and Supervisor logs for more information. Another attempt will be made at the next scheduled time if a backup schedule is configured."
},
"automatic_backup_failed_folders": {
"title": "Not all folders could be included in automatic backup",
"description": "Folders {failed_folders} could not be included in automatic backup. Please check the supervisor logs for more information. Another attempt will be made at the next scheduled time if a backup schedule is configured."
"description": "Folders {failed_folders} could not be included in automatic backup. Please check the Supervisor logs for more information. Another attempt will be made at the next scheduled time if a backup schedule is configured."
}
},
"services": {
@@ -497,16 +497,18 @@ class BayesianBinarySensor(BinarySensorEntity):
_LOGGER.debug(
(
"Observation for entity '%s' returned None, it will not be used"
" for Bayesian updating"
" for updating Bayesian sensor '%s'"
),
observation.entity_id,
self.entity_id,
)
continue
_LOGGER.debug(
(
"Observation for template entity returned None rather than a valid"
" boolean, it will not be used for Bayesian updating"
" boolean, it will not be used for updating Bayesian sensor '%s'"
),
self.entity_id,
)
# the prior has been updated and is now the posterior
return prior

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