Compare commits

...

630 Commits

Author SHA1 Message Date
Ludovic BOUÉ 45424e8557 Merge branch 'dev' into matter_cloure_fixture 2026-02-14 12:15:27 +01:00
Franck Nijhof 96b98c9cb9 Remove YAML anchors / expand GitHub CI workflows (#162987) 2026-02-14 12:01:29 +01:00
MoonDevLT 7d3601aa6f Replace the manufacturer name of lunatone (#162854) 2026-02-14 11:52:39 +01:00
Anders Ödlund 2ef7f6b317 Z-Wave lock service action modernization (#162967)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-14 10:33:23 +01:00
Matthias Alphart 7c8b181e6d Update knx-frontend to 2026.2.13.222258 (#162963) 2026-02-14 10:10:50 +01:00
Thomas Rupprecht b5147d8afa Improve SpaceAPI Manifest (#160805) 2026-02-14 09:55:55 +01:00
hanwg dc4bc6feea Set default file transfer timeouts for Telegram bot (#162978) 2026-02-14 09:36:25 +01:00
Thomas Rupprecht 4cea3b4aac Improve types and code in SpaceAPI (#162970) 2026-02-14 09:26:25 +01:00
Brett Adams d633a69e07 Bump python-tesla-fleet-api to v1.4.3 (#162977)
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-14 09:25:20 +01:00
AlCalzone 3e8e95f95e Handle Z-Wave values (re-)added at runtime (#162921) 2026-02-13 23:46:59 +01:00
Michael Hansen 6d66df9346 Bump intents to 2026.2.13 (#162959) 2026-02-13 23:29:55 +01:00
TheJulianJES ed15a01a6a Fix home-assistant-intents breaking nightly builds (#162957)
Co-authored-by: Robert Resch <robert@resch.dev>
2026-02-13 23:28:36 +01:00
Glenn de Haan 462d958b7e Bump hdfury to 1.5.0 (#162944) 2026-02-13 21:42:22 +01:00
Robin Lintermann d888579cbd Bump pysmarlaapi to 1.0.1 and compatibility changes (#162911) 2026-02-13 21:41:05 +01:00
Erik Montnemery e16a8ed20e Don't mock out filesystem operations in backup tests (#162877) 2026-02-13 21:39:34 +01:00
YogevBokobza b11a75d438 Add Switcher heater support (#162588)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
2026-02-13 22:32:55 +02:00
Glenn de Haan 95df5b9ec9 Fix incorrect type HDFury select platform (#162948) 2026-02-13 20:50:26 +01:00
epenet a301a9c4b6 Always include homeassistant translations in tests (#162850) 2026-02-13 20:17:48 +01:00
Thomas55555 e80bb871e4 Bump ruff to 0.15.1 (#162903) 2026-02-13 19:43:37 +01:00
epenet ff4ff98e54 Parametrize yeelight test_device_types test (#161838) 2026-02-13 19:43:07 +01:00
wollew 88c6cb3877 add OnOffLight without brightness control to velux integration (#162835) 2026-02-13 19:42:44 +01:00
Michael 6b3a7e4cd6 Fix handling when FRITZ!Box reboots in FRITZ!Smarthome (#162676) 2026-02-13 19:41:03 +01:00
Michael 36ff7506a0 Fix handling when FRITZ!Box reboots in FRITZ!Box Tools (#162679) 2026-02-13 19:40:51 +01:00
Allen Porter a0af35f2dc Improve MCP SSE fallback error handling (#162655) 2026-02-13 19:39:34 +01:00
Josef Zweck c15da19b84 Log remaining token duration in onedrive (#162933) 2026-02-13 19:38:44 +01:00
Damien Sorel 23e88a24f0 Add remove item intent for todo component (#152922) 2026-02-13 19:38:22 +01:00
Robert Resch 815c708d19 Block redirect to localhost (#162941) 2026-02-13 19:31:35 +01:00
Paulus Schoutsen f9f2f39a3c OpenAI: Increase max iterations for AI Task (#162599) 2026-02-13 13:16:26 -05:00
Erik Montnemery 490514c274 Add fixture to give tests their own unique copy of testing_config (#162938) 2026-02-13 18:07:18 +01:00
Kamil Breguła 7da339b59c Add quality scale for GIOS (#155603)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
2026-02-13 18:01:44 +01:00
Josef Zweck 1bb31892c2 Add integration for onedrive for business (#155709)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-13 07:01:52 -08:00
epenet 267caf2365 Use APPLICATION_CREDENTIALS_DOMAIN constant in tests (#162932) 2026-02-13 15:47:38 +01:00
Petro31 4e71a38e31 Ensure numeric template sensors only use numbers in _attr_native_state (#162878)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2026-02-13 14:14:28 +01:00
Petro31 d3d916566a Make template lock code error consistent between state based and trigger based template entities (#162923) 2026-02-13 14:13:58 +01:00
epenet fd3258a6d3 Use constants for update_entity calls in tests (#162920) 2026-02-13 13:54:40 +01:00
Sammy [Andrei Marinache] d1aadb5842 Add Miele TQ1000WP tumble dryer programs and program phases (#162871)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Åke Strandberg <ake@strandberg.eu>
2026-02-13 13:53:12 +01:00
epenet d984411911 Raise on missing supported color modes (#162717) 2026-02-13 13:39:48 +01:00
Robin Lintermann 8ed0a4cf29 Specifiy number of parallel updates in Smarla (#162914) 2026-02-13 13:24:24 +01:00
Simone Chemelli 9a407b8668 Optimize coordinator data type for UptimeRobot (#162912) 2026-02-13 13:23:59 +01:00
Robin Lintermann 72aa9d8a6a Improve smarla typing in tests (#162163) 2026-02-13 13:19:27 +01:00
Kevin Stillhammer dc1c52622e Fix google_travel_time get_travel_times config_entry_id description (#162910)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-13 13:18:55 +01:00
peteS-UK 44d5ecc926 Replace repeated patches in config_flow_test with fixtures for Squeezebox (#153032) 2026-02-13 12:00:24 +01:00
Simone Chemelli 54b0393ebe Cleanup code for UptimeRobot (#162905) 2026-02-13 11:53:04 +01:00
epenet 54141ffd3f Drop yardian custom translation overrides in tests (#162904) 2026-02-13 10:57:17 +01:00
David Bonnes 92b823068c Move evohome service registration to services.py (#162902) 2026-02-13 10:25:03 +01:00
Norbert Rittel d4a6377ab3 Fix capitalization of "Immich" and "MIME type" (#162900) 2026-02-13 10:00:39 +01:00
epenet 80d07c42ac Move evohome hasskey to const module (#162899) 2026-02-13 08:25:43 +00:00
puddly 077eeafa69 Bump ZHA to 0.0.90 (#162894) 2026-02-13 08:40:26 +01:00
dependabot[bot] b6ff8c94b1 Bump docker/build-push-action from 6.19.1 to 6.19.2 (#162896)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-13 08:39:53 +01:00
Michael 6a1581f2bf Immich reached platinum 🏆 (#162891) 2026-02-13 07:45:56 +01:00
johanzander 2dc0d32a29 Implement automatic migration for Growatt Server DEFAULT_PLANT_ID entries (#159972) 2026-02-13 01:56:50 +01:00
Niracler 036696f4cd Add energy sensor platform to sunricher_dali (#161415)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-13 01:55:16 +01:00
Michael 89f5b33a5e Cache get api calls in FRITZ!Box tools (#160246)
Co-authored-by: Simone Chemelli <simone.chemelli@gmail.com>
2026-02-13 01:54:33 +01:00
Matthias Alphart fc52885c21 Support KNX time server configuration from UI (#161854) 2026-02-13 01:52:38 +01:00
Ville Skyttä ffa8fc583d Recorder total_increasing warning clarifications (#157453) 2026-02-13 01:47:51 +01:00
Samuel Xiao f18fa07019 Switchbot Cloud: Add new supported device Ai Art Frame (#160754)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-13 01:47:03 +01:00
Alex Merkel ce704dd5f7 Add play/pause ability & media info to LG soundbars integration (#161184)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-13 01:39:05 +01:00
Patrick Vorgers d930755f92 IDrive e2 backup provider (#144910)
Co-authored-by: Josef Zweck <josef@zweck.dev>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-12 15:49:03 -08:00
epenet 196c6d9839 Do not unregister adguard services (#158308)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-13 00:40:30 +01:00
David Rapan cce5358901 Re-implement Cloudflare using coordinator (#156817)
Signed-off-by: David Rapan <david@rapan.cz>
2026-02-13 00:33:48 +01:00
Heindrich Paul df7c3d787d Only show trains for configured time if configured in nederlandse_spoorwegen (#159261) 2026-02-13 00:29:20 +01:00
Manu a6287731f7 Increase test coverage in Xbox integration (#162876) 2026-02-12 15:14:07 -08:00
karwosts 1667b3f16b Add annual statistics aggregation (#160857) 2026-02-13 00:11:07 +01:00
Noah Husby 2aa9d22350 Add room correction setting to Cambridge Audio (#162743)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2026-02-12 23:10:13 +00:00
Matthias Alphart 3bcb303ef1 Support KNX number entity configuration from UI (#161269) 2026-02-13 00:06:53 +01:00
Manu e6de37cc69 Use service helper to retrieve config entry in Duck DNS integration (#162879) 2026-02-12 23:00:23 +00:00
Jon d10f5cc9ea Expose power and energy sensors for vera metered switches (#161028) 2026-02-12 23:56:35 +01:00
Erwin Douna 4921f05189 Disable mobile devices in tado (#160881)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-12 23:56:01 +01:00
Brett Adams 877ad391f0 Add config flow to Splunk (#160478)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Erwin Douna <e.douna@gmail.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 23:27:49 +01:00
n-6 8a5594b9e4 Added Ambient Weather station sensors for AQIN monitor. (#161082)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 23:27:25 +01:00
Josef Zweck a0623d1f97 Add IQS to openai_conversation (#161051)
Co-authored-by: Robert Resch <robert@resch.dev>
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
Co-authored-by: Matthias Alphart <farmio@alphart.net>
Co-authored-by: Erwin Douna <e.douna@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 23:26:27 +01:00
Michael c8f8ef887a Add reconfigure flow to immich (#162892) 2026-02-12 23:25:51 +01:00
Eduardo Tsen 40ec6d3793 Add switch controls for dishwashers in SmartThings (#160266)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-12 22:57:54 +01:00
Matthias Alphart 0a79d84f9a KNX Expose: Add support for sending value periodically (#160883) 2026-02-12 22:51:40 +01:00
Przemko92 7a7e60ce75 Add number to Compit (#162165)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-12 22:49:34 +01:00
Kurt Chrisford 6bfaf6b188 Add action exception handling to Actron Air (#160579)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 22:46:53 +01:00
Kinachi249 34a445545c Cync - allow updating multiple attributes in one command (#159574)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-12 22:46:30 +01:00
epenet 3c854a7679 Improve type hints in utility_meter (#160993) 2026-02-12 22:46:13 +01:00
Florent Fourcot b7b6c1a72e Add more Melcloud sensors (#160770)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-12 22:39:21 +01:00
Michael fdf02cf657 Add missing exception translations in immich (#162889) 2026-02-12 22:32:22 +01:00
Kevin Stillhammer acf739df81 add services to google_travel_time (#160740)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-12 22:31:36 +01:00
Tom Matheussen 4801dcaded Add parent device for Satel Integra (#160933)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 22:29:59 +01:00
Daniel Hjelseth Høyer 11af0a2d04 Add reauthentication flow to Homevolt (#162868)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2026-02-12 22:27:30 +01:00
Michel Nederlof 40b30b94a2 Adjust discovery interval in govee-light-local (#160914)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 21:56:23 +01:00
Daniel Hjelseth Høyer 902d3f45a2 Add diagnostics to Homevolt (#162873)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2026-02-12 21:56:12 +01:00
ryanjones-gentex bf887fbc71 Add reauth flow to HomeLink integration (#158454)
Co-authored-by: Nicholas Aelick <niaexa@syntronic.com>
2026-02-12 21:51:26 +01:00
Michael e5ede7deea Categorize all immich sensor entities as diagnostic (#162887) 2026-02-12 21:36:45 +01:00
Erwin Douna 8b674a44a1 Melcloud move ConfigEntry declaration (#160890)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 21:32:54 +01:00
Joost Lekkerkerker e145963d48 Remove unused snapshots for Homevolt (#162885) 2026-02-12 21:32:41 +01:00
Simone Chemelli 1bca0ba5f8 Update UptimeRobot to API v3 (#153508) 2026-02-12 21:28:11 +01:00
Anders Ödlund 38531033a1 Catch AccessoryDisconnectedError in homekit pairing (#162466)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:51:09 +01:00
Xitee 9f1b6a12a5 Filter out transient zero values from qBittorrent alltime stats (#162821)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:45:42 +01:00
Daniel Hjelseth Høyer 876589f0cd Fix keys for Homevolt (#162874)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2026-02-12 18:42:50 +01:00
Przemko92 bd09ac9030 Add water heater support for Compit (#162021)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-12 18:39:02 +01:00
wollew 6d143c1ce2 add quality scale to manifest of velux integration (#162869) 2026-02-12 18:38:49 +01:00
Artur Pragacz f4ceb22d73 Add analytics platform to mobile_app (#162736) 2026-02-12 17:09:40 +01:00
Manu 5839191c37 Move entity service registration to async_setup in ntfy integration (#162833) 2026-02-12 16:42:15 +01:00
Manu 29feccb190 Improve tests in Bring! integration (#162853)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-02-12 16:41:08 +01:00
epenet a017417849 Use service helper to extract habitica config entry (#162795)
Co-authored-by: Manu <4445816+tr4nt0r@users.noreply.github.com>
2026-02-12 16:39:03 +01:00
Ludovic BOUÉ b22c48a07e Merge branch 'dev' into matter_cloure_fixture 2026-02-12 16:06:43 +01:00
Aron List 72a7d708b0 Expose ActuatorEnabled attr of matter DoorLock (#162598) 2026-02-12 16:03:30 +01:00
epenet 47be13e6bf Improve error validation in service tests (#162851) 2026-02-12 06:34:31 -08:00
ElCruncharino 7d583be8e1 Add timeout to B2 metadata downloads to prevent backup hang (#162562) 2026-02-12 06:26:50 -08:00
Manu ccb3b35694 Use https for media player cover images in Xbox integration (#162859) 2026-02-12 05:59:28 -08:00
Steve Easley 48893d4daa Add JVC Projector switch platform (#161899)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-12 14:21:34 +01:00
Yoshi Walsh 0388e5dd7f Bump pydaikin to 2.17.2 (#162846) 2026-02-12 14:18:46 +01:00
Marc Hörsken 7a68903318 Bump pywmspro to 0.3.3 (#162832) 2026-02-12 14:18:19 +01:00
Anders Ödlund 64766100fe Add get_lock_usercode service to zwave_js integration (#162057)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 13:44:33 +01:00
Abílio Costa 0576dd91b7 Validate core_files.yaml base_platforms completeness (#162826) 2026-02-12 11:59:19 +00:00
Jon Seager f4440e992f Bump pytouchlinesl to 0.6.0 (#162856) 2026-02-12 12:42:36 +01:00
Daniel Hjelseth Høyer ea83b5a892 Add Homevolt battery integration (#160416)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 12:39:58 +01:00
Vicx d148952c99 Bump slixmpp to 1.13.2 (#162837) 2026-02-12 11:48:48 +01:00
epenet ed9a810908 Fix unavailable status in Tuya (#162709) 2026-02-12 11:46:40 +01:00
Peter Kolbus 6960cd6853 Bump pyweatherflowudp to 1.5.0 (#162841)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-02-12 11:43:01 +01:00
dependabot[bot] 5bd86ba600 Bump docker/build-push-action from 6.18.0 to 6.19.1 (#162844)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-12 10:05:36 +01:00
LG-ThinQ-Integration 70bc49479d Add vacuum's activity table to LG ThinQ (#162616)
Co-authored-by: yunseon.park <yunseon.park@lge.com>
2026-02-12 10:02:29 +01:00
wh1t3f1r3 81e0c105d6 Fix Venstar integration crash when thermostat is unreachable (#162524) 2026-02-12 09:54:11 +01:00
Peter Kolbus 527e2aec1f Improve weatherflow type hints (#162843) 2026-02-12 09:07:30 +01:00
epenet cd6661260c Use service helper to extract bring config entry (#162790) 2026-02-12 00:05:18 -05:00
epenet efa522cc73 Use service helper to extract bosch alarm config entry (#162789) 2026-02-12 00:04:50 -05:00
Artur Pragacz f9bd1b3d30 Rename registry imports in intent helper (#162765)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 00:04:29 -05:00
staticdev 4cfdb14714 Fix devcontainer defaultFormatter blocks (#162750) 2026-02-12 00:02:27 -05:00
epenet 6fb802e6b9 Use service helper to extract transmission config entry (#162814) 2026-02-11 23:58:35 -05:00
Christian Lackas 9b30fecb0c Fix absolute humidity sensor on HmIP-WGT glass thermostats (#162455) 2026-02-11 23:42:37 +01:00
Roman Lytvyn e77acc1002 Add WATER_LEVEL sensor to homekit_controller (#161900) 2026-02-11 23:38:46 +01:00
cdnninja 07e8b780a2 Add DHCP Discovery to vesync (#162259)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-11 23:27:35 +01:00
Denis Shulyaka e060395786 Anthropic Structured Outputs support (#162515) 2026-02-11 23:25:46 +01:00
Denis Shulyaka 661b14dec5 Deprecate OpenAI actions (#162211) 2026-02-11 23:17:15 +01:00
Christian Lackas b8e63b7ef6 Use direct DHW status for ViCare water heater state (#162591) 2026-02-11 23:07:56 +01:00
Abílio Costa fd78e35a86 Align number unit converters with sensor (#162662) 2026-02-11 23:07:04 +01:00
Mick Vleeshouwer db55dfe3c7 Improve device information in Overkiz (#162419) 2026-02-11 22:39:34 +01:00
Joost Lekkerkerker bda3121f98 Add snapshot tests to waterfurnace sensors (#162594) 2026-02-11 22:28:41 +01:00
dontinelli fd4981f3e2 Split up coordinators in solarlog (#161169)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-11 22:23:32 +01:00
Manu ae1bedd94a Add uptime ratio and avg. response time sensors to Uptime Kuma (#162785) 2026-02-11 22:09:21 +01:00
hanwg 90b67f90fa Handle config entry not loaded for Telegram bot (#161951)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-11 22:05:21 +01:00
cdnninja 9c821fb5f5 Mark log unavailable as complete for vesync (#162464) 2026-02-11 22:03:12 +01:00
Graham Crockford 1f9691ace1 Add charge state to Victron BLE (#162593)
Co-authored-by: Graham Crockford <badgerwithagun@users.noreply.github.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-11 21:59:56 +01:00
Paulus Schoutsen 5331cd99c6 Google Gen AI: Increase max iterations for AI Task (#162600)
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 21:55:37 +01:00
Denis Shulyaka 1c3f24c78f Add TTS support for OpenAI (#162468)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-11 21:37:49 +01:00
Kamil Breguła e179e74df3 Support dual cook oven in Smartthing (#156561)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:27:40 +01:00
wollew 98602bd311 Bump pyvlx to 0.2.29 (#162829) 2026-02-11 21:10:44 +01:00
Jeef 5f01124c74 Bump typedmonarchmoney to 0.7.0 (#162686) 2026-02-11 19:44:08 +00:00
Brett Adams 4b5368be8e Complete config-entry-unloading quality check in Teslemetry (#161956)
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 20:31:30 +01:00
Brett Adams 6379014f13 Use chained comparison in Teslemetry update platform (#161950)
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 20:07:04 +01:00
Joost Lekkerkerker aa640020be Bump pySmartThings to 3.5.2 (#162809)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2026-02-11 20:02:28 +01:00
Simone Chemelli 92f4e600d1 Fix alarm refresh warning for Comelit SimpleHome (#162710) 2026-02-11 19:36:57 +01:00
Andreas Jakl 25a6b6fa65 Add switch platform to nrgkick integration for enabling or pausing car charging (#162563)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-11 19:36:36 +01:00
Manu 3cbe1295f9 Bump pythonkuma to 0.4.1 (#162773) 2026-02-11 19:35:12 +01:00
Erwin Douna 72581fb2b1 Add endpoint system df information (#160134) 2026-02-11 19:28:49 +01:00
Erwin Douna 97c89590e0 Portainer fix multiple environments & containers (#153674) 2026-02-11 19:21:36 +01:00
epenet b6ba86f3c1 Use service helper to extract onedrive config entry (#162803) 2026-02-11 10:16:55 -08:00
epenet cedc291872 Use service helper to extract tado config entry (#162812) 2026-02-11 10:15:38 -08:00
epenet 1d30486f82 Use service helper to extract velbus config entry (#162813) 2026-02-11 10:15:19 -08:00
Christopher Fenner 9f1b4c9035 Improve EnOcean config flow (#162751) 2026-02-11 19:14:45 +01:00
Christian Lackas 80ebb34ad1 Add smoke detector extended properties to homematicip_cloud (#161629)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-11 18:56:39 +01:00
hanwg e0e11fd99d Fix bug in edit_message_media action for Telegram bot (#162762) 2026-02-11 17:55:14 +01:00
Artur Pragacz 578a933f30 Move entity name helper to module-level function (#162766) 2026-02-11 17:54:53 +01:00
Christian Lackas 57493a1f69 Add ELV-SH-SB8 Status Board switch support to homematicip_cloud (#161668) 2026-02-11 17:43:51 +01:00
Simone Chemelli 3a4100fa94 Fix image platform state for Vodafone Station (#162747)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-11 17:39:51 +01:00
theobld-ww 0c1af1d613 Add switch entities to Watts Vision + (#162699)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-11 17:39:17 +01:00
starkillerOG 4e46431798 Add additional Reolink PTZ buttons (#162793) 2026-02-11 17:29:24 +01:00
starkillerOG bec66f49a2 Add Reolink PTZ patrol status (#162796) 2026-02-11 17:29:05 +01:00
epenet 4019768fa1 Use service helper to extract easyenergy config entry (#162791) 2026-02-11 17:24:57 +01:00
epenet 25d902fd3e Use service helper to extract google_photos config entry (#162792) 2026-02-11 17:24:44 +01:00
epenet 30f006538d Use service helper to extract google_sheets config entry (#162794) 2026-02-11 17:24:26 +01:00
epenet 15b1fee42d Use service helper to extract mastodon config entry (#162798) 2026-02-11 17:24:05 +01:00
epenet d69b816459 Use service helper to extract mealie config entry (#162800) 2026-02-11 17:19:03 +01:00
epenet bf79721e97 Use service helper to extract ohme config entry (#162801) 2026-02-11 17:18:25 +01:00
torben-iometer 66a0b44284 Fix missing values in battery_level in iometer (#162781) 2026-02-11 17:17:55 +01:00
Andy 8693294ea6 Add support for Nanoleaf Essentials / Replace aionanoleaf through aionanoleaf2 (#157295)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-11 17:06:40 +01:00
epenet 14ac7927f1 Use service helper to extract seventeentrack config entry (#162807) 2026-02-11 16:08:40 +01:00
Willem-Jan van Rootselaar b4674473d7 Fix BSBLAN water heater mapping and add on/off (#160256) 2026-02-11 16:06:26 +01:00
epenet f01ece1d3d Move TadoConfigEntry declaration (#162811) 2026-02-11 16:01:31 +01:00
epenet 08160a41a6 Use service helper to extract swiss public transport config entry (#162810) 2026-02-11 15:59:50 +01:00
epenet e617698770 Use service helper to extract stookwijzer config entry (#162808) 2026-02-11 15:59:36 +01:00
epenet ee31bdf18b Use service helper to extract radarr config entry (#162805) 2026-02-11 15:41:02 +01:00
epenet 305b911c0d Use service helper to extract overseerr config entry (#162804) 2026-02-11 15:36:34 +01:00
epenet 842abf78d2 Use service helper to extract risco config entry (#162806) 2026-02-11 15:35:27 +01:00
Willem-Jan van Rootselaar 134e8d1c1b Bump python-bsblan to version 4.2.0 (#162786) 2026-02-11 15:31:06 +01:00
epenet 733e90f747 Use service helper to extract immich config entry (#162797) 2026-02-11 15:02:32 +01:00
Artur Pragacz 6c92f7a864 Add integration type to mobile_app (#157719) 2026-02-11 14:48:10 +01:00
epenet f69b5b6e8f Use service helper to extract amberelectric config entry (#162788) 2026-02-11 13:49:29 +01:00
Willem-Jan van Rootselaar 59e53ee7b7 Add HVAC action support for BSBLAN climate entity (#156828)
Co-authored-by: Erwin Douna <e.douna@gmail.com>
2026-02-11 13:27:18 +01:00
epenet 62e1b0118c Add service helper to get config entry (#162068) 2026-02-11 13:20:37 +01:00
Guido Schmitz b7e9066b9d Add quality scale for devolo Home Control (#147483) 2026-02-11 12:17:02 +01:00
Erik Montnemery 2d6532b8ee Fix deadlock in ReloadServiceHelper (#162775) 2026-02-11 12:14:23 +01:00
Kamil Breguła ebd1f1b00f Add pagination support for AWS S3 (#162578)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-11 11:27:33 +01:00
jameson_uk 95a1ceb080 feat: add info skills to alexa devices (#162097) 2026-02-11 11:23:07 +01:00
dvdinth 3f9e7d1dba Add IntelliClima integration and tests (#157363)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-11 11:18:26 +01:00
epenet eab80f78d9 Raise on missing color mode (#162715) 2026-02-11 11:12:52 +01:00
Robert Resch aa9fdd56ec Bump cryptography to 46.0.5 (#162783) 2026-02-11 11:09:54 +01:00
epenet c727261f67 Move matter fixture list to a constant (#162776) 2026-02-11 10:47:09 +01:00
jameson_uk 703c62aa74 Bump aioamazondevices to 12.0.0 (#162778) 2026-02-11 10:21:11 +01:00
Tomás Correia 6e1f90228b fix to cloudflare r2 setup screen info (#162677) 2026-02-10 23:43:59 +01:00
LeoXie 3be089d2a5 Add Matter CO alarm state (#162627)
Co-authored-by: Ludovic BOUÉ <lboue@users.noreply.github.com>
2026-02-10 23:43:32 +01:00
Noah Husby 692d3d35cc Bump aiostreammagic to 2.12.1 (#162744) 2026-02-10 23:26:20 +01:00
starkillerOG c52cb8362e Bump reolink-aio to 0.19.0 (#162672) 2026-02-10 23:24:55 +01:00
Boaz Cahlon 93ac215ab4 Add integration for Hegel Music Systems amplifiers (#153867)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-10 22:56:48 +01:00
Michael f9eb86b50a Improve recognizability of Wi-Fi qr code in FRITZ!Box Tools (#162752) 2026-02-10 21:55:20 +00:00
Christian Lackas a7f9992a4e Bump homematicip to 2.6.0 (#162702)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2026-02-10 21:52:09 +00:00
Andreas Jakl 13fde0d135 Bump nrgkick-api to 1.7.1 (#162738) 2026-02-10 19:26:51 +01:00
tronikos 5105c6c50f Add last_changed and last_updated for the Opower statistics (#159101) 2026-02-10 17:08:58 +00:00
Josef Zweck af152ebe50 Bump onedrive-personal-sdk to 0.1.2 (#162689) 2026-02-10 08:52:29 -08:00
Manu dea4452e42 Set device entry type and integration type to service in Portainer integration (#162732) 2026-02-10 08:51:03 -08:00
Maikel Punie af07631d83 migrate velbus config entries (#162565) 2026-02-10 16:14:00 +01:00
theobld-ww d2ca00ca53 Refactor Watts Vision+ to generic device, in preparation for switch support (#162721)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-10 16:08:30 +01:00
Jeef bb2f7bdfc4 Bump intellifire4py to 4.3.1 (#162659) 2026-02-10 14:21:58 +00:00
epenet b1379d9153 Fix flaky lunatone test (#162727) 2026-02-10 15:18:59 +01:00
Anrijs ea4b286659 Bump aranet lib version to 2.6.0 (#162656)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
2026-02-10 16:03:16 +02:00
Norbert Rittel 2d00cb9a29 Improve descriptions of xiaomi_miio.vacuum_clean_segment action (#162698) 2026-02-10 05:47:46 -08:00
Christian Lackas 2ef1a20ae4 Add @lackas as code owner for homematicip_cloud (#162696) 2026-02-10 05:47:11 -08:00
Joost Lekkerkerker 95defddfff Add edenhaus as devcontainer codeowner (#162707) 2026-02-10 05:46:41 -08:00
J. Nick Koston 009bdd91cc Bump aioesphomeapi to 44.0.0 (#162712) 2026-02-10 14:21:56 +01:00
Manu 63bbead41e Add support for attachments from media sources in ntfy notifications (#152329)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-10 13:47:16 +01:00
MoonDevLT 2c9a96b62a Add config entry diagnostics to lunatone (#162406)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-10 13:18:23 +01:00
Brett Adams ace7fad62a Add exception translations to Teslemetry (#162141)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-10 12:22:59 +01:00
Brett Adams 3c73cc8bad Use icon translations for Teslemetry battery percent entities (#162140)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 12:15:30 +01:00
Petro31 83c41c265d Update template update to new template entity framework (#162561) 2026-02-10 11:39:29 +01:00
epenet c8bc5618dc Raise error when light reports invalid supported color modes (#162644) 2026-02-10 11:30:14 +01:00
Brandon Rothweiler 60d770f265 Bump py-aosmith to 1.0.17 (#162685) 2026-02-10 11:17:19 +01:00
joel-bourquard 6f4b9dcad7 Miele: Added support for Plate #5 on Miele KM 7699 (#162503) 2026-02-10 09:34:24 +01:00
ElCruncharino 1bba31f7af Fix AsyncIteratorReader blocking after stream exhaustion (#161731) 2026-02-10 09:21:52 +01:00
Ludovic BOUÉ 4705e584b0 Sort Matter fixture files list (#162693) 2026-02-10 07:41:50 +01:00
Ludovic BOUÉ 80bbe5df6a Add smoke detector test to Matter binary sensor tests (#162638) 2026-02-09 10:36:34 -08:00
Artur Pragacz 88c4d88e06 Simplify subscribe feature websocket in labs (#162646) 2026-02-09 17:05:43 +01:00
dependabot[bot] 718f459026 Bump actions/ai-inference from 2.0.5 to 2.0.6 (#162609)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-09 16:58:05 +01:00
XHyperDEVX 5c3ddcff3e Make “Reasoning Summary” configurable in OpenAI (#157557)
Co-authored-by: cto-new[bot] <140088366+cto-new[bot]@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-09 16:29:27 +01:00
Ludovic BOUÉ 08acececb2 Add local temperature calibration for all Matter thermostats (#161724)
Co-authored-by: TheJulianJES <TheJulianJES@users.noreply.github.com>
2026-02-09 16:09:25 +01:00
epenet 27d6ae2881 Adjust openrgb default color mode handling (#162650) 2026-02-09 16:00:44 +01:00
Brett Adams 5c4d9f4ca4 Fix Tesla Fleet partner registration to use all regions (#162525)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 15:33:05 +01:00
MarkGodwin 9ece327881 Limit actions on omada controller to one at a time (#162499) 2026-02-09 14:42:37 +01:00
cdnninja 1b0ef3f358 Add drying mode switch to vesync (#161905)
Co-authored-by: Dave T <17680170+davet2001@users.noreply.github.com>
2026-02-09 14:30:25 +01:00
Petro31 a5eca0614a Update template weather platform to new template entity framework (#162569) 2026-02-09 14:26:19 +01:00
Aaron Godfrey 7b2509fadb Increase max tasks retrieved per page to prevent timeout (#162587) 2026-02-09 14:19:40 +01:00
epenet f6e0bc28f4 Raise error when light reports an invalid color_mode (#162620) 2026-02-09 14:18:37 +01:00
Petro31 e87056408e Update template light to new entity framework (#162445) 2026-02-09 14:14:58 +01:00
Petro31 c945f32989 Update template fan platform to the new entity framework (#162328) 2026-02-09 14:13:23 +01:00
Ludovic BOUÉ 8d37917d8b Rename Matter Heiman smoke detector fixture file (#162632) 2026-02-09 14:05:13 +01:00
Artur Pragacz 68cc2dff53 Add subscribe preview feature helper to labs (#161778) 2026-02-09 14:03:02 +01:00
Andrea Turri 45babbca92 Add new Miele mappings (#162544) 2026-02-09 13:53:47 +01:00
Nick Beeuwsaert b56dcfb7e9 Add sensor state class to eufylife_ble (#162607) 2026-02-09 13:49:58 +01:00
Leonardo Merza a56114d84a Add slow mode option for SwitchBot curtains (#155272)
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-09 13:30:14 +01:00
Allen Porter de8a26c5b0 Bump grpc to 1.78.0 (#162520) 2026-02-09 13:20:55 +01:00
epenet 48f39524c4 Fix matter light color_mode (#162637) 2026-02-09 13:20:37 +01:00
Aidan Timson 2b4ef312c3 Add translation for MFA code (#162635) 2026-02-09 13:16:18 +01:00
epenet b4d175b811 Adjust esphome light test (#162633) 2026-02-09 12:48:14 +01:00
epenet 7ff6c2a421 Add missing features in tplink light tests (#162631) 2026-02-09 12:47:56 +01:00
dependabot[bot] cf0a438f32 Bump j178/prek-action from 1.1.0 to 1.1.1 (#162610)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-09 11:02:04 +01:00
epenet 9e1bfa3564 Cleanup mired light test (#162622) 2026-02-09 09:55:58 +01:00
Petro31 3c266183e1 Add new template entity framework to event platform (#162228) 2026-02-09 07:54:40 +01:00
epenet 5c5f5d064a Remove legacy fallback in light color_mode property (#162276) 2026-02-09 07:54:07 +01:00
Michael fc18ec4588 Bump aioimmich to 0.12.0 (#162573)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-08 23:51:24 +01:00
Thomas55555 3fd2fa27e7 Bump aioautomower to 2.7.3 (#162583)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-08 23:49:36 +01:00
Andres Ruiz cf637f8c2f Update waterfurnace integration to use Coordinator, instead of its own thread. (#161494)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-08 23:39:23 +01:00
Joost Lekkerkerker 228fca9f0c Pin setuptools to 81.0.0 (#162589)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-08 23:10:25 +01:00
tan-lawrence c5ce8998e2 Deprecate unknown fan mode in coolmaster (#161737)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-08 23:05:14 +01:00
Petro31 a4204bf11e Update template lock platform to new template entity framework (#162493) 2026-02-08 23:03:55 +01:00
mettolen 3e44d15fc1 Add diagnostics to Liebherr integration (#162360)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-02-08 22:52:56 +01:00
Norbert Rittel 4f07d8688c Sentence-case "speech-to-text" in google_cloud (#162534) 2026-02-08 22:50:12 +01:00
Petro31 89fda1a4ae update template number platform to new template entity framework (#162540) 2026-02-08 22:42:11 +01:00
Andres Ruiz f678e7ef34 Add additional sensors for waterfurnace integration (#162581) 2026-02-08 22:38:21 +01:00
Petro31 24e8208deb Update template select platform to new template entity framework (#162543) 2026-02-08 22:27:49 +01:00
Petro31 3c66a1b35d Update template vacuum platform to new template entity framework (#162564) 2026-02-08 22:27:21 +01:00
Petro31 5a2299e8b6 Update template switch platform to new template entity framework (#162556) 2026-02-08 22:25:38 +01:00
Noah Husby 8087953b90 Bump aiostreammagic to 2.12.0 (#162570) 2026-02-08 21:53:29 +01:00
Thomas55555 77a15b44c9 Increase polling in Husqvarna Automower (#162582) 2026-02-08 21:50:42 +01:00
hanwg 2177b494b9 Fix config flow bug for Telegram bot (#162555) 2026-02-08 21:32:51 +01:00
Peter Grauvogel 10497c2bf4 Fix Green Planet Energy price unit conversion (#162511) 2026-02-08 21:07:32 +01:00
Petro31 e7fd744941 Update template sensor platform to new template entity framework (#162554) 2026-02-08 21:01:31 +01:00
Elias Wernicke b9bfbc9e98 Validate conversation_command in start timer intent (#149915)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com>
2026-02-08 19:56:07 +01:00
Robert Svensson ba6f1343cc Add regression testing to Axis OUI support list (#162508) 2026-02-08 19:19:09 +01:00
Jaap Pieroen 0d07d4bc69 Bump essent-dynamic-pricing to 0.3.1 (#160958)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-02-08 10:03:20 +01:00
Norbert Rittel 94931a21fb Sentence-case "text-to-speech" and "speech-to-text" in elevenlabs (#162533) 2026-02-08 09:16:27 +01:00
Norbert Rittel ce295605ad Sentence-case "text-to-speech" and "speech-to-text" (#162532) 2026-02-08 09:11:58 +01:00
Denis Shulyaka 9e371fd083 Use hass httpx client for Anthropic (#162518) 2026-02-08 06:51:11 +01:00
Denis Shulyaka 9fa5a843cb Fix JSON serialization of datetime objects in Google Generative AI tool results (#162495) 2026-02-07 22:13:57 +01:00
Denis Shulyaka 8b5fb407e5 Fix JSON serialization of time objects in Open Router tool results (#162505) 2026-02-07 22:11:18 +01:00
Denis Shulyaka 8ef1e25f8c Fix JSON serialization of time objects in Ollama tool results (#162502)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-07 21:15:13 +01:00
Denis Shulyaka ce3dd2b6db Fix JSON serialization of time objects in OpenAI tool results (#162490) 2026-02-07 21:13:38 +01:00
Denis Shulyaka a98010d0c1 Fix JSON serialization of time objects in Cloud conversation tool results (#162506) 2026-02-07 21:08:39 +01:00
Shay Levy a915a69886 Add coverage for Shelly init (#162497) 2026-02-07 19:46:28 +02:00
cdnninja bb4ffd8c6e Add vesync Data Types (#162461) 2026-02-07 15:54:07 +00:00
epenet 403710354b Use shorthand attributes in tasmota lights (#162290) 2026-02-07 11:59:37 +01:00
Markus 9b3743a8bc Update snapcast to 2.3.7 (#162452) 2026-02-07 09:42:17 +01:00
rrooggiieerr 9642ff63ca Remove duplicate call of format_mac() (#162469) 2026-02-07 09:17:45 +01:00
Brett Adams 5a1862431e Fix device_class of backup reserve sensor in teslemetry (#162458) 2026-02-07 08:26:12 +01:00
Brett Adams efed2b75a5 Fix device_class of backup reserve sensor in Tessie (#162459) 2026-02-07 08:25:48 +01:00
epenet 5a87a8805e Add hassfest check for action-setup IQS (#162084)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-06 22:26:18 +01:00
Jonathan 8c48084b3f Fix device_class of backup reserve sensor (#161178) 2026-02-06 21:36:53 +01:00
arstom 60fd442ed7 Add ebusd sensors for Vaillant 700 (#161180)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2026-02-06 21:30:33 +01:00
epenet 1d6c5a283e Fix redundant off preset in Tuya climate (#161040) 2026-02-06 20:58:22 +01:00
Thomas55555 a53f876e09 Bump ruff to 0.15.0 (#162356)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-02-06 19:39:32 +01:00
jameson_uk 88d894212b dep: bump aioamazondevices to 11.1.3 (#162437) 2026-02-06 19:37:34 +01:00
Artur Pragacz f2d4319366 Make bad entity ID detection more lenient (#162425) 2026-02-06 15:58:27 +01:00
epenet 3eb8d64381 Fix invalid yardian snaphots (#162422) 2026-02-06 15:52:58 +01:00
epenet 818ce549d9 Remove duplicate class field in incomfort (#162420) 2026-02-06 15:16:20 +01:00
epenet db7800d170 Simplify (in-)equality checks (#162416) 2026-02-06 15:11:22 +01:00
epenet bc1c24efb1 Improve (r)split performance (#162418) 2026-02-06 15:10:30 +01:00
David Recordon 5ad632c34a Add Fan mode support to Control4 integration (#159980) 2026-02-06 14:11:18 +01:00
Sab44 65f95e5c4b Bump librehardwaremonitor-api to version 1.9.1 (#162409) 2026-02-06 14:04:21 +01:00
Joost Lekkerkerker bb406594d1 Remove double unit of measurement for yardian (#162412) 2026-02-06 14:03:57 +01:00
epenet b7a7b7bc63 Cleanup unnecessary brackets for except statements (a-h) (#162404) 2026-02-06 13:48:56 +01:00
epenet 1c59d846e3 Cleanup unnecessary brackets for except statements (core) (#162410) 2026-02-06 13:45:59 +01:00
Joost Lekkerkerker 3b40bb7d28 Remove entity id overwrite for ambient station (#162403) 2026-02-06 13:39:51 +01:00
epenet a171e17097 Cleanup unnecessary brackets for except statements (q-z) (#162408) 2026-02-06 13:31:56 +01:00
epenet c881d96d2f Cleanup unnecessary brackets for except statements (i-p) (#162405) 2026-02-06 13:23:25 +01:00
Luo Chen f1a99a2d65 Fix unicode escaping in MCP server tool response (#162319)
Co-authored-by: Franck Nijhof <git@frenck.dev>
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-02-06 13:11:28 +01:00
mettolen d02adabe5d Add Start session action to Saunum integration (#162177) 2026-02-06 12:47:50 +01:00
Mark Jansen 286730165d Simplify sun condition schema by re-using an existing type (#161894)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2026-02-06 12:27:16 +01:00
epenet 95a58252cf Reformat lambda (tests) (#162383) 2026-02-06 12:24:58 +01:00
epenet bf6643643b Reformat lambda (core) (#162382) 2026-02-06 12:24:48 +01:00
epenet 8d780d6712 Reformat lambda (t-z) (#162381) 2026-02-06 12:24:37 +01:00
epenet 576c7227c6 Reformat lambda (m-s) (#162379) 2026-02-06 12:24:19 +01:00
epenet 915d375f0a Reformat lambda (a-l) (#162377) 2026-02-06 12:24:12 +01:00
Petro31 e9487a81a7 Update template image platform to new entity framework (#162343) 2026-02-06 12:20:11 +01:00
Andres Ruiz 0a2fe01b66 Add device_info to waterfurnace sensors (#162080)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-06 12:17:27 +01:00
Peter Grauvogel 9de9bde7d8 Add timestamp sensors for highest and lowest price times (#161639) 2026-02-06 12:04:39 +01:00
epenet fbc91d3d3d Remove str from sensor state class (#161686) 2026-02-06 12:01:23 +01:00
Abílio Costa 47672614df Remove external url from config for local_only users (#161891) 2026-02-06 12:00:07 +01:00
Denis Shulyaka 8c01c4a155 Add gpt-image-1.5 model support (#162208) 2026-02-06 11:57:00 +01:00
Aaron Godfrey 5dc7f8bfe3 Fix conversion of data for todo.* actions (#162366) 2026-02-06 11:52:01 +01:00
epenet cc01d15d74 Use StrEnum in eq3btsmart (#162387) 2026-02-06 11:51:00 +01:00
epenet 5c980e8d97 Cleanup ternary if expressions (#162394) 2026-02-06 11:50:47 +01:00
epenet c01e3beb2e Use StrEnum in stt (#162389) 2026-02-06 11:50:35 +01:00
Jan Bouwhuis a5b16e3694 Remove parentheses for except statements where it is not needed in mqtt integration (#162398) 2026-02-06 11:49:42 +01:00
epenet 866cd52ada Cleanup default None value from dict.get (#162396) 2026-02-06 11:49:02 +01:00
John O'Nolan 2d308aaa20 Add Ghost integration (#162041)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-06 11:47:53 +01:00
epenet 0456eb54ee Use StrEnum in unifiprotect (#162390) 2026-02-06 11:42:34 +01:00
epenet ce6fced6a4 Use StrEnum in intent helper (#162391) 2026-02-06 11:41:58 +01:00
epenet fc56f52c74 Use StrEnum in modbus (#162388) 2026-02-06 11:41:29 +01:00
dependabot[bot] f7e65eeece Bump github/codeql-action from 4.32.1 to 4.32.2 (#162369)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-06 11:33:24 +01:00
epenet 8c94de4a9c Use StrEnum in easyenergy (#162386) 2026-02-06 12:15:42 +02:00
epenet 46971c1c82 Use StrEnum in cloud (#162385) 2026-02-06 12:15:09 +02:00
epenet fb5c3c7eb6 Use StrEnum in uptimerobot tests (#162392) 2026-02-06 12:14:28 +02:00
Anders Ödlund ea42237444 Add dismiss protection to config flows (#162270)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-02-06 10:59:37 +01:00
Matt Zimmerman 2a76c2678e Add missing config flow strings to SmartTub (#162375)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 08:53:00 +01:00
Manu 72b6e5fabe Add remote action exceptions to Xbox (#162347) 2026-02-06 08:27:31 +01:00
Jordan Harvey f739fc1f55 Update pynintendoparental requirement to version 2.3.2.1 (#162362) 2026-02-06 08:26:51 +01:00
Denis Shulyaka aecfca5020 Add Claude Opus 4.6 support (#162365) 2026-02-06 08:25:53 +01:00
Matt Zimmerman f024ae442f Add PARALLEL_UPDATES to SmartTub platform files (#162373)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 08:21:33 +01:00
Matt Zimmerman 07a9aad4a4 Bump python-smarttub to 0.0.47 (#162367)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 08:14:42 +01:00
Denis Shulyaka 22ab58077e Bump anthropic to 0.78.0 (#162349) 2026-02-05 22:15:16 +01:00
epenet 4b666688c9 Adjust color mode handling in esphome lights (#162294) 2026-02-05 21:04:21 +01:00
Shay Levy d118332366 Fix Shelly Linkedgo Thermostat status update (#162339) 2026-02-05 20:52:21 +01:00
Michael Potthoff 9f32e0da14 Add type option "first_available" to sensor group in group component (#155525) 2026-02-05 20:26:45 +01:00
Andre Lengwenus 1cef223a06 Bump pypck to 0.9.10 (#162333) 2026-02-05 20:14:04 +01:00
epenet 29da1233f3 Fix missing color_mode attribute in mqtt light (#162311)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-05 18:22:57 +01:00
Arie Catsman a5b3d22058 Bump pyenphase to 2.4.5 (#162324) 2026-02-05 17:42:45 +01:00
jameson_uk d37e958a0b Add config entry tests to alexa_devices (#162295) 2026-02-05 13:07:14 +00:00
epenet 0498ac7364 Migrate supported_color_modes to shorthand attribute in zwave_js lights (#162296) 2026-02-05 13:56:20 +01:00
epenet 67bdeb9945 Adjust unknown color mode handling in ZHA lights (#162292) 2026-02-05 12:30:06 +01:00
Oliver a227307387 Add support for media_stop command for denonavr receivers (#162236) 2026-02-05 12:17:25 +01:00
Oliver 0e0309cabf Add mapping for stopped state to denonavr media player (#162283) 2026-02-05 12:15:14 +01:00
epenet fd2dfc83c6 Use shorthand attributes in zwave_js lights (#162293) 2026-02-05 12:05:08 +01:00
epenet 9e736891c4 Use shorthand attributes in demo lights (#162282) 2026-02-05 12:02:41 +01:00
Oliver fbabf0dcb8 Bump denonavr to 1.3.2 (#162271) 2026-02-05 11:59:10 +01:00
Tomás Correia 7128791152 Fix multipart upload to use consistent part sizes for R2/S3 (#162278) 2026-02-05 11:54:02 +01:00
epenet 94456b5bc3 Improve type hints in tradfri lights (#162287) 2026-02-05 11:51:34 +01:00
epenet 2105c6b177 Improve type hints in switchbot lights (#162286) 2026-02-05 11:46:50 +01:00
Robin Lintermann 34156f79e8 Bump pysmarlaapi to 0.13.0 (#162277) 2026-02-05 11:45:29 +01:00
epenet bb1a2530f5 Improve type hints in nanoleaf lights (#162284) 2026-02-05 11:44:54 +01:00
epenet 06613746f9 Remove unnecessary shorthand attribute init in template (#162279) 2026-02-05 11:41:57 +01:00
epenet 98ca948afe Improve type hints in abode lights (#162281) 2026-02-05 11:35:43 +01:00
Krisjanis Lejejs fa58fe5f4e Bump hass-nabucasa from 1.12.0 to 1.13.0 (#162274) 2026-02-05 11:03:44 +01:00
Petro31 46f230c487 Clean up unused cover constants (#162225) 2026-02-05 10:46:36 +01:00
epenet 13a987aba3 Cleanup deprecated SUPPORT_ light constants (#162210) 2026-02-05 10:32:32 +01:00
cdnninja 9cef323581 Update Vesync quality-scale to Bronze (#162260) 2026-02-05 09:44:47 +01:00
epenet 7ea7576188 Cleanup legacy support for extracting color modes from light supported features (#162265) 2026-02-05 09:33:22 +01:00
Franck Nijhof f8abbfd42b Merge branch 'master' into dev 2026-02-05 08:17:24 +00:00
Erik Montnemery 5cd1821bc9 Update redgtech snapshots (#162267) 2026-02-05 09:13:13 +01:00
Norbert Rittel 2ef7f26ffb Improve description of camera.play_stream action (#162264) 2026-02-05 09:07:10 +01:00
Jonathan Sady do Nascimento 184bea49e2 Add redgtech integration (#136947)
Co-authored-by: luan-nvg <luannnvg@gmail.com>
2026-02-05 09:04:14 +01:00
David Bonnes c853fb2068 Bump evohome-async to 1.1.3 (#162232) 2026-02-05 08:25:30 +01:00
mettolen 79e0a93e48 Upgrade Liebherr integration to Silver (#162178) 2026-02-04 22:24:53 +01:00
Andres Ruiz 3867c1d7d1 Extract waterfurnace sensor names for translation (#162025)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-04 21:48:23 +01:00
Thomas55555 b9b6b050cc Bump google_air_quality_api to 3.0.1 (#162233) 2026-02-04 21:46:07 +01:00
Muhammad Hamza Khan d960736b3d Improve typing in syncthing (#162193)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-04 21:43:13 +01:00
Franck Nijhof 3e8923f105 2026.2.0 (#162224) 2026-02-04 20:35:11 +01:00
Franck Nijhof 17cca3e69d Bump version to 2026.2.0 2026-02-04 18:53:49 +00:00
Franck Nijhof 12714c489f Bump version to 2026.2.0b5 2026-02-04 18:45:36 +00:00
Robert Resch f788d61b4a Revert "Bump intents (#162205)" (#162226) 2026-02-04 18:36:12 +00:00
Simone Chemelli 5c726af00b Fix logic and tests for Alexa Devices utils module (#162223) 2026-02-04 18:36:10 +00:00
Joost Lekkerkerker d1d207fbb2 Add guard for Apple TV text focus state (#162207) 2026-02-04 18:36:09 +00:00
David Bonnes 6c7f8df7f7 Fix evohome not updating scheduled setpoints in state attrs (#162043) 2026-02-04 18:36:07 +00:00
Kevin Stillhammer 6f8c9b1504 Bump fressnapftracker to 0.2.2 (#161913) 2026-02-04 18:36:06 +00:00
Kevin Stillhammer 4f9aedbc84 Filter out invalid trackers in fressnapf_tracker (#161670) 2026-02-04 18:36:04 +00:00
Joost Lekkerkerker afa0f572ce Add guard for Apple TV text focus state (#162207) 2026-02-04 19:34:53 +01:00
Simone Chemelli a6a1b9ddbd Fix logic and tests for Alexa Devices utils module (#162223) 2026-02-04 19:31:57 +01:00
Robert Resch c1f5b4593f Revert "Bump intents (#162205)" (#162226) 2026-02-04 19:30:05 +01:00
Kevin Stillhammer f1de4dc1cc Filter out invalid trackers in fressnapf_tracker (#161670) 2026-02-04 17:43:24 +01:00
David Bonnes 4ae0d9a9c6 Fix evohome not updating scheduled setpoints in state attrs (#162043) 2026-02-04 17:37:41 +01:00
David Girón fcd0b579cf Compress container image with zstd (#160665)
Co-authored-by: Robert Resch <robert@resch.dev>
2026-02-04 17:28:07 +01:00
Franck Nijhof 52fb0343e4 Bump version to 2026.2.0b4 2026-02-04 16:14:23 +00:00
Bram Kragten 1050b4580a Update frontend to 20260128.6 (#162214) 2026-02-04 16:10:08 +00:00
Åke Strandberg 344c42172e Add missing codes for Miele coffe systems (#162206) 2026-02-04 16:10:06 +00:00
Michael Hansen 93cc0fd7f1 Bump intents (#162205) 2026-02-04 16:10:05 +00:00
andreimoraru 05fe636b55 Bump yt-dlp to 2026.02.04 (#162204)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-04 16:10:03 +00:00
Marc Mueller f22467d099 Pin auth0-python to <5.0 (#162203) 2026-02-04 16:10:01 +00:00
TheJulianJES 4bc3899b32 Bump ZHA to 0.0.89 (#162195) 2026-02-04 16:10:00 +00:00
Oliver fc4d6bf5f1 Bump denonavr to 1.3.1 (#162183) 2026-02-04 16:09:58 +00:00
johanzander 8ed0672a8f Bump growattServer to 1.9.0 (#162179)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 16:09:57 +00:00
Norbert Rittel 282e347a1b Clarify action descriptions in media_player (#162172) 2026-02-04 16:09:55 +00:00
Erik Montnemery 1bfb02b440 Bump python-otbr-api to 2.8.0 (#162167) 2026-02-04 16:09:54 +00:00
Przemko92 71b03bd9ae Bump compit-inext-api to 0.8.0 (#162166) 2026-02-04 16:09:52 +00:00
Przemko92 cbd69822eb Update compit-inext-api to 0.7.0 (#162020) 2026-02-04 16:09:51 +00:00
Denis Shulyaka db900f4dd2 Anthropic repair deprecated models (#162162)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-04 16:00:14 +00:00
Jonathan Bangert a707e695bc Bump bleak-esphome to 3.6.0 (#162028) 2026-02-04 16:00:12 +00:00
Liquidmasl 4feceac205 Jellyfin native client controls (#161982) 2026-02-04 16:00:11 +00:00
Petro31 10c20faaca Fix template weather humidity (#161945) 2026-02-04 16:00:09 +00:00
Robert Svensson abcd512401 Add missing OUI to Axis integration, discovery would abort with unsup… (#161943) 2026-02-04 16:00:07 +00:00
Bram Kragten dee7a237ee Update frontend to 20260128.6 (#162214) 2026-02-04 16:58:12 +01:00
Åke Strandberg 3975eba12c Add missing codes for Miele coffe systems (#162206) 2026-02-04 15:06:35 +01:00
epenet ade91ebdab Cleanup deprecated COLOR_MODE light constants (#162197) 2026-02-04 15:00:12 +01:00
Norbert Rittel 1bf194dd0f Clarify action descriptions in media_player (#162172) 2026-02-04 14:58:40 +01:00
Manu 2eca8db8aa Add action exceptions to Xbox integration (#162198) 2026-02-04 14:56:52 +01:00
Robert Svensson 78415bc1ff Add missing OUI to Axis integration, discovery would abort with unsup… (#161943) 2026-02-04 14:43:04 +01:00
Denis Shulyaka e2469bcd0f Anthropic repair deprecated models (#162162)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-04 14:40:31 +01:00
Michael Hansen 54d64b7da2 Bump intents (#162205) 2026-02-04 14:25:28 +01:00
Erik Montnemery d548f3d12f Bump python-otbr-api to 2.8.0 (#162167) 2026-02-04 14:23:02 +01:00
epenet 668995da73 Fix incorrect exception in telegram_bot (#162191) 2026-02-04 13:32:29 +01:00
epenet 9eeae8eac6 Improve typing in telegram_bot (#162190) 2026-02-04 12:15:23 +00:00
andreimoraru 7e7056aa94 Bump yt-dlp to 2026.02.04 (#162204)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-04 12:07:40 +00:00
epenet b633b8d271 Fix test_before_setup IQS check (#162187)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-04 12:41:59 +01:00
Marc Mueller 45c7b9ccb8 Pin auth0-python to <5.0 (#162203) 2026-02-04 12:19:49 +01:00
dependabot[bot] 3ad1a57dfc Bump github/codeql-action from 4.32.0 to 4.32.1 (#162118)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-04 10:40:44 +01:00
Brandon Rothweiler 3cbe236a36 Bump py-aosmith to 1.0.16 (#162160) 2026-02-04 10:40:09 +01:00
Przemko92 39816c1e8a Bump compit-inext-api to 0.8.0 (#162166) 2026-02-04 10:39:12 +01:00
johanzander 5587dd43b9 Bump growattServer to 1.9.0 (#162179)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 10:38:18 +01:00
Jonathan Bangert 715d1e4eb8 Bump bleak-esphome to 3.6.0 (#162028) 2026-02-04 10:34:30 +01:00
Oliver af172fb70d Bump denonavr to 1.3.1 (#162183) 2026-02-04 10:33:44 +01:00
TheJulianJES 8c8bc104eb Bump ZHA to 0.0.89 (#162195) 2026-02-04 10:27:23 +01:00
Liquidmasl 51b20fb5db Adjust radarr constants and strings (#162159) 2026-02-04 10:16:47 +01:00
Kamil Breguła 445ba26667 Enable check for duplicate exception handlers (#162169)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
Co-authored-by: Josef Zweck <josef@zweck.dev>
2026-02-04 10:14:46 +01:00
epenet 886448f4ba Cleanup deprecated mired handling in light platform (#161777) 2026-02-04 09:52:53 +01:00
Petro31 ede4341ef3 Fix template weather humidity (#161945) 2026-02-04 08:02:09 +01:00
Liquidmasl fe363f32ec Jellyfin native client controls (#161982) 2026-02-03 20:18:59 +01:00
Kamil Breguła 31562e7571 Remove duplicated exception handler in overkiz (#162171)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
2026-02-03 20:16:06 +01:00
Kamil Breguła 0bdb51e4ca Remove duplicated exception handler in systemmonitor (#162170)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
2026-02-03 20:14:37 +01:00
epenet 67a5d7ac21 Move neato service registration (#162146) 2026-02-03 20:05:12 +01:00
epenet 5e7f06c476 Move sharkiq service registration (#162147) 2026-02-03 19:52:54 +01:00
epenet 9a69852296 Move xiaomi_miio service registration (#162148) 2026-02-03 19:48:39 +01:00
Bram Kragten fdf8edf474 Bump version to 2026.2.0b3 2026-02-03 18:03:54 +01:00
Bram Kragten 47e1a98bee Update frontend to 20260128.5 (#162156) 2026-02-03 18:03:04 +01:00
Joost Lekkerkerker 2d8572b943 Add Heatit virtual brand (#162155) 2026-02-03 18:03:02 +01:00
Joost Lekkerkerker 660cfdbd50 Add Heiman virtual brand (#162152) 2026-02-03 18:03:00 +01:00
Steven Travers 4208595da6 Modify Analytics text on feature labs (#162151) 2026-02-03 18:02:59 +01:00
Paul Bottein b6b2d2fc6f Update title and description of YAML dashboard repair (#162138) 2026-02-03 18:02:58 +01:00
victorigualada 6c4c632848 Handle chat log attachments in Cloud integration (#162121) 2026-02-03 18:02:57 +01:00
Shay Levy 78cf62176f Fix Shelly xpercent sensor state_class (#162107) 2026-02-03 18:02:56 +01:00
Denis Shulyaka df971c7a42 Anthropic: Switch default model to Haiku 4.5 (#162093) 2026-02-03 18:02:55 +01:00
mezz64 1fcabb7f2d Bump pyhik to 0.4.2 (#162092)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-03 18:02:53 +01:00
Åke Strandberg 9fb60c9ea2 Update Senz temperature sensor (#162016) 2026-02-03 18:02:52 +01:00
J. Diego Rodríguez Royo 9c11a4646f Remove coffee machine's hot water sensor's state class at Home Connect (#161246) 2026-02-03 17:58:47 +01:00
jameson_uk b036a78776 Remove invalid notification sensors for Alexa devices (#160422)
Co-authored-by: Simone Chemelli <simone.chemelli@gmail.com>
2026-02-03 17:58:45 +01:00
Kamil Breguła 60bb3cb704 Handle missing battery stats in systemmonitor (#158287)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-03 17:58:43 +01:00
Bram Kragten a722925b8e Update frontend to 20260128.5 (#162156) 2026-02-03 17:57:15 +01:00
Joost Lekkerkerker 419c5de50e Add Heiman virtual brand (#162152) 2026-02-03 17:20:25 +01:00
Joost Lekkerkerker 37faed565e Add Heatit virtual brand (#162155) 2026-02-03 17:19:50 +01:00
Paul Bottein 622953e61f Update title and description of YAML dashboard repair (#162138) 2026-02-03 17:09:23 +01:00
Steven Travers 17926c3f6a Modify Analytics text on feature labs (#162151) 2026-02-03 16:09:34 +01:00
victorigualada 48d85170c2 Handle chat log attachments in Cloud integration (#162121) 2026-02-03 15:54:56 +01:00
epenet 08d179c520 Move ecovacs service registration (#162145) 2026-02-03 15:50:17 +01:00
hanwg 5752387da8 Add entity_id parameter for Telegram bot actions (#159745)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2026-02-03 15:34:39 +01:00
Sebastiaan Speck 1ebde65f03 Add sound horn and flash lights buttons to Renault (#161976)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-02-03 15:18:55 +01:00
Denis Shulyaka 89f536e332 Anthropic: Switch default model to Haiku 4.5 (#162093) 2026-02-03 14:12:21 +01:00
Shay Levy 8784329333 Fix Shelly xpercent sensor state_class (#162107) 2026-02-03 14:11:55 +01:00
Marc Mueller d73538722d Use Generator and AsyncGenerator for contextmanager typing (#162144) 2026-02-03 13:52:33 +01:00
Brett Adams d49d3f0a2f Mark test-coverage as done for Teslemetry quality scale (#161958)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-03 12:57:14 +01:00
Blaine Cook 8466dd4c2b Add temperature sensor to Huum integration (#161405)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-03 12:38:39 +01:00
Brett Adams 6bb1e688c6 Mark reconfiguration-flow as done for Teslemetry (#162139)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 12:37:24 +01:00
epenet 9bc1c4c4f3 Simplify reolink method arguments (#162137) 2026-02-03 12:23:33 +01:00
jameson_uk a554cb8211 Remove invalid notification sensors for Alexa devices (#160422)
Co-authored-by: Simone Chemelli <simone.chemelli@gmail.com>
2026-02-03 11:48:57 +01:00
Liquidmasl 145d38403e Add get_queue and get_movies service calls to Radarr (#160753)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-03 11:30:30 +01:00
Erwin Douna 10d4af5674 Use asyncio.gather pattern in portainer (#160888) 2026-02-03 11:23:34 +01:00
Brett Adams ed3b4d2de3 Fix oauth debug log bug in Teslemetry (#161652) 2026-02-03 11:16:45 +01:00
epenet e66d324877 Move openhome service registration (#162127) 2026-02-03 11:15:53 +01:00
epenet f7f18627a2 Move squeezebox service registration (#162132) 2026-02-03 11:15:28 +01:00
epenet d18630020f Move songpal service registration (#162131) 2026-02-03 11:15:05 +01:00
epenet a715ec318c Move snapcast service registration (#162130) 2026-02-03 11:14:39 +01:00
epenet 0ef5a77dc9 Move roon service registration (#162129) 2026-02-03 11:14:06 +01:00
epenet b43abf83b8 Move roku service registration (#162128) 2026-02-03 11:13:19 +01:00
epenet 84d28db3a7 Move linkplay service registration (#162126) 2026-02-03 11:12:32 +01:00
epenet 74d99fa0be Move denonavr service registration (#162123) 2026-02-03 11:12:04 +01:00
epenet 3ff0320ed8 Move vizio service registration (#162133) 2026-02-03 11:11:19 +01:00
epenet 16cb9e9785 Move kodi service registration (#162125) 2026-02-03 11:10:41 +01:00
epenet d92279dfcb Move epson service registration (#162124) 2026-02-03 11:10:10 +01:00
Kamil Breguła 4b9d28d0e5 Handle missing battery stats in systemmonitor (#158287)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-03 10:54:31 +01:00
Wendelin e6a60dfe50 Add option to use frontend PR artifact to frontend integration (#161291)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2026-02-03 10:23:25 +01:00
Tom d219056e9d Add target_humidity_step attribute to climate (#160418) 2026-02-03 09:34:31 +02:00
epenet 6ff6b099b5 Move bring service registration (#162077) 2026-02-03 07:42:03 +01:00
Brett Adams c5b9699098 Add model_id and sw_version to Teslemetry device info (#161959)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 21:58:02 +01:00
mettolen 6937bfdf67 Add number entity to Liebherr integration (#162011) 2026-02-02 21:48:39 +01:00
epenet 39ee3fcfaa Move bond service registration (#162075) 2026-02-02 21:47:30 +01:00
J. Diego Rodríguez Royo 16cdfd05a0 Remove coffee machine's hot water sensor's state class at Home Connect (#161246) 2026-02-02 21:30:43 +01:00
mezz64 f49d4787be Bump pyhik to 0.4.2 (#162092)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-02 21:22:42 +01:00
epenet 2076700dc4 Move rainbird service registration (#162089) 2026-02-02 21:02:57 +01:00
Åke Strandberg 76c135913e Update Senz temperature sensor (#162016) 2026-02-02 20:10:46 +01:00
epenet c3534d5445 Mark tts method type hints as mandatory (#161235) 2026-02-02 19:49:55 +01:00
epenet fc60b16d65 Mark device_tracker method type hints as mandatory (#161232) 2026-02-02 19:49:26 +01:00
epenet 0443c93f77 Move webostv service registration (#162091) 2026-02-02 20:48:21 +02:00
Bram Kragten 0e770958ac Bump version to 2026.2.0b2 2026-02-02 19:12:33 +01:00
Bram Kragten 2a54c71b6c Update frontend to 20260128.4 (#162096) 2026-02-02 19:11:59 +01:00
Steven Travers 50463291ab Add learn more data for Analytics in labs (#162094) 2026-02-02 19:11:59 +01:00
Andrea Turri 43cc34042a Fix Miele dishwasher PowerDisk filling level sensor not showing up (#162048) 2026-02-02 19:11:58 +01:00
Jan Bouwhuis a02244ccda Bump incomfort-client to 0.6.12 (#162037) 2026-02-02 19:11:57 +01:00
Adrián Moreno a739619121 Bump pymeteoclimatic to 0.1.1 (#162029) 2026-02-02 19:11:56 +01:00
Åke Strandberg 5db97a5f1c Improved error checking during startup of SENZ (#162026) 2026-02-02 19:11:54 +01:00
Josef Zweck 804ba9c9cc Remove file description dependency in onedrive (#162012) 2026-02-02 19:11:53 +01:00
Filip Bårdsnes Tomren 5ecbcea946 Update ical requirement version to 12.1.3 (#162010) 2026-02-02 19:11:52 +01:00
hanwg 11be2b6289 Fix parse_mode for Telegram bot actions (#162006) 2026-02-02 19:11:51 +01:00
cdnninja eefae0307b Add integration type of hub to vesync (#162004) 2026-02-02 19:11:50 +01:00
Matthias Alphart d397ee28ea Fix KNX fan unique_id for switch-only fans (#162002) 2026-02-02 19:11:49 +01:00
starkillerOG 02c821128e Bump reolink-aio to 0.18.2 (#161998) 2026-02-02 19:11:48 +01:00
Shay Levy 71dc15d45f Fix Shelly CoIoT repair issue (#161973)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-02 19:11:47 +01:00
Raphael Hehl 1078387b22 Bump uiprotect to version 10.1.0 (#161967)
Co-authored-by: RaHehl <rahehl@users.noreply.github.com>
2026-02-02 19:11:46 +01:00
tronikos 35fab27d15 Bump opower to 0.17.0 (#161962) 2026-02-02 19:11:45 +01:00
Yuxin Wang 915dc7a908 Mark datetime sensors as unknown when parsing fails (#161952) 2026-02-02 19:11:44 +01:00
mvn23 e5a9738983 Fix OpenTherm Gateway button availability (#161933) 2026-02-02 19:11:43 +01:00
mvn23 2ff73219a2 Bump pyotgw to 2.2.3 (#161928) 2026-02-02 19:11:42 +01:00
epenet 5dc1270ed1 Fix mired warning in template light (#161923) 2026-02-02 19:11:41 +01:00
J. Diego Rodríguez Royo 9e95ad5a85 Restore the Home Connect program option entities (#156401)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2026-02-02 19:11:40 +01:00
Bram Kragten f97cf0e446 Update frontend to 20260128.4 (#162096) 2026-02-02 19:03:38 +01:00
epenet bd4fa0d5c2 Move reolink service registration (#162085) 2026-02-02 19:02:09 +01:00
Steven Travers f60d367184 Add learn more data for Analytics in labs (#162094) 2026-02-02 17:22:01 +01:00
epenet 6e231f2ec5 Move husqvarna_automower service registration (#162087) 2026-02-02 17:08:41 +01:00
epenet 13ba2d2e47 Move litterrobot service registration (#162088) 2026-02-02 17:08:07 +01:00
epenet ba4a163e24 Move roborock service registration (#162090) 2026-02-02 17:07:44 +01:00
epenet b7db8684db Move elgato service registration (#162086) 2026-02-02 17:05:48 +01:00
Ludovic BOUÉ a7595dc468 Rename Matter Inovelli VTM31-SN fixture (#162076) 2026-02-02 15:49:11 +01:00
epenet d2c8c3565b Move blink service registration (#162078) 2026-02-02 14:49:05 +01:00
Ludovic BOUÉ 422d1031f4 Rename Matter Mock air purifier fixture file (#161937) 2026-02-02 14:43:27 +01:00
Viktor Andersson c9a79cf100 Update Electricity Maps translations (#162074)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2026-02-02 13:54:07 +01:00
epenet c42d47a619 Rename service registration function in growatt_server (#162073) 2026-02-02 13:32:33 +01:00
Ludovic BOUÉ a26f871d32 Rename Matter Mock devices (#161949) 2026-02-02 12:59:32 +01:00
Gage Benne d481c1bcc5 Improve accuracy of blood glucose conversion factor (#161644) 2026-02-02 12:19:16 +01:00
dependabot[bot] 379e3596b4 Bump dawidd6/action-download-artifact from 12 to 14 (#162058)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 10:55:15 +01:00
Jan Bouwhuis 423a7cdbba Bump incomfort-client to 0.6.12 (#162037) 2026-02-02 10:10:11 +01:00
Henning Kerstan 841fa48186 Replace hass.data[DATA_ENOCEAN] by config_entry.runtime_data (#161997) 2026-02-02 09:50:49 +01:00
Andres Ruiz 61e35157e3 Bump waterfurnace to 1.5.1 (#162042) 2026-02-02 08:59:53 +01:00
epenet 87f655f56d Move alarmdecoder service registration (#162063) 2026-02-02 08:59:47 +01:00
epenet 692b8d0722 Move agent_dvr service registration (#162062) 2026-02-02 08:59:35 +01:00
Luke Lashley 5f9f623c3f Bump python-roborock to 4.12.0 (#162054) 2026-02-01 20:28:35 -08:00
Przemko92 e595b6cd90 Update compit-inext-api to 0.7.0 (#162020) 2026-02-02 02:28:36 +01:00
Andrea Turri a748eebf3e Fix Miele dishwasher PowerDisk filling level sensor not showing up (#162048) 2026-02-02 02:18:02 +01:00
Adrián Moreno 6bdd544867 Bump pymeteoclimatic to 0.1.1 (#162029) 2026-02-02 00:44:29 +01:00
Luke Lashley 705eadf8ce Add the ability to select region for Roborock (#160898) 2026-02-01 11:50:34 -08:00
Josef Zweck b7c6e4eafc Remove file description dependency in onedrive (#162012) 2026-02-01 19:43:56 +01:00
Åke Strandberg f4aba286fe Improved error checking during startup of SENZ (#162026) 2026-02-01 19:42:27 +01:00
Yuxin Wang 5fa4f6de11 Mark datetime sensors as unknown when parsing fails (#161952) 2026-02-01 17:41:01 +01:00
Justus db1f045c42 bump iometer to v0.4.0 (#162027) 2026-02-01 17:32:03 +01:00
Erwin Douna eaba4817bd Optimize attribute lookup in DSMR Reader (#161994) 2026-02-01 15:26:00 +01:00
Erwin Douna 96cb2247df Remove unneeded NotImplementedError in Volvlo entity (#161990) 2026-02-01 15:25:23 +01:00
Matthias Alphart 99fa7a1f52 Fix KNX fan unique_id for switch-only fans (#162002) 2026-02-01 12:53:19 +01:00
Filip Bårdsnes Tomren e0ba928296 Update ical requirement version to 12.1.3 (#162010) 2026-02-01 12:43:34 +01:00
Tomasz 16fd5e8f1f Move initial_color to CalendarEntityDescription (#161831)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-02-01 11:01:05 +00:00
Brett Adams 201e95a417 Complete config-flow-test-coverage quality in Teslemetry (#161955)
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 10:54:35 +01:00
dafal dc01592991 Bthome encryption downgrade (#159646)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-02-01 09:40:47 +02:00
hanwg c5fb2bd566 Fix parse_mode for Telegram bot actions (#162006) 2026-02-01 08:37:23 +01:00
cdnninja d03d996155 Add integration type of hub to vesync (#162004) 2026-02-01 08:33:04 +01:00
starkillerOG 9618412a44 Bump reolink-aio to 0.18.2 (#161998) 2026-02-01 07:49:55 +01:00
Erwin Douna 967e97661f Add reauth to Proxmox (#161944) 2026-01-31 22:42:33 +01:00
Erwin Douna b757312fe0 Remove unused variables in SMA (#161989) 2026-01-31 20:40:28 +01:00
Erwin Douna 2ed8ec0bdf Add reconfigure to Proxmox (#161941)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2026-01-31 20:21:55 +01:00
epenet 97f6e3741a Fix mired warning in template light (#161923) 2026-01-31 17:30:41 +01:00
Colin c2d3244d26 openevse: Turn on strict typing (#161957)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2026-01-31 16:56:17 +01:00
Shay Levy eafeba792d Fix Shelly CoIoT repair issue (#161973)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-31 16:33:31 +02:00
Norbert Rittel c9318b6fbf Clarify action description for input_button helper (#161963) 2026-01-31 15:16:36 +01:00
epenet 99be382abf Remove outdated device registry cleanup in generic_hygrostat (#161859) 2026-01-31 15:15:19 +01:00
epenet 7cfcfca210 Remove outdated device registry cleanup in generic_thermostat (#161861) 2026-01-31 15:14:57 +01:00
epenet f29daccb19 Remove outdated device registry cleanup in history_stats (#161862) 2026-01-31 15:14:42 +01:00
epenet be869fce6c Remove outdated device registry cleanup in mold_indicator (#161864) 2026-01-31 15:14:26 +01:00
epenet 7bb0414a39 Remove outdated device registry cleanup in statistics (#161865) 2026-01-31 15:14:09 +01:00
epenet 3f8807d063 Remove outdated device registry cleanup in threshold (#161866) 2026-01-31 15:13:54 +01:00
mettolen 67642e6246 Add reauthentication flow to Liebherr integration (#161902)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-31 15:12:52 +01:00
mvn23 0d215597f3 Fix OpenTherm Gateway button availability (#161933) 2026-01-31 15:06:21 +01:00
mvn23 f41bd2b582 Bump pyotgw to 2.2.3 (#161928) 2026-01-31 15:03:56 +01:00
Norbert Rittel 5c9ec1911b Clarify action descriptions for input_boolean (#161924) 2026-01-31 15:03:08 +01:00
J. Diego Rodríguez Royo 1a0b7fe984 Restore the Home Connect program option entities (#156401)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2026-01-31 12:32:18 +01:00
Erwin Douna 26ee25d7bb Pattern fix for Proxmox config flow (#161946) 2026-01-31 11:41:41 +01:00
Norbert Rittel aabf52d3cf Rename "service" to "action", use common state for "High" (#161940) 2026-01-31 11:40:55 +01:00
Erwin Douna 99fcb46a7e Add parallel updates to Portainer (#161947) 2026-01-31 11:40:25 +01:00
Raphael Hehl 6580c5e5bf Bump uiprotect to version 10.1.0 (#161967)
Co-authored-by: RaHehl <rahehl@users.noreply.github.com>
2026-01-31 11:39:20 +01:00
tronikos 63e7d4dc08 Bump opower to 0.17.0 (#161962) 2026-01-31 11:38:43 +01:00
Sid cc6900d846 Bump eheimdigital to 1.6.0 (#161961) 2026-01-31 11:38:14 +01:00
Brett Adams ca2ad22884 Rename drive inverter unavailable state in Teslemetry (#161960)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 11:36:12 +01:00
Armin Ghofrani 40944f0f2d Enable prompt caching for Anthropic conversation integration (#158957)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:32:47 +03:00
uptimeZERO_ 91a3e488b1 Bump media source upload limit from 10mb to 20mb (#161436) 2026-01-30 13:07:37 +01:00
Magnus Øverli 9a1f517e6e Convert flexit_bacnet fireplace mode to climate preset- Rename 'Boost… (#155760)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-01-30 12:59:10 +01:00
Franck Nijhof 9a5d4610f7 Bump version to 2026.2.0b1 2026-01-30 11:45:08 +00:00
Paul Bottein 41c524fce4 Update frontend to 20260128.3 (#161918) 2026-01-30 11:44:54 +00:00
David Recordon 5f9fa95554 Fix Control4 HVAC state-to-action mapping (#161916) 2026-01-30 11:44:51 +00:00
Simone Chemelli 6950be8ea9 Handle hostname resolution for Shelly repair issue (#161914) 2026-01-30 11:44:47 +00:00
puddly c5a8bf64d0 Bump ZHA to 0.0.88 (#161904) 2026-01-30 11:44:44 +00:00
hanwg a2b9a6e9df Update translations for Telegram bot (#161903) 2026-01-30 11:44:43 +00:00
Marc Mueller a0c567f0da Update fritzconnection to 1.15.1 (#161887) 2026-01-30 11:44:40 +00:00
Bram Kragten c7feafdde6 Update frontend to 20260128.2 (#161881) 2026-01-30 11:44:38 +00:00
Björn Dalfors e1e74b0aeb Bump nibe to 2.22.0 (#161873) 2026-01-30 11:44:36 +00:00
Sebastiaan Speck 673411ef97 Bump renault-api to 0.5.3 (#161857) 2026-01-30 11:44:34 +00:00
epenet f7e5af7cb1 Fix incorrect entity_description class in radarr (#161856) 2026-01-30 11:44:32 +00:00
Norbert Rittel 0ee56ce708 Fix action descriptions of alarm_control_panel (#161852) 2026-01-30 11:44:30 +00:00
Manu f93a176398 Fix string in Namecheap DynamicDNS integration (#161821) 2026-01-30 11:44:28 +00:00
Paul Bottein cd2394bc12 Allow lovelace path for dashboard in yaml and fix yaml dashboard migration (#161816) 2026-01-30 11:44:26 +00:00
Michael Hansen 5c20b8eaff Bump intents to 2026.1.28 (#161813) 2026-01-30 11:44:25 +00:00
Aaron Godfrey 4bd499d3a6 Update todoist-api-python to 3.1.0 (#161811)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-30 11:44:23 +00:00
Jan Bouwhuis 8a53b94c5a Fix use of ambiguous units for reactive power and energy (#161810) 2026-01-30 11:44:20 +00:00
victorigualada d5aff326e3 Use OpenAI schema dataclasses for cloud stream responses (#161663) 2026-01-30 11:44:18 +00:00
Gage Benne 22f66abbe7 Bump pydexcom to 0.5.1 (#161549) 2026-01-30 11:44:16 +00:00
Mattia Monga f635228b1f Make viaggiatreno work by fixing some critical bugs (#160093)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-01-30 11:44:14 +00:00
Artur Pragacz 4c708c143d Fix validation of actions config in intent_script (#158266) 2026-01-30 11:44:12 +00:00
Simone Chemelli c82c614bb9 Handle hostname resolution for Shelly repair issue (#161914) 2026-01-30 12:26:48 +01:00
Norbert Rittel 20914dce67 Improve action descriptions of camera (#161876) 2026-01-30 12:08:49 +01:00
Paul Bottein 5fc407d2f3 Update frontend to 20260128.3 (#161918) 2026-01-30 11:51:53 +01:00
Marc Mueller c7444d38a1 Remove pydantic v1 mypy plugin (#161901) 2026-01-30 11:19:06 +01:00
puddly 81f6136bda Bump ZHA to 0.0.88 (#161904) 2026-01-30 11:18:38 +01:00
Steve Easley 862d0ea49e Bump JVC Projector dependency to 2.0.1 (#161898) 2026-01-30 11:17:14 +01:00
hanwg f2fdfed241 Update translations for Telegram bot (#161903) 2026-01-30 11:13:46 +01:00
David Recordon 15640049cb Fix Control4 HVAC state-to-action mapping (#161916) 2026-01-30 10:59:39 +01:00
dependabot[bot] 5c163434f8 Bump actions/cache from 5.0.2 to 5.0.3 (#161906)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-30 10:47:02 +01:00
Sebastiaan Speck e54c2ea55e Ensure Renault buttons are supported by the vehicle (#161893)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-01-30 09:58:50 +01:00
Kevin Stillhammer 1ec42693ab Bump fressnapftracker to 0.2.2 (#161913) 2026-01-30 09:32:13 +01:00
epenet 672864ae4f Remove outdated device registry cleanup in trend (#161867) 2026-01-30 08:07:53 +01:00
Artur Pragacz e54d7e42cb Add subscription pattern for conversation intents (#158456) 2026-01-30 07:19:57 +01:00
Jan Bouwhuis 5d63fce015 Re-add Claude code to devcontainer via native install script (#161807) 2026-01-29 23:35:59 -05:00
Paul Bottein 190fe10eed Allow lovelace path for dashboard in yaml and fix yaml dashboard migration (#161816) 2026-01-29 17:19:37 -05:00
Bram Kragten ef410c1e2a Update frontend to 20260128.2 (#161881) 2026-01-29 23:02:59 +01:00
Artur Pragacz 5a712398e7 Fix validation of actions config in intent_script (#158266) 2026-01-29 22:12:46 +01:00
Franck Nijhof 3369459d41 Bump version to 2026.2.0b0 2026-01-28 20:00:19 +00:00
Ludovic BOUÉ 69739cf3b2 Add mock closure to integration fixture for Matter component tests 2025-12-11 10:23:44 +00:00
Ludovic BOUÉ a3fcf1cfd6 Add mock closure JSON fixture for Matter component tests 2025-12-11 10:23:17 +00:00
Ludovic BOUÉ 8788a7ba84 Add Matter closure fixture 2025-12-11 10:12:01 +00:00
2007 changed files with 74447 additions and 26505 deletions
+2 -1
View File
@@ -22,6 +22,7 @@ base_platforms: &base_platforms
- homeassistant/components/calendar/**
- homeassistant/components/camera/**
- homeassistant/components/climate/**
- homeassistant/components/conversation/**
- homeassistant/components/cover/**
- homeassistant/components/date/**
- homeassistant/components/datetime/**
@@ -53,6 +54,7 @@ base_platforms: &base_platforms
- homeassistant/components/update/**
- homeassistant/components/vacuum/**
- homeassistant/components/valve/**
- homeassistant/components/wake_word/**
- homeassistant/components/water_heater/**
- homeassistant/components/weather/**
@@ -70,7 +72,6 @@ components: &components
- homeassistant/components/cloud/**
- homeassistant/components/config/**
- homeassistant/components/configurator/**
- homeassistant/components/conversation/**
- homeassistant/components/demo/**
- homeassistant/components/device_automation/**
- homeassistant/components/dhcp/**
+7 -1
View File
@@ -60,7 +60,13 @@
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
},
"[json][jsonc][yaml]": {
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"json.schemas": [
+12 -9
View File
@@ -100,7 +100,7 @@ jobs:
- name: Download nightly wheels of frontend
if: needs.init.outputs.channel == 'dev'
uses: dawidd6/action-download-artifact@0bd50d53a6d7fb5cb921e607957e9cc12b4ce392 # v12
uses: dawidd6/action-download-artifact@5c98f0b039f36ef966fdb7dfa9779262785ecb05 # v14
with:
github_token: ${{secrets.GITHUB_TOKEN}}
repo: home-assistant/frontend
@@ -111,7 +111,7 @@ jobs:
- name: Download nightly wheels of intents
if: needs.init.outputs.channel == 'dev'
uses: dawidd6/action-download-artifact@0bd50d53a6d7fb5cb921e607957e9cc12b4ce392 # v12
uses: dawidd6/action-download-artifact@5c98f0b039f36ef966fdb7dfa9779262785ecb05 # v14
with:
github_token: ${{secrets.GITHUB_TOKEN}}
repo: OHF-Voice/intents-package
@@ -165,7 +165,7 @@ jobs:
sed -i "s|home-assistant-intents==.*|home-assistant-intents==${BASH_REMATCH[1]}|" \
homeassistant/package_constraints.txt
sed -i "s|home-assistant-intents==.*||" requirements_all.txt
sed -i "s|home-assistant-intents==.*||" requirements_all.txt requirements.txt
fi
- name: Download translations
@@ -190,8 +190,7 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- &install_cosign
name: Install Cosign
- name: Install Cosign
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
with:
cosign-release: "v2.5.3"
@@ -225,7 +224,7 @@ jobs:
- name: Build base image
id: build
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: .
file: ./Dockerfile
@@ -235,6 +234,7 @@ jobs:
build-args: |
BUILD_FROM=${{ steps.vars.outputs.base_image }}
tags: ghcr.io/home-assistant/${{ matrix.arch }}-homeassistant:${{ needs.init.outputs.version }}
outputs: type=image,push=true,compression=zstd,compression-level=9,force-compression=true,oci-mediatypes=true
labels: |
io.hass.arch=${{ matrix.arch }}
io.hass.version=${{ needs.init.outputs.version }}
@@ -354,7 +354,10 @@ jobs:
matrix:
registry: ["ghcr.io/home-assistant", "docker.io/homeassistant"]
steps:
- *install_cosign
- name: Install Cosign
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
with:
cosign-release: "v2.5.3"
- name: Login to DockerHub
if: matrix.registry == 'docker.io/homeassistant'
@@ -529,7 +532,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: . # So action will not pull the repository again
file: ./script/hassfest/docker/Dockerfile
@@ -542,7 +545,7 @@ jobs:
- name: Push Docker image
if: needs.init.outputs.channel != 'dev' && needs.init.outputs.publish == 'true'
id: push
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: . # So action will not pull the repository again
file: ./script/hassfest/docker/Dockerfile
+400 -159
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -24,11 +24,11 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Initialize CodeQL
uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
with:
languages: python
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
with:
category: "/language:python"
@@ -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@a6101c89c6feaecc585efdd8d461f18bb7896f20 # v2.0.5
uses: actions/ai-inference@a380166897b5408b8fb7dddd148142794cb5624a # v2.0.6
with:
model: openai/gpt-4o
system-prompt: |
@@ -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@a6101c89c6feaecc585efdd8d461f18bb7896f20 # v2.0.5
uses: actions/ai-inference@a380166897b5408b8fb7dddd148142794cb5624a # v2.0.6
with:
model: openai/gpt-4o-mini
system-prompt: |
+32 -20
View File
@@ -29,8 +29,7 @@ jobs:
if: github.repository_owner == 'home-assistant'
runs-on: ubuntu-latest
steps:
- &checkout
name: Checkout the repository
- name: Checkout the repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -74,7 +73,7 @@ jobs:
) > .env_file
- name: Upload env_file
uses: &actions-upload-artifact actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: env_file
path: ./.env_file
@@ -82,7 +81,7 @@ jobs:
overwrite: true
- name: Upload requirements_diff
uses: *actions-upload-artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: requirements_diff
path: ./requirements_diff.txt
@@ -94,7 +93,7 @@ jobs:
python -m script.gen_requirements_all ci
- name: Upload requirements_all_wheels
uses: *actions-upload-artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: requirements_all_wheels
path: ./requirements_all_wheels_*.txt
@@ -106,7 +105,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix: &matrix-build
matrix:
abi: ["cp313", "cp314"]
arch: ["amd64", "aarch64"]
include:
@@ -115,17 +114,16 @@ jobs:
- arch: aarch64
os: ubuntu-24.04-arm
steps:
- *checkout
- name: Checkout the repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- &download-env-file
name: Download env_file
uses: &actions-download-artifact actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
- name: Download env_file
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: env_file
- &download-requirements-diff
name: Download requirements_diff
uses: *actions-download-artifact
- name: Download requirements_diff
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: requirements_diff
@@ -136,7 +134,7 @@ jobs:
sed -i "/uv/d" requirements_diff.txt
- name: Build wheels
uses: &home-assistant-wheels home-assistant/wheels@e5742a69d69f0e274e2689c998900c7d19652c21 # 2025.12.0
uses: home-assistant/wheels@e5742a69d69f0e274e2689c998900c7d19652c21 # 2025.12.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
@@ -156,16 +154,30 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix: *matrix-build
matrix:
abi: ["cp313", "cp314"]
arch: ["amd64", "aarch64"]
include:
- arch: amd64
os: ubuntu-latest
- arch: aarch64
os: ubuntu-24.04-arm
steps:
- *checkout
- name: Checkout the repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- *download-env-file
- name: Download env_file
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: env_file
- *download-requirements-diff
- name: Download requirements_diff
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: requirements_diff
- name: Download requirements_all_wheels
uses: *actions-download-artifact
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: requirements_all_wheels
@@ -178,7 +190,7 @@ jobs:
sed -i "/uv/d" requirements_diff.txt
- name: Build wheels
uses: *home-assistant-wheels
uses: home-assistant/wheels@e5742a69d69f0e274e2689c998900c7d19652c21 # 2025.12.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
+1 -1
View File
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.13
rev: v0.15.1
hooks:
- id: ruff-check
args:
+5 -1
View File
@@ -221,6 +221,7 @@ homeassistant.components.generic_hygrostat.*
homeassistant.components.generic_thermostat.*
homeassistant.components.geo_location.*
homeassistant.components.geocaching.*
homeassistant.components.ghost.*
homeassistant.components.gios.*
homeassistant.components.github.*
homeassistant.components.glances.*
@@ -286,6 +287,7 @@ homeassistant.components.input_button.*
homeassistant.components.input_select.*
homeassistant.components.input_text.*
homeassistant.components.integration.*
homeassistant.components.intelliclima.*
homeassistant.components.intent.*
homeassistant.components.intent_script.*
homeassistant.components.ios.*
@@ -362,7 +364,6 @@ homeassistant.components.my.*
homeassistant.components.mysensors.*
homeassistant.components.myuplink.*
homeassistant.components.nam.*
homeassistant.components.nanoleaf.*
homeassistant.components.nasweb.*
homeassistant.components.neato.*
homeassistant.components.nest.*
@@ -384,11 +385,13 @@ homeassistant.components.ohme.*
homeassistant.components.onboarding.*
homeassistant.components.oncue.*
homeassistant.components.onedrive.*
homeassistant.components.onedrive_for_business.*
homeassistant.components.onewire.*
homeassistant.components.onkyo.*
homeassistant.components.open_meteo.*
homeassistant.components.open_router.*
homeassistant.components.openai_conversation.*
homeassistant.components.openevse.*
homeassistant.components.openexchangerates.*
homeassistant.components.opensky.*
homeassistant.components.openuv.*
@@ -434,6 +437,7 @@ homeassistant.components.raspberry_pi.*
homeassistant.components.rdw.*
homeassistant.components.recollect_waste.*
homeassistant.components.recorder.*
homeassistant.components.redgtech.*
homeassistant.components.remember_the_milk.*
homeassistant.components.remote.*
homeassistant.components.remote_calendar.*
Generated
+20 -5
View File
@@ -15,7 +15,7 @@
.yamllint @home-assistant/core
pyproject.toml @home-assistant/core
requirements_test.txt @home-assistant/core
/.devcontainer/ @home-assistant/core
/.devcontainer/ @home-assistant/core @edenhaus
/.github/ @home-assistant/core
/.vscode/ @home-assistant/core
/homeassistant/*.py @home-assistant/core
@@ -595,6 +595,8 @@ build.json @home-assistant/supervisor
/tests/components/geonetnz_quakes/ @exxamalte
/homeassistant/components/geonetnz_volcano/ @exxamalte
/tests/components/geonetnz_volcano/ @exxamalte
/homeassistant/components/ghost/ @johnonolan
/tests/components/ghost/ @johnonolan
/homeassistant/components/gios/ @bieniu
/tests/components/gios/ @bieniu
/homeassistant/components/github/ @timmo001 @ludeeus
@@ -670,6 +672,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/hdmi_cec/ @inytar
/tests/components/hdmi_cec/ @inytar
/homeassistant/components/heatmiser/ @andylockran
/homeassistant/components/hegel/ @boazca
/tests/components/hegel/ @boazca
/homeassistant/components/heos/ @andrewsayre
/tests/components/heos/ @andrewsayre
/homeassistant/components/here_travel_time/ @eifinger
@@ -713,8 +717,10 @@ build.json @home-assistant/supervisor
/tests/components/homekit_controller/ @Jc2k @bdraco
/homeassistant/components/homematic/ @pvizeli
/tests/components/homematic/ @pvizeli
/homeassistant/components/homematicip_cloud/ @hahn-th
/tests/components/homematicip_cloud/ @hahn-th
/homeassistant/components/homematicip_cloud/ @hahn-th @lackas
/tests/components/homematicip_cloud/ @hahn-th @lackas
/homeassistant/components/homevolt/ @danielhiversen
/tests/components/homevolt/ @danielhiversen
/homeassistant/components/homewizard/ @DCSBL
/tests/components/homewizard/ @DCSBL
/homeassistant/components/honeywell/ @rdfurman @mkmer
@@ -756,6 +762,8 @@ build.json @home-assistant/supervisor
/tests/components/icloud/ @Quentame @nzapponi
/homeassistant/components/idasen_desk/ @abmantis
/tests/components/idasen_desk/ @abmantis
/homeassistant/components/idrive_e2/ @patrickvorgers
/tests/components/idrive_e2/ @patrickvorgers
/homeassistant/components/igloohome/ @keithle888
/tests/components/igloohome/ @keithle888
/homeassistant/components/ign_sismologia/ @exxamalte
@@ -800,6 +808,8 @@ build.json @home-assistant/supervisor
/tests/components/insteon/ @teharris1
/homeassistant/components/integration/ @dgomes
/tests/components/integration/ @dgomes
/homeassistant/components/intelliclima/ @dvdinth
/tests/components/intelliclima/ @dvdinth
/homeassistant/components/intellifire/ @jeeftor
/tests/components/intellifire/ @jeeftor
/homeassistant/components/intent/ @home-assistant/core @synesthesiam @arturpragacz
@@ -1076,8 +1086,8 @@ build.json @home-assistant/supervisor
/tests/components/nam/ @bieniu
/homeassistant/components/namecheapdns/ @tr4nt0r
/tests/components/namecheapdns/ @tr4nt0r
/homeassistant/components/nanoleaf/ @milanmeu @joostlek
/tests/components/nanoleaf/ @milanmeu @joostlek
/homeassistant/components/nanoleaf/ @milanmeu @joostlek @loebi-ch @JaspervRijbroek @jonathanrobichaud4
/tests/components/nanoleaf/ @milanmeu @joostlek @loebi-ch @JaspervRijbroek @jonathanrobichaud4
/homeassistant/components/nasweb/ @nasWebio
/tests/components/nasweb/ @nasWebio
/homeassistant/components/nederlandse_spoorwegen/ @YarmoM @heindrichpaul
@@ -1170,6 +1180,8 @@ build.json @home-assistant/supervisor
/tests/components/ondilo_ico/ @JeromeHXP
/homeassistant/components/onedrive/ @zweckj
/tests/components/onedrive/ @zweckj
/homeassistant/components/onedrive_for_business/ @zweckj
/tests/components/onedrive_for_business/ @zweckj
/homeassistant/components/onewire/ @garbled1 @epenet
/tests/components/onewire/ @garbled1 @epenet
/homeassistant/components/onkyo/ @arturpragacz @eclair4151
@@ -1355,6 +1367,8 @@ build.json @home-assistant/supervisor
/tests/components/recorder/ @home-assistant/core
/homeassistant/components/recovery_mode/ @home-assistant/core
/tests/components/recovery_mode/ @home-assistant/core
/homeassistant/components/redgtech/ @jonhsady @luan-nvg
/tests/components/redgtech/ @jonhsady @luan-nvg
/homeassistant/components/refoss/ @ashionky
/tests/components/refoss/ @ashionky
/homeassistant/components/rehlko/ @bdraco @peterager
@@ -1561,6 +1575,7 @@ build.json @home-assistant/supervisor
/homeassistant/components/speedtestdotnet/ @rohankapoorcom @engrbm87
/tests/components/speedtestdotnet/ @rohankapoorcom @engrbm87
/homeassistant/components/splunk/ @Bre77
/tests/components/splunk/ @Bre77
/homeassistant/components/spotify/ @frenck @joostlek
/tests/components/spotify/ @frenck @joostlek
/homeassistant/components/sql/ @gjohansson-ST @dougiteixeira
+3
View File
@@ -52,6 +52,9 @@ RUN --mount=type=bind,source=requirements.txt,target=requirements.txt \
--mount=type=bind,source=requirements_test_pre_commit.txt,target=requirements_test_pre_commit.txt \
uv pip install -r requirements.txt -r requirements_test.txt
# Claude Code native install
RUN curl -fsSL https://claude.ai/install.sh | bash
WORKDIR /workspaces
# Set the default shell to bash instead of sh
+5
View File
@@ -0,0 +1,5 @@
{
"domain": "heatit",
"name": "Heatit",
"iot_standards": ["zwave"]
}
+5
View File
@@ -0,0 +1,5 @@
{
"domain": "heiman",
"name": "Heiman",
"iot_standards": ["matter", "zigbee"]
}
+1
View File
@@ -13,6 +13,7 @@
"microsoft",
"msteams",
"onedrive",
"onedrive_for_business",
"xbox"
]
}
@@ -64,7 +64,7 @@ class AbodeFlowHandler(ConfigFlow, domain=DOMAIN):
else:
errors = {"base": "cannot_connect"}
except (ConnectTimeout, HTTPError):
except ConnectTimeout, HTTPError:
errors = {"base": "cannot_connect"}
if errors:
+2 -2
View File
@@ -99,7 +99,7 @@ class AbodeLight(AbodeDevice, LightEntity):
return _hs
@property
def color_mode(self) -> ColorMode | None:
def color_mode(self) -> ColorMode:
"""Return the color mode of the light."""
if self._device.is_dimmable and self._device.is_color_capable:
if self.hs_color is not None:
@@ -110,7 +110,7 @@ class AbodeLight(AbodeDevice, LightEntity):
return ColorMode.ONOFF
@property
def supported_color_modes(self) -> set[ColorMode] | None:
def supported_color_modes(self) -> set[ColorMode]:
"""Flag supported color modes."""
if self._device.is_dimmable and self._device.is_color_capable:
return {ColorMode.COLOR_TEMP, ColorMode.HS}
@@ -43,7 +43,7 @@ class AccuWeatherFlowHandler(ConfigFlow, domain=DOMAIN):
longitude=user_input[CONF_LONGITUDE],
)
await accuweather.async_get_location()
except (ApiError, ClientConnectorError, TimeoutError, ClientError):
except ApiError, ClientConnectorError, TimeoutError, ClientError:
errors["base"] = "cannot_connect"
except InvalidApiKeyError:
errors[CONF_API_KEY] = "invalid_api_key"
@@ -104,7 +104,7 @@ class AccuWeatherFlowHandler(ConfigFlow, domain=DOMAIN):
longitude=self._longitude,
)
await accuweather.async_get_location()
except (ApiError, ClientConnectorError, TimeoutError, ClientError):
except ApiError, ClientConnectorError, TimeoutError, ClientError:
errors["base"] = "cannot_connect"
except InvalidApiKeyError:
errors["base"] = "invalid_api_key"
@@ -18,7 +18,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .coordinator import ActronAirConfigEntry, ActronAirSystemCoordinator
from .entity import ActronAirAcEntity, ActronAirZoneEntity
from .entity import ActronAirAcEntity, ActronAirZoneEntity, handle_actron_api_errors
PARALLEL_UPDATES = 0
@@ -136,16 +136,19 @@ class ActronSystemClimate(ActronAirAcEntity, ActronAirClimateEntity):
"""Return the target temperature."""
return self._status.user_aircon_settings.temperature_setpoint_cool_c
@handle_actron_api_errors
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set a new fan mode."""
api_fan_mode = FAN_MODE_MAPPING_HA_TO_ACTRONAIR.get(fan_mode)
await self._status.user_aircon_settings.set_fan_mode(api_fan_mode)
@handle_actron_api_errors
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the HVAC mode."""
ac_mode = HVAC_MODE_MAPPING_HA_TO_ACTRONAIR.get(hvac_mode)
await self._status.ac_system.set_system_mode(ac_mode)
@handle_actron_api_errors
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the temperature."""
temp = kwargs.get(ATTR_TEMPERATURE)
@@ -209,11 +212,13 @@ class ActronZoneClimate(ActronAirZoneEntity, ActronAirClimateEntity):
"""Return the target temperature."""
return self._zone.temperature_setpoint_cool_c
@handle_actron_api_errors
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the HVAC mode."""
is_enabled = hvac_mode != HVACMode.OFF
await self._zone.enable(is_enabled)
@handle_actron_api_errors
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the temperature."""
await self._zone.set_temperature(temperature=kwargs.get(ATTR_TEMPERATURE))
+26 -1
View File
@@ -1,7 +1,12 @@
"""Base entity classes for Actron Air integration."""
from actron_neo_api import ActronAirZone
from collections.abc import Callable, Coroutine
from functools import wraps
from typing import Any, Concatenate
from actron_neo_api import ActronAirAPIError, ActronAirZone
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@@ -9,6 +14,26 @@ from .const import DOMAIN
from .coordinator import ActronAirSystemCoordinator
def handle_actron_api_errors[_EntityT: ActronAirEntity, **_P](
func: Callable[Concatenate[_EntityT, _P], Coroutine[Any, Any, Any]],
) -> Callable[Concatenate[_EntityT, _P], Coroutine[Any, Any, None]]:
"""Decorate Actron Air API calls to handle ActronAirAPIError exceptions."""
@wraps(func)
async def wrapper(self: _EntityT, *args: _P.args, **kwargs: _P.kwargs) -> None:
"""Wrap API calls with exception handling."""
try:
await func(self, *args, **kwargs)
except ActronAirAPIError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="api_error",
translation_placeholders={"error": str(err)},
) from err
return wrapper
class ActronAirEntity(CoordinatorEntity[ActronAirSystemCoordinator]):
"""Base class for Actron Air entities."""
@@ -26,7 +26,7 @@ rules:
unique-config-entry: done
# Silver
action-exceptions: todo
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters:
status: exempt
@@ -49,6 +49,9 @@
}
},
"exceptions": {
"api_error": {
"message": "Failed to communicate with Actron Air device: {error}"
},
"auth_error": {
"message": "Authentication failed, please reauthenticate"
},
+27 -13
View File
@@ -10,7 +10,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .coordinator import ActronAirConfigEntry, ActronAirSystemCoordinator
from .entity import ActronAirAcEntity
from .entity import ActronAirAcEntity, handle_actron_api_errors
PARALLEL_UPDATES = 0
@@ -29,30 +29,42 @@ SWITCHES: tuple[ActronAirSwitchEntityDescription, ...] = (
key="away_mode",
translation_key="away_mode",
is_on_fn=lambda coordinator: coordinator.data.user_aircon_settings.away_mode,
set_fn=lambda coordinator,
enabled: coordinator.data.user_aircon_settings.set_away_mode(enabled),
set_fn=lambda coordinator, enabled: (
coordinator.data.user_aircon_settings.set_away_mode(enabled)
),
),
ActronAirSwitchEntityDescription(
key="continuous_fan",
translation_key="continuous_fan",
is_on_fn=lambda coordinator: coordinator.data.user_aircon_settings.continuous_fan_enabled,
set_fn=lambda coordinator,
enabled: coordinator.data.user_aircon_settings.set_continuous_mode(enabled),
is_on_fn=lambda coordinator: (
coordinator.data.user_aircon_settings.continuous_fan_enabled
),
set_fn=lambda coordinator, enabled: (
coordinator.data.user_aircon_settings.set_continuous_mode(enabled)
),
),
ActronAirSwitchEntityDescription(
key="quiet_mode",
translation_key="quiet_mode",
is_on_fn=lambda coordinator: coordinator.data.user_aircon_settings.quiet_mode_enabled,
set_fn=lambda coordinator,
enabled: coordinator.data.user_aircon_settings.set_quiet_mode(enabled),
is_on_fn=lambda coordinator: (
coordinator.data.user_aircon_settings.quiet_mode_enabled
),
set_fn=lambda coordinator, enabled: (
coordinator.data.user_aircon_settings.set_quiet_mode(enabled)
),
),
ActronAirSwitchEntityDescription(
key="turbo_mode",
translation_key="turbo_mode",
is_on_fn=lambda coordinator: coordinator.data.user_aircon_settings.turbo_enabled,
set_fn=lambda coordinator,
enabled: coordinator.data.user_aircon_settings.set_turbo_mode(enabled),
is_supported_fn=lambda coordinator: coordinator.data.user_aircon_settings.turbo_supported,
is_on_fn=lambda coordinator: (
coordinator.data.user_aircon_settings.turbo_enabled
),
set_fn=lambda coordinator, enabled: (
coordinator.data.user_aircon_settings.set_turbo_mode(enabled)
),
is_supported_fn=lambda coordinator: (
coordinator.data.user_aircon_settings.turbo_supported
),
),
)
@@ -93,10 +105,12 @@ class ActronAirSwitch(ActronAirAcEntity, SwitchEntity):
"""Return true if the switch is on."""
return self.entity_description.is_on_fn(self.coordinator)
@handle_actron_api_errors
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
await self.entity_description.set_fn(self.coordinator, True)
@handle_actron_api_errors
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
await self.entity_description.set_fn(self.coordinator, False)
+67 -49
View File
@@ -20,9 +20,10 @@ from homeassistant.const import (
Platform,
)
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.exceptions import ConfigEntryNotReady, ServiceValidationError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.typing import ConfigType
from .const import (
CONF_FORCE,
@@ -45,6 +46,7 @@ SERVICE_REFRESH_SCHEMA = vol.Schema(
{vol.Optional(CONF_FORCE, default=False): cv.boolean}
)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
PLATFORMS = [Platform.SENSOR, Platform.SWITCH, Platform.UPDATE]
type AdGuardConfigEntry = ConfigEntry[AdGuardData]
@@ -57,6 +59,69 @@ class AdGuardData:
version: str
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the component."""
def _get_adguard_instances(hass: HomeAssistant) -> list[AdGuardHome]:
"""Get the AdGuardHome instances."""
entries: list[AdGuardConfigEntry] = hass.config_entries.async_loaded_entries(
DOMAIN
)
if not entries:
raise ServiceValidationError(
translation_domain=DOMAIN, translation_key="config_entry_not_loaded"
)
return [entry.runtime_data.client for entry in entries]
async def add_url(call: ServiceCall) -> None:
"""Service call to add a new filter subscription to AdGuard Home."""
for adguard in _get_adguard_instances(call.hass):
await adguard.filtering.add_url(
allowlist=False, name=call.data[CONF_NAME], url=call.data[CONF_URL]
)
async def remove_url(call: ServiceCall) -> None:
"""Service call to remove a filter subscription from AdGuard Home."""
for adguard in _get_adguard_instances(call.hass):
await adguard.filtering.remove_url(allowlist=False, url=call.data[CONF_URL])
async def enable_url(call: ServiceCall) -> None:
"""Service call to enable a filter subscription in AdGuard Home."""
for adguard in _get_adguard_instances(call.hass):
await adguard.filtering.enable_url(allowlist=False, url=call.data[CONF_URL])
async def disable_url(call: ServiceCall) -> None:
"""Service call to disable a filter subscription in AdGuard Home."""
for adguard in _get_adguard_instances(call.hass):
await adguard.filtering.disable_url(
allowlist=False, url=call.data[CONF_URL]
)
async def refresh(call: ServiceCall) -> None:
"""Service call to refresh the filter subscriptions in AdGuard Home."""
for adguard in _get_adguard_instances(call.hass):
await adguard.filtering.refresh(
allowlist=False, force=call.data[CONF_FORCE]
)
hass.services.async_register(
DOMAIN, SERVICE_ADD_URL, add_url, schema=SERVICE_ADD_URL_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_REMOVE_URL, remove_url, schema=SERVICE_URL_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_ENABLE_URL, enable_url, schema=SERVICE_URL_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_DISABLE_URL, disable_url, schema=SERVICE_URL_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_REFRESH, refresh, schema=SERVICE_REFRESH_SCHEMA
)
return True
async def async_setup_entry(hass: HomeAssistant, entry: AdGuardConfigEntry) -> bool:
"""Set up AdGuard Home from a config entry."""
session = async_get_clientsession(hass, entry.data[CONF_VERIFY_SSL])
@@ -79,56 +144,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: AdGuardConfigEntry) -> b
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
async def add_url(call: ServiceCall) -> None:
"""Service call to add a new filter subscription to AdGuard Home."""
await adguard.filtering.add_url(
allowlist=False, name=call.data[CONF_NAME], url=call.data[CONF_URL]
)
async def remove_url(call: ServiceCall) -> None:
"""Service call to remove a filter subscription from AdGuard Home."""
await adguard.filtering.remove_url(allowlist=False, url=call.data[CONF_URL])
async def enable_url(call: ServiceCall) -> None:
"""Service call to enable a filter subscription in AdGuard Home."""
await adguard.filtering.enable_url(allowlist=False, url=call.data[CONF_URL])
async def disable_url(call: ServiceCall) -> None:
"""Service call to disable a filter subscription in AdGuard Home."""
await adguard.filtering.disable_url(allowlist=False, url=call.data[CONF_URL])
async def refresh(call: ServiceCall) -> None:
"""Service call to refresh the filter subscriptions in AdGuard Home."""
await adguard.filtering.refresh(allowlist=False, force=call.data[CONF_FORCE])
hass.services.async_register(
DOMAIN, SERVICE_ADD_URL, add_url, schema=SERVICE_ADD_URL_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_REMOVE_URL, remove_url, schema=SERVICE_URL_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_ENABLE_URL, enable_url, schema=SERVICE_URL_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_DISABLE_URL, disable_url, schema=SERVICE_URL_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_REFRESH, refresh, schema=SERVICE_REFRESH_SCHEMA
)
return True
async def async_unload_entry(hass: HomeAssistant, entry: AdGuardConfigEntry) -> bool:
"""Unload AdGuard Home config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if not hass.config_entries.async_loaded_entries(DOMAIN):
# This is the last loaded instance of AdGuard, deregister any services
hass.services.async_remove(DOMAIN, SERVICE_ADD_URL)
hass.services.async_remove(DOMAIN, SERVICE_REMOVE_URL)
hass.services.async_remove(DOMAIN, SERVICE_ENABLE_URL)
hass.services.async_remove(DOMAIN, SERVICE_DISABLE_URL)
hass.services.async_remove(DOMAIN, SERVICE_REFRESH)
return unload_ok
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
@@ -76,6 +76,11 @@
}
}
},
"exceptions": {
"config_entry_not_loaded": {
"message": "Config entry not loaded."
}
},
"services": {
"add_url": {
"description": "Adds a new filter subscription to AdGuard Home.",
+11 -1
View File
@@ -7,10 +7,12 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN, SERVER_URL
from .services import async_setup_services
ATTRIBUTION = "ispyconnect.com"
DEFAULT_BRAND = "Agent DVR by ispyconnect.com"
@@ -19,6 +21,14 @@ PLATFORMS = [Platform.ALARM_CONTROL_PANEL, Platform.CAMERA]
AgentDVRConfigEntry = ConfigEntry[Agent]
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the component."""
async_setup_services(hass)
return True
async def async_setup_entry(
hass: HomeAssistant, config_entry: AgentDVRConfigEntry
+1 -22
View File
@@ -9,10 +9,7 @@ from homeassistant.components.camera import CameraEntityFeature
from homeassistant.components.mjpeg import MjpegCamera, filter_urllib3_logging
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
async_get_current_platform,
)
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import AgentDVRConfigEntry
from .const import ATTRIBUTION, CAMERA_SCAN_INTERVAL_SECS, DOMAIN
@@ -21,20 +18,6 @@ SCAN_INTERVAL = timedelta(seconds=CAMERA_SCAN_INTERVAL_SECS)
_LOGGER = logging.getLogger(__name__)
_DEV_EN_ALT = "enable_alerts"
_DEV_DS_ALT = "disable_alerts"
_DEV_EN_REC = "start_recording"
_DEV_DS_REC = "stop_recording"
_DEV_SNAP = "snapshot"
CAMERA_SERVICES = {
_DEV_EN_ALT: "async_enable_alerts",
_DEV_DS_ALT: "async_disable_alerts",
_DEV_EN_REC: "async_start_recording",
_DEV_DS_REC: "async_stop_recording",
_DEV_SNAP: "async_snapshot",
}
async def async_setup_entry(
hass: HomeAssistant,
@@ -57,10 +40,6 @@ async def async_setup_entry(
async_add_entities(cameras)
platform = async_get_current_platform()
for service, method in CAMERA_SERVICES.items():
platform.async_register_entity_service(service, None, method)
class AgentCamera(MjpegCamera):
"""Representation of an Agent Device Stream."""
@@ -0,0 +1,38 @@
"""Services for Agent DVR."""
from __future__ import annotations
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import service
from .const import DOMAIN
_DEV_EN_ALT = "enable_alerts"
_DEV_DS_ALT = "disable_alerts"
_DEV_EN_REC = "start_recording"
_DEV_DS_REC = "stop_recording"
_DEV_SNAP = "snapshot"
CAMERA_SERVICES = {
_DEV_EN_ALT: "async_enable_alerts",
_DEV_DS_ALT: "async_disable_alerts",
_DEV_EN_REC: "async_start_recording",
_DEV_DS_REC: "async_stop_recording",
_DEV_SNAP: "async_snapshot",
}
@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Home Assistant services."""
for service_name, method in CAMERA_SERVICES.items():
service.async_register_platform_entity_service(
hass,
DOMAIN,
service_name,
entity_domain=CAMERA_DOMAIN,
schema=None,
func=method,
)
@@ -133,8 +133,9 @@ CONTROL_ENTITIES: tuple[AirGradientSelectEntityDescription, ...] = (
value_fn=lambda config: _get_value(
config.co2_automatic_baseline_calibration_days, ABC_DAYS
),
set_value_fn=lambda client,
value: client.set_co2_automatic_baseline_calibration(int(value)),
set_value_fn=lambda client, value: (
client.set_co2_automatic_baseline_calibration(int(value))
),
),
)
+1 -1
View File
@@ -85,7 +85,7 @@ class AirobotButton(AirobotEntity, ButtonEntity):
"""Handle the button press."""
try:
await self.entity_description.press_fn(self.coordinator)
except (AirobotConnectionError, AirobotTimeoutError):
except AirobotConnectionError, AirobotTimeoutError:
# Connection errors during reboot are expected as device restarts
pass
except AirobotError as err:
@@ -114,7 +114,7 @@ class AirOSConfigFlow(ConfigFlow, domain=DOMAIN):
AirOSDeviceConnectionError,
):
self.errors["base"] = "cannot_connect"
except (AirOSConnectionAuthenticationError, AirOSDataMissingError):
except AirOSConnectionAuthenticationError, AirOSDataMissingError:
self.errors["base"] = "invalid_auth"
except AirOSKeyDataMissingError:
self.errors["base"] = "key_data_missing"
@@ -130,7 +130,7 @@ class AirVisualFlowHandler(ConfigFlow, domain=DOMAIN):
try:
await coro
except (InvalidKeyError, KeyExpiredError, UnauthorizedError):
except InvalidKeyError, KeyExpiredError, UnauthorizedError:
errors[CONF_API_KEY] = "invalid_api_key"
except NotFoundError:
errors[CONF_CITY] = "location_not_found"
@@ -100,7 +100,7 @@ class AirZoneCloudConfigFlow(ConfigFlow, domain=DOMAIN):
try:
await self.airzone.login()
except (AirzoneCloudError, LoginError):
except AirzoneCloudError, LoginError:
errors["base"] = "cannot_connect"
else:
return await self.async_step_inst_pick()
@@ -18,12 +18,15 @@ from homeassistant.const import (
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.typing import ConfigType
from .const import (
CONF_DEVICE_BAUD,
CONF_DEVICE_PATH,
DOMAIN,
PROTOCOL_SERIAL,
PROTOCOL_SOCKET,
SIGNAL_PANEL_MESSAGE,
@@ -32,9 +35,11 @@ from .const import (
SIGNAL_ZONE_FAULT,
SIGNAL_ZONE_RESTORE,
)
from .services import async_setup_services
_LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
PLATFORMS = [
Platform.ALARM_CONTROL_PANEL,
Platform.BINARY_SENSOR,
@@ -54,6 +59,12 @@ class AlarmDecoderData:
restart: bool
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the component."""
async_setup_services(hass)
return True
async def async_setup_entry(
hass: HomeAssistant, entry: AlarmDecoderConfigEntry
) -> bool:
@@ -2,17 +2,13 @@
from __future__ import annotations
import voluptuous as vol
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import ATTR_CODE
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
@@ -27,11 +23,6 @@ from .const import (
)
from .entity import AlarmDecoderEntity
SERVICE_ALARM_TOGGLE_CHIME = "alarm_toggle_chime"
SERVICE_ALARM_KEYPRESS = "alarm_keypress"
ATTR_KEYPRESS = "keypress"
async def async_setup_entry(
hass: HomeAssistant,
@@ -50,23 +41,6 @@ async def async_setup_entry(
)
async_add_entities([entity])
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_ALARM_TOGGLE_CHIME,
{
vol.Required(ATTR_CODE): cv.string,
},
"alarm_toggle_chime",
)
platform.async_register_entity_service(
SERVICE_ALARM_KEYPRESS,
{
vol.Required(ATTR_KEYPRESS): cv.string,
},
"alarm_keypress",
)
class AlarmDecoderAlarmPanel(AlarmDecoderEntity, AlarmControlPanelEntity):
"""Representation of an AlarmDecoder-based alarm panel."""
@@ -0,0 +1,46 @@
"""Support for AlarmDecoder-based alarm control panels (Honeywell/DSC)."""
from __future__ import annotations
import voluptuous as vol
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
)
from homeassistant.const import ATTR_CODE
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, service
from .const import DOMAIN
SERVICE_ALARM_TOGGLE_CHIME = "alarm_toggle_chime"
SERVICE_ALARM_KEYPRESS = "alarm_keypress"
ATTR_KEYPRESS = "keypress"
@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Home Assistant services."""
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_ALARM_TOGGLE_CHIME,
entity_domain=ALARM_CONTROL_PANEL_DOMAIN,
schema={
vol.Required(ATTR_CODE): cv.string,
},
func="alarm_toggle_chime",
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_ALARM_KEYPRESS,
entity_domain=ALARM_CONTROL_PANEL_DOMAIN,
schema={
vol.Required(ATTR_KEYPRESS): cv.string,
},
func="alarm_keypress",
)
+1 -1
View File
@@ -123,7 +123,7 @@ class Auth:
allow_redirects=True,
)
except (TimeoutError, aiohttp.ClientError):
except TimeoutError, aiohttp.ClientError:
_LOGGER.error("Timeout calling LWA to get auth token")
return None
@@ -358,7 +358,7 @@ async def async_send_changereport_message(
"""
try:
token = await config.async_get_access_token()
except (RequireRelink, NoTokenAvailable):
except RequireRelink, NoTokenAvailable:
await config.set_authorized(False)
_LOGGER.error(
"Error when sending ChangeReport to Alexa, could not get access token"
@@ -392,7 +392,7 @@ async def async_send_changereport_message(
allow_redirects=True,
)
except (TimeoutError, aiohttp.ClientError):
except TimeoutError, aiohttp.ClientError:
_LOGGER.error("Timeout sending report to Alexa for %s", alexa_entity.entity_id)
return
@@ -549,7 +549,7 @@ async def async_send_doorbell_event_message(
allow_redirects=True,
)
except (TimeoutError, aiohttp.ClientError):
except TimeoutError, aiohttp.ClientError:
_LOGGER.error("Timeout sending report to Alexa for %s", alexa_entity.entity_id)
return
@@ -29,3 +29,24 @@ COUNTRY_DOMAINS = {
CATEGORY_SENSORS = "sensors"
CATEGORY_NOTIFICATIONS = "notifications"
# Map service translation keys to Alexa API
INFO_SKILLS_MAPPING = {
"calendar_today": "Alexa.Calendar.PlayToday",
"calendar_tomorrow": "Alexa.Calendar.PlayTomorrow",
"calendar_next": "Alexa.Calendar.PlayNext",
"date": "Alexa.Date.Play",
"time": "Alexa.Time.Play",
"national_news": "Alexa.News.NationalNews",
"flash_briefing": "Alexa.FlashBriefing.Play",
"traffic": "Alexa.Traffic.Play",
"weather": "Alexa.Weather.Play",
"cleanup": "Alexa.CleanUp.Play",
"good_morning": "Alexa.GoodMorning.Play",
"sing_song": "Alexa.SingASong.Play",
"fun_fact": "Alexa.FunFact.Play",
"tell_joke": "Alexa.Joke.Play",
"tell_story": "Alexa.TellStory.Play",
"im_home": "Alexa.ImHome.Play",
"goodnight": "Alexa.GoodNight.Play",
}
@@ -1,5 +1,8 @@
{
"services": {
"send_info_skill": {
"service": "mdi:information"
},
"send_sound": {
"service": "mdi:cast-audio"
},
@@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["aioamazondevices"],
"quality_scale": "platinum",
"requirements": ["aioamazondevices==11.0.2"]
"requirements": ["aioamazondevices==12.0.0"]
}
@@ -28,6 +28,7 @@ from homeassistant.helpers.typing import StateType
from .const import CATEGORY_NOTIFICATIONS, CATEGORY_SENSORS
from .coordinator import AmazonConfigEntry
from .entity import AmazonEntity
from .utils import async_remove_unsupported_notification_sensors
# Coordinator is used to centralize the data updates
PARALLEL_UPDATES = 0
@@ -105,6 +106,9 @@ async def async_setup_entry(
coordinator = entry.runtime_data
# Remove notification sensors from unsupported devices
await async_remove_unsupported_notification_sensors(hass, coordinator)
known_devices: set[str] = set()
def _check_device() -> None:
@@ -122,6 +126,7 @@ async def async_setup_entry(
AmazonSensorEntity(coordinator, serial_num, notification_desc)
for notification_desc in NOTIFICATIONS
for serial_num in new_devices
if coordinator.data[serial_num].notifications_supported
]
async_add_entities(sensors_list + notifications_list)
@@ -1,5 +1,6 @@
"""Support for services."""
from aioamazondevices.const.metadata import ALEXA_INFO_SKILLS
from aioamazondevices.const.sounds import SOUNDS_LIST
import voluptuous as vol
@@ -9,13 +10,15 @@ from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import config_validation as cv, device_registry as dr
from .const import DOMAIN
from .const import DOMAIN, INFO_SKILLS_MAPPING
from .coordinator import AmazonConfigEntry
ATTR_TEXT_COMMAND = "text_command"
ATTR_SOUND = "sound"
ATTR_INFO_SKILL = "info_skill"
SERVICE_TEXT_COMMAND = "send_text_command"
SERVICE_SOUND_NOTIFICATION = "send_sound"
SERVICE_INFO_SKILL = "send_info_skill"
SCHEMA_SOUND_SERVICE = vol.Schema(
{
@@ -29,6 +32,12 @@ SCHEMA_CUSTOM_COMMAND = vol.Schema(
vol.Required(ATTR_DEVICE_ID): cv.string,
}
)
SCHEMA_INFO_SKILL = vol.Schema(
{
vol.Required(ATTR_INFO_SKILL): cv.string,
vol.Required(ATTR_DEVICE_ID): cv.string,
}
)
@callback
@@ -86,6 +95,17 @@ async def _async_execute_action(call: ServiceCall, attribute: str) -> None:
await coordinator.api.call_alexa_text_command(
coordinator.data[device.serial_number], value
)
elif attribute == ATTR_INFO_SKILL:
info_skill = INFO_SKILLS_MAPPING.get(value)
if info_skill not in ALEXA_INFO_SKILLS:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="invalid_info_skill_value",
translation_placeholders={"info_skill": value},
)
await coordinator.api.call_alexa_info_skill(
coordinator.data[device.serial_number], value
)
async def async_send_sound_notification(call: ServiceCall) -> None:
@@ -98,6 +118,11 @@ async def async_send_text_command(call: ServiceCall) -> None:
await _async_execute_action(call, ATTR_TEXT_COMMAND)
async def async_send_info_skill(call: ServiceCall) -> None:
"""Send an info skill command to a AmazonDevice."""
await _async_execute_action(call, ATTR_INFO_SKILL)
@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Set up the services for the Amazon Devices integration."""
@@ -112,5 +137,10 @@ def async_setup_services(hass: HomeAssistant) -> None:
async_send_text_command,
SCHEMA_CUSTOM_COMMAND,
),
(
SERVICE_INFO_SKILL,
async_send_info_skill,
SCHEMA_INFO_SKILL,
),
):
hass.services.async_register(DOMAIN, service_name, method, schema=schema)
@@ -67,3 +67,36 @@ send_sound:
- squeaky_12
- zap_01
translation_key: sound
send_info_skill:
fields:
device_id:
required: true
selector:
device:
integration: alexa_devices
info_skill:
required: true
example: date
default: date
selector:
select:
options:
- calendar_today
- calendar_tomorrow
- calendar_next
- date
- time
- national_news
- flash_briefing
- traffic
- weather
- cleanup
- good_morning
- sing_song
- fun_fact
- tell_joke
- tell_story
- im_home
- goodnight
translation_key: info_skill
@@ -90,6 +90,9 @@
"cannot_retrieve_data_with_error": {
"message": "Error retrieving data: {error}"
},
"config_entry_not_found": {
"message": "Config entry not found: {device_id}"
},
"device_serial_number_missing": {
"message": "Device serial number missing: {device_id}"
},
@@ -99,11 +102,35 @@
"invalid_device_id": {
"message": "Invalid device ID specified: {device_id}"
},
"invalid_info_skill_value": {
"message": "Invalid info skill {info_skill} specified"
},
"invalid_sound_value": {
"message": "Invalid sound {sound} specified"
}
},
"selector": {
"info_skill": {
"options": {
"calendar_next": "Calendar: Next event",
"calendar_today": "Calendar: Today's Calendar",
"calendar_tomorrow": "Calendar: Tomorrow's Calendar",
"cleanup": "Encourage me to clean up",
"date": "Date",
"flash_briefing": "Flash Briefing",
"fun_fact": "Tell me a fun fact",
"good_morning": "Good morning",
"goodnight": "Wish me a good night",
"im_home": "Welcome me home",
"national_news": "National News",
"sing_song": "Sing a song",
"tell_joke": "Tell me a joke",
"tell_story": "Tell me a story",
"time": "Time",
"traffic": "Traffic",
"weather": "Weather"
}
},
"sound": {
"options": {
"air_horn_03": "Air horn",
@@ -151,6 +178,20 @@
}
},
"services": {
"send_info_skill": {
"description": "Sends an info skill command to a device",
"fields": {
"device_id": {
"description": "[%key:component::alexa_devices::common::device_id_description%]",
"name": "Device"
},
"info_skill": {
"description": "The info skill command to send.",
"name": "Alexa info skill command"
}
},
"name": "Send info skill command"
},
"send_sound": {
"description": "Sends a sound to a device",
"fields": {
@@ -59,13 +59,15 @@ async def async_setup_entry(
coordinator = entry.runtime_data
# Replace unique id for "DND" switch and remove from Speaker Group
await async_update_unique_id(
hass, coordinator, SWITCH_DOMAIN, "do_not_disturb", "dnd"
)
# DND keys
old_key = "do_not_disturb"
new_key = "dnd"
# Remove DND switch from virtual groups
await async_remove_dnd_from_virtual_group(hass, coordinator)
# Remove old DND switch from virtual groups
await async_remove_dnd_from_virtual_group(hass, coordinator, old_key)
# Replace unique id for DND switch
await async_update_unique_id(hass, coordinator, SWITCH_DOMAIN, old_key, new_key)
known_devices: set[str] = set()
@@ -5,8 +5,14 @@ from functools import wraps
from typing import Any, Concatenate
from aioamazondevices.const.devices import SPEAKER_GROUP_FAMILY
from aioamazondevices.const.schedules import (
NOTIFICATION_ALARM,
NOTIFICATION_REMINDER,
NOTIFICATION_TIMER,
)
from aioamazondevices.exceptions import CannotConnect, CannotRetrieveData
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
@@ -48,7 +54,7 @@ def alexa_api_call[_T: AmazonEntity, **_P](
async def async_update_unique_id(
hass: HomeAssistant,
coordinator: AmazonDevicesCoordinator,
domain: str,
platform: str,
old_key: str,
new_key: str,
) -> None:
@@ -57,7 +63,9 @@ async def async_update_unique_id(
for serial_num in coordinator.data:
unique_id = f"{serial_num}-{old_key}"
if entity_id := entity_registry.async_get_entity_id(domain, DOMAIN, unique_id):
if entity_id := entity_registry.async_get_entity_id(
DOMAIN, platform, unique_id
):
_LOGGER.debug("Updating unique_id for %s", entity_id)
new_unique_id = unique_id.replace(old_key, new_key)
@@ -68,12 +76,13 @@ async def async_update_unique_id(
async def async_remove_dnd_from_virtual_group(
hass: HomeAssistant,
coordinator: AmazonDevicesCoordinator,
key: str,
) -> None:
"""Remove entity DND from virtual group."""
entity_registry = er.async_get(hass)
for serial_num in coordinator.data:
unique_id = f"{serial_num}-do_not_disturb"
unique_id = f"{serial_num}-{key}"
entity_id = entity_registry.async_get_entity_id(
DOMAIN, SWITCH_DOMAIN, unique_id
)
@@ -81,3 +90,27 @@ async def async_remove_dnd_from_virtual_group(
if entity_id and is_group:
entity_registry.async_remove(entity_id)
_LOGGER.debug("Removed DND switch from virtual group %s", entity_id)
async def async_remove_unsupported_notification_sensors(
hass: HomeAssistant,
coordinator: AmazonDevicesCoordinator,
) -> None:
"""Remove notification sensors from unsupported devices."""
entity_registry = er.async_get(hass)
for serial_num in coordinator.data:
for notification_key in (
NOTIFICATION_ALARM,
NOTIFICATION_REMINDER,
NOTIFICATION_TIMER,
):
unique_id = f"{serial_num}-{notification_key}"
entity_id = entity_registry.async_get_entity_id(
DOMAIN, SENSOR_DOMAIN, unique_id=unique_id
)
is_unsupported = not coordinator.data[serial_num].notifications_supported
if entity_id and is_unsupported:
entity_registry.async_remove(entity_id)
_LOGGER.debug("Removed unsupported notification sensor %s", entity_id)
@@ -3,7 +3,6 @@
from amberelectric.models.channel import ChannelType
import voluptuous as vol
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ATTR_CONFIG_ENTRY_ID
from homeassistant.core import (
HomeAssistant,
@@ -13,6 +12,7 @@ from homeassistant.core import (
callback,
)
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import service
from homeassistant.helpers.selector import ConfigEntrySelector
from homeassistant.util.json import JsonValueType
@@ -37,23 +37,6 @@ GET_FORECASTS_SCHEMA = vol.Schema(
)
def async_get_entry(hass: HomeAssistant, config_entry_id: str) -> AmberConfigEntry:
"""Get the Amber config entry."""
if not (entry := hass.config_entries.async_get_entry(config_entry_id)):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="integration_not_found",
translation_placeholders={"target": config_entry_id},
)
if entry.state is not ConfigEntryState.LOADED:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="not_loaded",
translation_placeholders={"target": entry.title},
)
return entry
def get_forecasts(channel_type: str, data: dict) -> list[JsonValueType]:
"""Return an array of forecasts."""
results: list[JsonValueType] = []
@@ -109,7 +92,9 @@ def async_setup_services(hass: HomeAssistant) -> None:
async def handle_get_forecasts(call: ServiceCall) -> ServiceResponse:
channel_type = call.data[ATTR_CHANNEL_TYPE]
entry = async_get_entry(hass, call.data[ATTR_CONFIG_ENTRY_ID])
entry: AmberConfigEntry = service.async_get_config_entry(
hass, DOMAIN, call.data[ATTR_CONFIG_ENTRY_ID]
)
coordinator = entry.runtime_data
forecasts = get_forecasts(channel_type, coordinator.data)
return {"forecasts": forecasts}
@@ -25,12 +25,6 @@
"exceptions": {
"channel_not_found": {
"message": "There is no {channel_type} channel at this site."
},
"integration_not_found": {
"message": "Config entry \"{target}\" not found in registry."
},
"not_loaded": {
"message": "{target} is not loaded."
}
},
"selector": {
@@ -77,9 +77,11 @@ class AmbientNetworkConfigFlow(ConfigFlow, domain=DOMAIN):
# Filter out indoor stations
self._stations = dict(
filter(
lambda item: not item[1]
.get(API_STATION_INFO, {})
.get(API_STATION_INDOOR, False),
lambda item: (
not item[1]
.get(API_STATION_INFO, {})
.get(API_STATION_INDOOR, False)
),
self._stations.items(),
)
)
@@ -113,7 +115,7 @@ class AmbientNetworkConfigFlow(ConfigFlow, domain=DOMAIN):
)
return self.async_show_form(
step_id=CONF_USER, data_schema=schema, errors=errors if errors else {}
step_id=CONF_USER, data_schema=schema, errors=errors or {}
)
async def async_step_station(
@@ -31,7 +31,7 @@ class AmbientStationFlowHandler(ConfigFlow, domain=DOMAIN):
return self.async_show_form(
step_id="user",
data_schema=self.data_schema,
errors=errors if errors else {},
errors=errors or {},
)
async def async_step_user(
@@ -26,21 +26,26 @@ from homeassistant.const import (
UnitOfVolumetricFlux,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import AmbientStation, AmbientStationConfigEntry
from . import AmbientStationConfigEntry
from .const import ATTR_LAST_DATA, TYPE_SOLARRADIATION, TYPE_SOLARRADIATION_LX
from .entity import AmbientWeatherEntity
TYPE_24HOURRAININ = "24hourrainin"
TYPE_AQI_PM10_24H_AQIN = "aqi_pm10_24h_aqin"
TYPE_AQI_PM10_AQIN = "aqi_pm10_aqin"
TYPE_AQI_PM25 = "aqi_pm25"
TYPE_AQI_PM25_24H = "aqi_pm25_24h"
TYPE_AQI_PM25_24H_AQIN = "aqi_pm25_24h_aqin"
TYPE_AQI_PM25_AQIN = "aqi_pm25_aqin"
TYPE_AQI_PM25_IN = "aqi_pm25_in"
TYPE_AQI_PM25_IN_24H = "aqi_pm25_in_24h"
TYPE_BAROMABSIN = "baromabsin"
TYPE_BAROMRELIN = "baromrelin"
TYPE_CO2 = "co2"
TYPE_CO2_IN_24H_AQIN = "co2_in_24h_aqin"
TYPE_CO2_IN_AQIN = "co2_in_aqin"
TYPE_DAILYRAININ = "dailyrainin"
TYPE_DEWPOINT = "dewPoint"
TYPE_EVENTRAININ = "eventrainin"
@@ -58,17 +63,23 @@ TYPE_HUMIDITY7 = "humidity7"
TYPE_HUMIDITY8 = "humidity8"
TYPE_HUMIDITY9 = "humidity9"
TYPE_HUMIDITYIN = "humidityin"
TYPE_LASTLIGHTNING = "lightning_time"
TYPE_LASTLIGHTNING_DISTANCE = "lightning_distance"
TYPE_LASTRAIN = "lastRain"
TYPE_LIGHTNING_PER_DAY = "lightning_day"
TYPE_LIGHTNING_PER_HOUR = "lightning_hour"
TYPE_LASTLIGHTNING_DISTANCE = "lightning_distance"
TYPE_LASTLIGHTNING = "lightning_time"
TYPE_MAXDAILYGUST = "maxdailygust"
TYPE_MONTHLYRAININ = "monthlyrainin"
TYPE_PM_IN_HUMIDITY_AQIN = "pm_in_humidity_aqin"
TYPE_PM_IN_TEMP_AQIN = "pm_in_temp_aqin"
TYPE_PM10_IN_24H_AQIN = "pm10_in_24h_aqin"
TYPE_PM10_IN_AQIN = "pm10_in_aqin"
TYPE_PM25 = "pm25"
TYPE_PM25_24H = "pm25_24h"
TYPE_PM25_IN = "pm25_in"
TYPE_PM25_IN_24H = "pm25_in_24h"
TYPE_PM25_IN_24H_AQIN = "pm25_in_24h_aqin"
TYPE_PM25_IN_AQIN = "pm25_in_aqin"
TYPE_SOILHUM1 = "soilhum1"
TYPE_SOILHUM10 = "soilhum10"
TYPE_SOILHUM2 = "soilhum2"
@@ -79,8 +90,8 @@ TYPE_SOILHUM6 = "soilhum6"
TYPE_SOILHUM7 = "soilhum7"
TYPE_SOILHUM8 = "soilhum8"
TYPE_SOILHUM9 = "soilhum9"
TYPE_SOILTEMP1F = "soiltemp1f"
TYPE_SOILTEMP10F = "soiltemp10f"
TYPE_SOILTEMP1F = "soiltemp1f"
TYPE_SOILTEMP2F = "soiltemp2f"
TYPE_SOILTEMP3F = "soiltemp3f"
TYPE_SOILTEMP4F = "soiltemp4f"
@@ -144,6 +155,86 @@ SENSOR_DESCRIPTIONS = (
translation_key="pm25_indoor_aqi_24h_average",
device_class=SensorDeviceClass.AQI,
),
SensorEntityDescription(
key=TYPE_PM25_IN_AQIN,
translation_key="pm25_indoor_aqin",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM25,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_PM25_IN_24H_AQIN,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
translation_key="pm25_indoor_24h_aqin",
device_class=SensorDeviceClass.PM25,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_PM10_IN_AQIN,
translation_key="pm10_indoor_aqin",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM10,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_PM10_IN_24H_AQIN,
translation_key="pm10_indoor_24h_aqin",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM10,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_CO2_IN_AQIN,
translation_key="co2_indoor_aqin",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
device_class=SensorDeviceClass.CO2,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_CO2_IN_24H_AQIN,
translation_key="co2_indoor_24h_aqin",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
device_class=SensorDeviceClass.CO2,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_PM_IN_TEMP_AQIN,
translation_key="pm_indoor_temp_aqin",
native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_PM_IN_HUMIDITY_AQIN,
translation_key="pm_indoor_humidity_aqin",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_AQI_PM25_AQIN,
translation_key="pm25_aqi_aqin",
device_class=SensorDeviceClass.AQI,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_AQI_PM25_24H_AQIN,
translation_key="pm25_aqi_24h_aqin",
device_class=SensorDeviceClass.AQI,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_AQI_PM10_AQIN,
translation_key="pm10_aqi_aqin",
device_class=SensorDeviceClass.AQI,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_AQI_PM10_24H_AQIN,
translation_key="pm10_aqi_24h_aqin",
device_class=SensorDeviceClass.AQI,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_BAROMABSIN,
translation_key="absolute_pressure",
@@ -683,22 +774,6 @@ async def async_setup_entry(
class AmbientWeatherSensor(AmbientWeatherEntity, SensorEntity):
"""Define an Ambient sensor."""
def __init__(
self,
ambient: AmbientStation,
mac_address: str,
station_name: str,
description: EntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(ambient, mac_address, station_name, description)
if description.key == TYPE_SOLARRADIATION_LX:
# Since TYPE_SOLARRADIATION and TYPE_SOLARRADIATION_LX will have the same
# name in the UI, we influence the entity ID of TYPE_SOLARRADIATION_LX here
# to differentiate them:
self.entity_id = f"sensor.{station_name}_solar_rad_lx"
@callback
def update_from_latest_data(self) -> None:
"""Fetch new state data for the sensor."""
@@ -156,6 +156,12 @@
"absolute_pressure": {
"name": "Absolute pressure"
},
"co2_indoor_24h_aqin": {
"name": "CO2 Indoor 24h Average AQIN"
},
"co2_indoor_aqin": {
"name": "CO2 Indoor AQIN"
},
"daily_rain": {
"name": "Daily rain"
},
@@ -228,18 +234,39 @@
"monthly_rain": {
"name": "Monthly rain"
},
"pm10_aqi_24h_aqin": {
"name": "PM10 Indoor AQI 24h Average AQIN"
},
"pm10_aqi_aqin": {
"name": "PM10 Indoor AQI AQIN"
},
"pm10_indoor_24h_aqin": {
"name": "PM10 Indoor 24h Average AQIN"
},
"pm10_indoor_aqin": {
"name": "PM10 Indoor AQIN"
},
"pm25_24h_average": {
"name": "PM2.5 24 hour average"
},
"pm25_aqi": {
"name": "PM2.5 AQI"
},
"pm25_aqi_24h_aqin": {
"name": "PM2.5 Indoor AQI 24h Average AQIN"
},
"pm25_aqi_24h_average": {
"name": "PM2.5 AQI 24 hour average"
},
"pm25_aqi_aqin": {
"name": "PM2.5 Indoor AQI AQIN"
},
"pm25_indoor": {
"name": "PM2.5 indoor"
},
"pm25_indoor_24h_aqin": {
"name": "PM2.5 Indoor 24h AQIN"
},
"pm25_indoor_24h_average": {
"name": "PM2.5 indoor 24 hour average"
},
@@ -249,6 +276,15 @@
"pm25_indoor_aqi_24h_average": {
"name": "PM2.5 indoor AQI"
},
"pm25_indoor_aqin": {
"name": "PM2.5 Indoor AQIN"
},
"pm_indoor_humidity_aqin": {
"name": "Indoor Humidity AQIN"
},
"pm_indoor_temp_aqin": {
"name": "Indoor Temperature AQIN"
},
"relative_pressure": {
"name": "Relative pressure"
},
+3 -3
View File
@@ -3,7 +3,7 @@
from __future__ import annotations
import asyncio
from collections.abc import AsyncIterator, Callable
from collections.abc import AsyncGenerator, Callable
from contextlib import asynccontextmanager, suppress
from dataclasses import dataclass
from datetime import datetime, timedelta
@@ -202,7 +202,7 @@ class AmcrestChecker(ApiWrapper):
@asynccontextmanager
async def async_stream_command(
self, *args: Any, **kwargs: Any
) -> AsyncIterator[httpx.Response]:
) -> AsyncGenerator[httpx.Response]:
"""amcrest.ApiWrapper.command wrapper to catch errors."""
async with (
self._async_command_wrapper(),
@@ -211,7 +211,7 @@ class AmcrestChecker(ApiWrapper):
yield ret
@asynccontextmanager
async def _async_command_wrapper(self) -> AsyncIterator[None]:
async def _async_command_wrapper(self) -> AsyncGenerator[None]:
try:
yield
except LoginError as ex:
+4 -14
View File
@@ -73,31 +73,21 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
started = False
async def _async_handle_labs_update(
event: Event[labs.EventLabsUpdatedData],
event_data: labs.EventLabsUpdatedData,
) -> None:
"""Handle labs feature toggle."""
await analytics.save_preferences({ATTR_SNAPSHOTS: event.data["enabled"]})
await analytics.save_preferences({ATTR_SNAPSHOTS: event_data["enabled"]})
if started:
await analytics.async_schedule()
@callback
def _async_labs_event_filter(event_data: labs.EventLabsUpdatedData) -> bool:
"""Filter labs events for this integration's snapshot feature."""
return (
event_data["domain"] == DOMAIN
and event_data["preview_feature"] == LABS_SNAPSHOT_FEATURE
)
async def start_schedule(_event: Event) -> None:
"""Start the send schedule after the started event."""
nonlocal started
started = True
await analytics.async_schedule()
hass.bus.async_listen(
labs.EVENT_LABS_UPDATED,
_async_handle_labs_update,
event_filter=_async_labs_event_filter,
labs.async_subscribe_preview_feature(
hass, DOMAIN, LABS_SNAPSHOT_FEATURE, _async_handle_labs_update
)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, start_schedule)
@@ -10,6 +10,7 @@
"preview_features": {
"snapshots": {
"feedback_url": "https://forms.gle/GqvRmgmghSDco8M46",
"learn_more_url": "https://www.home-assistant.io/blog/2026/02/02/about-device-database/",
"report_issue_url": "https://github.com/OHF-Device-Database/device-database/issues/new"
}
},
@@ -1,7 +1,7 @@
{
"preview_features": {
"snapshots": {
"description": "This free, open source device database of the Open Home Foundation helps users find useful information about smart home devices used in real installations.\n\nYou can help build it by anonymously sharing data about your devices. Only device-specific details (like model or manufacturer) are shared — never personally identifying information (like the names you assign).\n\nLearn more about the device database and how we process your data in our [Data Use Statement](https://www.openhomefoundation.org/device-database-data-use-statement), which you accept by opting in.",
"description": "We're creating the [Open Home Foundation Device Database](https://www.home-assistant.io/blog/2026/02/02/about-device-database/): a free, open source community-powered resource to help users find practical information about how smart home devices perform in real installations.\n\nYou can help us build it by opting in to share anonymized data about your devices. This data will only ever include device-specific details (like model or manufacturer) never personally identifying information (like the names you assign).\n\nFind out how we process your data (should you choose to contribute) in our [Data Use Statement](https://www.openhomefoundation.org/device-database-data-use-statement).",
"disable_confirmation": "Your data will no longer be shared with the Open Home Foundation's device database.",
"enable_confirmation": "This feature is still in development and may change. The device database is being refined based on user feedback and is not yet complete.",
"name": "Device database"
@@ -93,7 +93,7 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
self._abort_if_unique_id_configured(updates={CONF_HOST: self.host})
try:
return await self._async_start_pair()
except (CannotConnect, ConnectionClosed):
except CannotConnect, ConnectionClosed:
errors["base"] = "cannot_connect"
else:
user_input = {}
@@ -135,7 +135,7 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
# Attempt to pair again.
try:
return await self._async_start_pair()
except (CannotConnect, ConnectionClosed):
except CannotConnect, ConnectionClosed:
# Device doesn't respond to the specified host. Abort.
# If we are in the user flow we could go back to the user step to allow
# them to enter a new IP address but we cannot do that for the zeroconf
@@ -203,7 +203,7 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
if user_input is not None:
try:
return await self._async_start_pair()
except (CannotConnect, ConnectionClosed):
except CannotConnect, ConnectionClosed:
# Device became network unreachable after discovery.
# Abort and let discovery find it again later.
return self.async_abort(reason="cannot_connect")
@@ -229,7 +229,7 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
if user_input is not None:
try:
return await self._async_start_pair()
except (CannotConnect, ConnectionClosed):
except CannotConnect, ConnectionClosed:
# Device is network unreachable. Abort.
errors["base"] = "cannot_connect"
return self.async_show_form(
@@ -264,7 +264,7 @@ class AndroidTVRemoteOptionsFlowHandler(OptionsFlowWithReload):
@callback
def _save_config(self, data: dict[str, Any]) -> ConfigFlowResult:
"""Save the updated options."""
new_data = {k: v for k, v in data.items() if k not in [CONF_APPS]}
new_data = {k: v for k, v in data.items() if k != CONF_APPS}
if self._apps:
new_data[CONF_APPS] = self._apps
@@ -73,7 +73,7 @@ async def validate_account(auth: MSOB2CAuth, account_number: str) -> str | MSOB2
_aw = AnglianWater(authenticator=auth)
try:
await _aw.validate_smart_meter(account_number)
except (InvalidAccountIdError, SmartMeterUnavailableError):
except InvalidAccountIdError, SmartMeterUnavailableError:
return "smart_meter_unavailable"
return auth
+34 -5
View File
@@ -2,8 +2,6 @@
from __future__ import annotations
from functools import partial
import anthropic
from homeassistant.config_entries import ConfigEntry, ConfigSubentry
@@ -14,10 +12,19 @@ from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
entity_registry as er,
issue_registry as ir,
)
from homeassistant.helpers.httpx_client import get_async_client
from homeassistant.helpers.typing import ConfigType
from .const import DEFAULT_CONVERSATION_NAME, DOMAIN, LOGGER
from .const import (
CONF_CHAT_MODEL,
DATA_REPAIR_DEFER_RELOAD,
DEFAULT_CONVERSATION_NAME,
DEPRECATED_MODELS,
DOMAIN,
LOGGER,
)
PLATFORMS = (Platform.AI_TASK, Platform.CONVERSATION)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
@@ -27,14 +34,15 @@ type AnthropicConfigEntry = ConfigEntry[anthropic.AsyncClient]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Anthropic."""
hass.data.setdefault(DOMAIN, {}).setdefault(DATA_REPAIR_DEFER_RELOAD, set())
await async_migrate_integration(hass)
return True
async def async_setup_entry(hass: HomeAssistant, entry: AnthropicConfigEntry) -> bool:
"""Set up Anthropic from a config entry."""
client = await hass.async_add_executor_job(
partial(anthropic.AsyncAnthropic, api_key=entry.data[CONF_API_KEY])
client = anthropic.AsyncAnthropic(
api_key=entry.data[CONF_API_KEY], http_client=get_async_client(hass)
)
try:
await client.models.list(timeout=10.0)
@@ -50,6 +58,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: AnthropicConfigEntry) ->
entry.async_on_unload(entry.add_update_listener(async_update_options))
for subentry in entry.subentries.values():
if (model := subentry.data.get(CONF_CHAT_MODEL)) and model.startswith(
tuple(DEPRECATED_MODELS)
):
ir.async_create_issue(
hass,
DOMAIN,
"model_deprecated",
is_fixable=True,
is_persistent=False,
learn_more_url="https://platform.claude.com/docs/en/about-claude/model-deprecations",
severity=ir.IssueSeverity.WARNING,
translation_key="model_deprecated",
)
break
return True
@@ -62,6 +86,11 @@ async def async_update_options(
hass: HomeAssistant, entry: AnthropicConfigEntry
) -> None:
"""Update options."""
defer_reload_entries: set[str] = hass.data.setdefault(DOMAIN, {}).setdefault(
DATA_REPAIR_DEFER_RELOAD, set()
)
if entry.entry_id in defer_reload_entries:
return
await hass.config_entries.async_reload(entry.entry_id)
@@ -2,7 +2,6 @@
from __future__ import annotations
from functools import partial
import json
import logging
import re
@@ -30,12 +29,14 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import llm
from homeassistant.helpers.httpx_client import get_async_client
from homeassistant.helpers.selector import (
NumberSelector,
NumberSelectorConfig,
SelectOptionDict,
SelectSelector,
SelectSelectorConfig,
SelectSelectorMode,
TemplateSelector,
)
from homeassistant.helpers.typing import VolDictType
@@ -47,6 +48,7 @@ from .const import (
CONF_RECOMMENDED,
CONF_TEMPERATURE,
CONF_THINKING_BUDGET,
CONF_THINKING_EFFORT,
CONF_WEB_SEARCH,
CONF_WEB_SEARCH_CITY,
CONF_WEB_SEARCH_COUNTRY,
@@ -58,6 +60,7 @@ from .const import (
DEFAULT_AI_TASK_NAME,
DEFAULT_CONVERSATION_NAME,
DOMAIN,
NON_ADAPTIVE_THINKING_MODELS,
NON_THINKING_MODELS,
WEB_SEARCH_UNSUPPORTED_MODELS,
)
@@ -86,12 +89,47 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> None:
Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
"""
client = await hass.async_add_executor_job(
partial(anthropic.AsyncAnthropic, api_key=data[CONF_API_KEY])
client = anthropic.AsyncAnthropic(
api_key=data[CONF_API_KEY], http_client=get_async_client(hass)
)
await client.models.list(timeout=10.0)
async def get_model_list(client: anthropic.AsyncAnthropic) -> list[SelectOptionDict]:
"""Get list of available models."""
try:
models = (await client.models.list()).data
except anthropic.AnthropicError:
models = []
_LOGGER.debug("Available models: %s", models)
model_options: list[SelectOptionDict] = []
short_form = re.compile(r"[^\d]-\d$")
for model_info in models:
# Resolve alias from versioned model name:
model_alias = (
model_info.id[:-9]
if model_info.id
not in (
"claude-3-haiku-20240307",
"claude-3-5-haiku-20241022",
"claude-3-opus-20240229",
)
and model_info.id[-2:-1] != "-"
else model_info.id
)
if short_form.search(model_alias):
model_alias += "-0"
if model_alias.endswith(("haiku", "opus", "sonnet")):
model_alias += "-latest"
model_options.append(
SelectOptionDict(
label=model_info.display_name,
value=model_alias,
)
)
return model_options
class AnthropicConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Anthropic."""
@@ -320,7 +358,9 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
model = self.options[CONF_CHAT_MODEL]
if not model.startswith(tuple(NON_THINKING_MODELS)):
if not model.startswith(tuple(NON_THINKING_MODELS)) and model.startswith(
tuple(NON_ADAPTIVE_THINKING_MODELS)
):
step_schema[
vol.Optional(
CONF_THINKING_BUDGET, default=DEFAULT[CONF_THINKING_BUDGET]
@@ -337,6 +377,22 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
else:
self.options.pop(CONF_THINKING_BUDGET, None)
if not model.startswith(tuple(NON_ADAPTIVE_THINKING_MODELS)):
step_schema[
vol.Optional(
CONF_THINKING_EFFORT,
default=DEFAULT[CONF_THINKING_EFFORT],
)
] = SelectSelector(
SelectSelectorConfig(
options=["none", "low", "medium", "high", "max"],
translation_key=CONF_THINKING_EFFORT,
mode=SelectSelectorMode.DROPDOWN,
)
)
else:
self.options.pop(CONF_THINKING_EFFORT, None)
if not model.startswith(tuple(WEB_SEARCH_UNSUPPORTED_MODELS)):
step_schema.update(
{
@@ -401,49 +457,20 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
async def _get_model_list(self) -> list[SelectOptionDict]:
"""Get list of available models."""
try:
client = await self.hass.async_add_executor_job(
partial(
anthropic.AsyncAnthropic,
api_key=self._get_entry().data[CONF_API_KEY],
)
)
models = (await client.models.list()).data
except anthropic.AnthropicError:
models = []
_LOGGER.debug("Available models: %s", models)
model_options: list[SelectOptionDict] = []
short_form = re.compile(r"[^\d]-\d$")
for model_info in models:
# Resolve alias from versioned model name:
model_alias = (
model_info.id[:-9]
if model_info.id
not in ("claude-3-haiku-20240307", "claude-3-opus-20240229")
else model_info.id
)
if short_form.search(model_alias):
model_alias += "-0"
if model_alias.endswith(("haiku", "opus", "sonnet")):
model_alias += "-latest"
model_options.append(
SelectOptionDict(
label=model_info.display_name,
value=model_alias,
)
)
return model_options
client = anthropic.AsyncAnthropic(
api_key=self._get_entry().data[CONF_API_KEY],
http_client=get_async_client(self.hass),
)
return await get_model_list(client)
async def _get_location_data(self) -> dict[str, str]:
"""Get approximate location data of the user."""
location_data: dict[str, str] = {}
zone_home = self.hass.states.get(ENTITY_ID_HOME)
if zone_home is not None:
client = await self.hass.async_add_executor_job(
partial(
anthropic.AsyncAnthropic,
api_key=self._get_entry().data[CONF_API_KEY],
)
client = anthropic.AsyncAnthropic(
api_key=self._get_entry().data[CONF_API_KEY],
http_client=get_async_client(self.hass),
)
location_schema = vol.Schema(
{
@@ -464,22 +491,24 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
"role": "user",
"content": "Where are the following coordinates located: "
f"({zone_home.attributes[ATTR_LATITUDE]},"
f" {zone_home.attributes[ATTR_LONGITUDE]})? Please respond "
"only with a JSON object using the following schema:\n"
f"{convert(location_schema)}",
},
{
"role": "assistant",
"content": "{", # hints the model to skip any preamble
},
f" {zone_home.attributes[ATTR_LONGITUDE]})?",
}
],
max_tokens=cast(int, DEFAULT[CONF_MAX_TOKENS]),
output_config={
"format": {
"type": "json_schema",
"schema": {
**convert(location_schema),
"additionalProperties": False,
},
}
},
)
_LOGGER.debug("Model response: %s", response.content)
location_data = location_schema(
json.loads(
"{"
+ "".join(
"".join(
block.text
for block in response.content
if isinstance(block, anthropic.types.TextBlock)
+33 -1
View File
@@ -14,6 +14,7 @@ CONF_CHAT_MODEL = "chat_model"
CONF_MAX_TOKENS = "max_tokens"
CONF_TEMPERATURE = "temperature"
CONF_THINKING_BUDGET = "thinking_budget"
CONF_THINKING_EFFORT = "thinking_effort"
CONF_WEB_SEARCH = "web_search"
CONF_WEB_SEARCH_USER_LOCATION = "user_location"
CONF_WEB_SEARCH_MAX_USES = "web_search_max_uses"
@@ -22,11 +23,14 @@ CONF_WEB_SEARCH_REGION = "region"
CONF_WEB_SEARCH_COUNTRY = "country"
CONF_WEB_SEARCH_TIMEZONE = "timezone"
DATA_REPAIR_DEFER_RELOAD = "repair_defer_reload"
DEFAULT = {
CONF_CHAT_MODEL: "claude-3-5-haiku-latest",
CONF_CHAT_MODEL: "claude-haiku-4-5",
CONF_MAX_TOKENS: 3000,
CONF_TEMPERATURE: 1.0,
CONF_THINKING_BUDGET: 0,
CONF_THINKING_EFFORT: "low",
CONF_WEB_SEARCH: False,
CONF_WEB_SEARCH_USER_LOCATION: False,
CONF_WEB_SEARCH_MAX_USES: 5,
@@ -40,9 +44,37 @@ NON_THINKING_MODELS = [
"claude-3-haiku",
]
NON_ADAPTIVE_THINKING_MODELS = [
"claude-opus-4-5",
"claude-sonnet-4-5",
"claude-haiku-4-5",
"claude-opus-4-1",
"claude-opus-4-0",
"claude-opus-4-20250514",
"claude-sonnet-4-0",
"claude-sonnet-4-20250514",
"claude-3",
]
UNSUPPORTED_STRUCTURED_OUTPUT_MODELS = [
"claude-opus-4-1",
"claude-opus-4-0",
"claude-opus-4-20250514",
"claude-sonnet-4-0",
"claude-sonnet-4-20250514",
"claude-3",
]
WEB_SEARCH_UNSUPPORTED_MODELS = [
"claude-3-haiku",
"claude-3-opus",
"claude-3-5-sonnet-20240620",
"claude-3-5-sonnet-20241022",
]
DEPRECATED_MODELS = [
"claude-3-5-haiku",
"claude-3-7-sonnet",
"claude-3-5-sonnet",
"claude-3-opus",
]
+77 -32
View File
@@ -20,9 +20,11 @@ from anthropic.types import (
DocumentBlockParam,
ImageBlockParam,
InputJSONDelta,
JSONOutputFormatParam,
MessageDeltaUsage,
MessageParam,
MessageStreamEvent,
OutputConfigParam,
RawContentBlockDeltaEvent,
RawContentBlockStartEvent,
RawContentBlockStopEvent,
@@ -41,6 +43,7 @@ from anthropic.types import (
TextDelta,
ThinkingBlock,
ThinkingBlockParam,
ThinkingConfigAdaptiveParam,
ThinkingConfigDisabledParam,
ThinkingConfigEnabledParam,
ThinkingDelta,
@@ -78,6 +81,7 @@ from .const import (
CONF_MAX_TOKENS,
CONF_TEMPERATURE,
CONF_THINKING_BUDGET,
CONF_THINKING_EFFORT,
CONF_WEB_SEARCH,
CONF_WEB_SEARCH_CITY,
CONF_WEB_SEARCH_COUNTRY,
@@ -89,7 +93,9 @@ from .const import (
DOMAIN,
LOGGER,
MIN_THINKING_BUDGET,
NON_ADAPTIVE_THINKING_MODELS,
NON_THINKING_MODELS,
UNSUPPORTED_STRUCTURED_OUTPUT_MODELS,
)
# Max number of back and forth with the LLM to generate a response
@@ -600,6 +606,16 @@ class AnthropicBaseLLMEntity(Entity):
system = chat_log.content[0]
if not isinstance(system, conversation.SystemContent):
raise TypeError("First message must be a system message")
# System prompt with caching enabled
system_prompt: list[TextBlockParam] = [
TextBlockParam(
type="text",
text=system.content,
cache_control={"type": "ephemeral"},
)
]
messages = _convert_content(chat_log.content[1:])
model = options.get(CONF_CHAT_MODEL, DEFAULT[CONF_CHAT_MODEL])
@@ -608,25 +624,38 @@ class AnthropicBaseLLMEntity(Entity):
model=model,
messages=messages,
max_tokens=options.get(CONF_MAX_TOKENS, DEFAULT[CONF_MAX_TOKENS]),
system=system.content,
system=system_prompt,
stream=True,
)
thinking_budget = options.get(
CONF_THINKING_BUDGET, DEFAULT[CONF_THINKING_BUDGET]
)
if (
not model.startswith(tuple(NON_THINKING_MODELS))
and thinking_budget >= MIN_THINKING_BUDGET
):
model_args["thinking"] = ThinkingConfigEnabledParam(
type="enabled", budget_tokens=thinking_budget
if not model.startswith(tuple(NON_ADAPTIVE_THINKING_MODELS)):
thinking_effort = options.get(
CONF_THINKING_EFFORT, DEFAULT[CONF_THINKING_EFFORT]
)
if thinking_effort != "none":
model_args["thinking"] = ThinkingConfigAdaptiveParam(type="adaptive")
model_args["output_config"] = OutputConfigParam(effort=thinking_effort)
else:
model_args["thinking"] = ThinkingConfigDisabledParam(type="disabled")
model_args["temperature"] = options.get(
CONF_TEMPERATURE, DEFAULT[CONF_TEMPERATURE]
)
else:
model_args["thinking"] = ThinkingConfigDisabledParam(type="disabled")
model_args["temperature"] = options.get(
CONF_TEMPERATURE, DEFAULT[CONF_TEMPERATURE]
thinking_budget = options.get(
CONF_THINKING_BUDGET, DEFAULT[CONF_THINKING_BUDGET]
)
if (
not model.startswith(tuple(NON_THINKING_MODELS))
and thinking_budget >= MIN_THINKING_BUDGET
):
model_args["thinking"] = ThinkingConfigEnabledParam(
type="enabled", budget_tokens=thinking_budget
)
else:
model_args["thinking"] = ThinkingConfigDisabledParam(type="disabled")
model_args["temperature"] = options.get(
CONF_TEMPERATURE, DEFAULT[CONF_TEMPERATURE]
)
tools: list[ToolUnionParam] = []
if chat_log.llm_api:
@@ -670,8 +699,25 @@ class AnthropicBaseLLMEntity(Entity):
)
if structure and structure_name:
structure_name = slugify(structure_name)
if model_args["thinking"]["type"] == "disabled":
if not model.startswith(tuple(UNSUPPORTED_STRUCTURED_OUTPUT_MODELS)):
# Native structured output for those models who support it.
structure_name = None
model_args.setdefault("output_config", OutputConfigParam())[
"format"
] = JSONOutputFormatParam(
type="json_schema",
schema={
**convert(
structure,
custom_serializer=chat_log.llm_api.custom_serializer
if chat_log.llm_api
else llm.selector_serializer,
),
"additionalProperties": False,
},
)
elif model_args["thinking"]["type"] == "disabled":
structure_name = slugify(structure_name)
if not tools:
# Simplest case: no tools and no extended thinking
# Add a tool and force its use
@@ -691,33 +737,32 @@ class AnthropicBaseLLMEntity(Entity):
# force tool use or disable text responses, so we add a hint to the
# system prompt instead. With extended thinking, the model should be
# smart enough to use the tool.
structure_name = slugify(structure_name)
model_args["tool_choice"] = ToolChoiceAutoParam(
type="auto",
)
if isinstance(model_args["system"], str):
model_args["system"] = [
TextBlockParam(type="text", text=model_args["system"])
]
model_args["system"].append( # type: ignore[union-attr]
TextBlockParam(
type="text",
text=f"Claude MUST use the '{structure_name}' tool to provide the final answer instead of plain text.",
text=f"Claude MUST use the '{structure_name}' tool to provide "
"the final answer instead of plain text.",
)
)
tools.append(
ToolParam(
name=structure_name,
description="Use this tool to reply to the user",
input_schema=convert(
structure,
custom_serializer=chat_log.llm_api.custom_serializer
if chat_log.llm_api
else llm.selector_serializer,
),
if structure_name:
tools.append(
ToolParam(
name=structure_name,
description="Use this tool to reply to the user",
input_schema=convert(
structure,
custom_serializer=chat_log.llm_api.custom_serializer
if chat_log.llm_api
else llm.selector_serializer,
),
)
)
)
if tools:
model_args["tools"] = tools
@@ -738,7 +783,7 @@ class AnthropicBaseLLMEntity(Entity):
_transform_stream(
chat_log,
stream,
output_tool=structure_name if structure else None,
output_tool=structure_name or None,
),
)
]
@@ -8,5 +8,5 @@
"documentation": "https://www.home-assistant.io/integrations/anthropic",
"integration_type": "service",
"iot_class": "cloud_polling",
"requirements": ["anthropic==0.75.0"]
"requirements": ["anthropic==0.78.0"]
}
@@ -0,0 +1,275 @@
"""Issue repair flow for Anthropic."""
from __future__ import annotations
from collections.abc import Iterator
from typing import cast
import voluptuous as vol
from homeassistant import data_entry_flow
from homeassistant.components.repairs import RepairsFlow
from homeassistant.config_entries import ConfigEntry, ConfigEntryState, ConfigSubentry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.selector import SelectSelector, SelectSelectorConfig
from .config_flow import get_model_list
from .const import (
CONF_CHAT_MODEL,
DATA_REPAIR_DEFER_RELOAD,
DEFAULT,
DEPRECATED_MODELS,
DOMAIN,
)
class ModelDeprecatedRepairFlow(RepairsFlow):
"""Handler for an issue fixing flow."""
_subentry_iter: Iterator[tuple[str, str]] | None
_current_entry_id: str | None
_current_subentry_id: str | None
_reload_pending: set[str]
_pending_updates: dict[str, dict[str, str]]
def __init__(self) -> None:
"""Initialize the flow."""
super().__init__()
self._subentry_iter = None
self._current_entry_id = None
self._current_subentry_id = None
self._reload_pending = set()
self._pending_updates = {}
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> data_entry_flow.FlowResult:
"""Handle the first step of a fix flow."""
previous_entry_id: str | None = None
if user_input is not None:
previous_entry_id = self._async_update_current_subentry(user_input)
self._clear_current_target()
target = await self._async_next_target()
next_entry_id = target[0].entry_id if target else None
if previous_entry_id and previous_entry_id != next_entry_id:
await self._async_apply_pending_updates(previous_entry_id)
if target is None:
await self._async_apply_all_pending_updates()
return self.async_create_entry(data={})
entry, subentry, model = target
client = entry.runtime_data
model_list = [
model_option
for model_option in await get_model_list(client)
if not model_option["value"].startswith(tuple(DEPRECATED_MODELS))
]
if "opus" in model:
suggested_model = "claude-opus-4-5"
elif "haiku" in model:
suggested_model = "claude-haiku-4-5"
elif "sonnet" in model:
suggested_model = "claude-sonnet-4-5"
else:
suggested_model = cast(str, DEFAULT[CONF_CHAT_MODEL])
schema = vol.Schema(
{
vol.Required(
CONF_CHAT_MODEL,
default=suggested_model,
): SelectSelector(
SelectSelectorConfig(options=model_list, custom_value=True)
),
}
)
return self.async_show_form(
step_id="init",
data_schema=schema,
description_placeholders={
"entry_name": entry.title,
"model": model,
"subentry_name": subentry.title,
"subentry_type": self._format_subentry_type(subentry.subentry_type),
},
)
def _iter_deprecated_subentries(self) -> Iterator[tuple[str, str]]:
"""Yield entry/subentry pairs that use deprecated models."""
for entry in self.hass.config_entries.async_entries(DOMAIN):
if entry.state is not ConfigEntryState.LOADED:
continue
for subentry in entry.subentries.values():
model = subentry.data.get(CONF_CHAT_MODEL)
if model and model.startswith(tuple(DEPRECATED_MODELS)):
yield entry.entry_id, subentry.subentry_id
async def _async_next_target(
self,
) -> tuple[ConfigEntry, ConfigSubentry, str] | None:
"""Return the next deprecated subentry target."""
if self._subentry_iter is None:
self._subentry_iter = self._iter_deprecated_subentries()
while True:
try:
entry_id, subentry_id = next(self._subentry_iter)
except StopIteration:
return None
entry = self.hass.config_entries.async_get_entry(entry_id)
if entry is None:
continue
subentry = entry.subentries.get(subentry_id)
if subentry is None:
continue
model = self._pending_model(entry_id, subentry_id)
if model is None:
model = subentry.data.get(CONF_CHAT_MODEL)
if not model or not model.startswith(tuple(DEPRECATED_MODELS)):
continue
self._current_entry_id = entry_id
self._current_subentry_id = subentry_id
return entry, subentry, model
def _async_update_current_subentry(self, user_input: dict[str, str]) -> str | None:
"""Update the currently selected subentry."""
if not self._current_entry_id or not self._current_subentry_id:
return None
entry = self.hass.config_entries.async_get_entry(self._current_entry_id)
if entry is None:
return None
subentry = entry.subentries.get(self._current_subentry_id)
if subentry is None:
return None
updated_data = {
**subentry.data,
CONF_CHAT_MODEL: user_input[CONF_CHAT_MODEL],
}
if updated_data == subentry.data:
return entry.entry_id
self._queue_pending_update(
entry.entry_id,
subentry.subentry_id,
updated_data[CONF_CHAT_MODEL],
)
return entry.entry_id
def _clear_current_target(self) -> None:
"""Clear current target tracking."""
self._current_entry_id = None
self._current_subentry_id = None
def _format_subentry_type(self, subentry_type: str) -> str:
"""Return a user-friendly subentry type label."""
if subentry_type == "conversation":
return "Conversation agent"
if subentry_type in ("ai_task", "ai_task_data"):
return "AI task"
return subentry_type
def _queue_pending_update(
self, entry_id: str, subentry_id: str, model: str
) -> None:
"""Store a pending model update for a subentry."""
self._pending_updates.setdefault(entry_id, {})[subentry_id] = model
def _pending_model(self, entry_id: str, subentry_id: str) -> str | None:
"""Return a pending model update if one exists."""
return self._pending_updates.get(entry_id, {}).get(subentry_id)
def _mark_entry_for_reload(self, entry_id: str) -> None:
"""Prevent reload until repairs are complete for the entry."""
self._reload_pending.add(entry_id)
defer_reload_entries: set[str] = self.hass.data.setdefault(
DOMAIN, {}
).setdefault(DATA_REPAIR_DEFER_RELOAD, set())
defer_reload_entries.add(entry_id)
async def _async_reload_entry(self, entry_id: str) -> None:
"""Reload an entry once all repairs are completed."""
if entry_id not in self._reload_pending:
return
entry = self.hass.config_entries.async_get_entry(entry_id)
if entry is not None and entry.state is not ConfigEntryState.LOADED:
self._clear_defer_reload(entry_id)
self._reload_pending.discard(entry_id)
return
if entry is not None:
await self.hass.config_entries.async_reload(entry_id)
self._clear_defer_reload(entry_id)
self._reload_pending.discard(entry_id)
def _clear_defer_reload(self, entry_id: str) -> None:
"""Remove entry from the deferred reload set."""
defer_reload_entries: set[str] = self.hass.data.setdefault(
DOMAIN, {}
).setdefault(DATA_REPAIR_DEFER_RELOAD, set())
defer_reload_entries.discard(entry_id)
async def _async_apply_pending_updates(self, entry_id: str) -> None:
"""Apply pending subentry updates for a single entry."""
updates = self._pending_updates.pop(entry_id, None)
if not updates:
return
entry = self.hass.config_entries.async_get_entry(entry_id)
if entry is None or entry.state is not ConfigEntryState.LOADED:
return
changed = False
for subentry_id, model in updates.items():
subentry = entry.subentries.get(subentry_id)
if subentry is None:
continue
updated_data = {
**subentry.data,
CONF_CHAT_MODEL: model,
}
if updated_data == subentry.data:
continue
if not changed:
self._mark_entry_for_reload(entry_id)
changed = True
self.hass.config_entries.async_update_subentry(
entry,
subentry,
data=updated_data,
)
if not changed:
return
await self._async_reload_entry(entry_id)
async def _async_apply_all_pending_updates(self) -> None:
"""Apply all pending updates across entries."""
for entry_id in list(self._pending_updates):
await self._async_apply_pending_updates(entry_id)
async def async_create_fix_flow(
hass: HomeAssistant,
issue_id: str,
data: dict[str, str | int | float | None] | None,
) -> RepairsFlow:
"""Create flow."""
if issue_id == "model_deprecated":
return ModelDeprecatedRepairFlow()
raise HomeAssistantError("Unknown issue ID")
@@ -47,12 +47,14 @@
"model": {
"data": {
"thinking_budget": "[%key:component::anthropic::config_subentries::conversation::step::model::data::thinking_budget%]",
"thinking_effort": "[%key:component::anthropic::config_subentries::conversation::step::model::data::thinking_effort%]",
"user_location": "[%key:component::anthropic::config_subentries::conversation::step::model::data::user_location%]",
"web_search": "[%key:component::anthropic::config_subentries::conversation::step::model::data::web_search%]",
"web_search_max_uses": "[%key:component::anthropic::config_subentries::conversation::step::model::data::web_search_max_uses%]"
},
"data_description": {
"thinking_budget": "[%key:component::anthropic::config_subentries::conversation::step::model::data_description::thinking_budget%]",
"thinking_effort": "[%key:component::anthropic::config_subentries::conversation::step::model::data_description::thinking_effort%]",
"user_location": "[%key:component::anthropic::config_subentries::conversation::step::model::data_description::user_location%]",
"web_search": "[%key:component::anthropic::config_subentries::conversation::step::model::data_description::web_search%]",
"web_search_max_uses": "[%key:component::anthropic::config_subentries::conversation::step::model::data_description::web_search_max_uses%]"
@@ -95,12 +97,14 @@
"model": {
"data": {
"thinking_budget": "Thinking budget",
"thinking_effort": "Thinking effort",
"user_location": "Include home location",
"web_search": "Enable web search",
"web_search_max_uses": "Maximum web searches"
},
"data_description": {
"thinking_budget": "The number of tokens the model can use to think about the response out of the total maximum number of tokens. Set to 1024 or greater to enable extended thinking.",
"thinking_effort": "Control how many tokens Claude uses when responding, trading off between response thoroughness and token efficiency",
"user_location": "Localize search results based on home location",
"web_search": "The web search tool gives Claude direct access to real-time web content, allowing it to answer questions with up-to-date information beyond its knowledge cutoff",
"web_search_max_uses": "Limit the number of searches performed per response"
@@ -109,5 +113,32 @@
}
}
}
},
"issues": {
"model_deprecated": {
"fix_flow": {
"step": {
"init": {
"data": {
"chat_model": "[%key:common::generic::model%]"
},
"description": "You are updating {subentry_name} ({subentry_type}) in {entry_name}. The current model {model} is deprecated. Select a supported model to continue.",
"title": "Update model"
}
}
},
"title": "Model deprecated"
}
},
"selector": {
"thinking_effort": {
"options": {
"high": "[%key:common::state::high%]",
"low": "[%key:common::state::low%]",
"max": "Max",
"medium": "[%key:common::state::medium%]",
"none": "None"
}
}
}
}
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/aosmith",
"integration_type": "hub",
"iot_class": "cloud_polling",
"requirements": ["py-aosmith==1.0.15"]
"requirements": ["py-aosmith==1.0.17"]
}
@@ -50,7 +50,7 @@ class ConfigFlowHandler(ConfigFlow, domain=DOMAIN):
try:
async with asyncio.timeout(CONNECTION_TIMEOUT):
data = APCUPSdData(await aioapcaccess.request_status(host, port))
except (OSError, asyncio.IncompleteReadError, TimeoutError):
except OSError, asyncio.IncompleteReadError, TimeoutError:
errors = {"base": "cannot_connect"}
return self.async_show_form(
step_id="user", data_schema=_SCHEMA, errors=errors
@@ -77,7 +77,7 @@ class ConfigFlowHandler(ConfigFlow, domain=DOMAIN):
try:
async with asyncio.timeout(CONNECTION_TIMEOUT):
data = APCUPSdData(await aioapcaccess.request_status(host, port))
except (OSError, asyncio.IncompleteReadError, TimeoutError):
except OSError, asyncio.IncompleteReadError, TimeoutError:
errors = {"base": "cannot_connect"}
return self.async_show_form(
step_id="reconfigure", data_schema=_SCHEMA, errors=errors
+11 -1
View File
@@ -540,7 +540,17 @@ class APCUPSdSensor(APCUPSdEntity, SensorEntity):
data = self.coordinator.data[key]
if self.entity_description.device_class == SensorDeviceClass.TIMESTAMP:
self._attr_native_value = dateutil.parser.parse(data)
# The date could be "N/A" for certain fields (e.g., XOFFBATT), indicating there is no value yet.
if data == "N/A":
self._attr_native_value = None
return
try:
self._attr_native_value = dateutil.parser.parse(data)
except dateutil.parser.ParserError, OverflowError:
# If parsing fails we should mark it as unknown, with a log for further debugging.
_LOGGER.warning('Failed to parse date for %s: "%s"', key, data)
self._attr_native_value = None
return
self._attr_native_value, inferred_unit = infer_unit(data)
@@ -2,15 +2,16 @@
from __future__ import annotations
from pyatv.const import KeyboardFocusState
from pyatv.const import FeatureName, FeatureState, KeyboardFocusState
from pyatv.interface import AppleTV, KeyboardListener
from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import AppleTvConfigEntry
from . import SIGNAL_CONNECTED, AppleTvConfigEntry
from .entity import AppleTVEntity
@@ -21,10 +22,22 @@ async def async_setup_entry(
) -> None:
"""Load Apple TV binary sensor based on a config entry."""
# apple_tv config entries always have a unique id
assert config_entry.unique_id is not None
name: str = config_entry.data[CONF_NAME]
manager = config_entry.runtime_data
async_add_entities([AppleTVKeyboardFocused(name, config_entry.unique_id, manager)])
cb: CALLBACK_TYPE
def setup_entities(atv: AppleTV) -> None:
if atv.features.in_state(FeatureState.Available, FeatureName.TextFocusState):
assert config_entry.unique_id is not None
name: str = config_entry.data[CONF_NAME]
async_add_entities(
[AppleTVKeyboardFocused(name, config_entry.unique_id, manager)]
)
cb()
cb = async_dispatcher_connect(
hass, f"{SIGNAL_CONNECTED}_{config_entry.unique_id}", setup_entities
)
config_entry.async_on_unload(cb)
class AppleTVKeyboardFocused(AppleTVEntity, BinarySensorEntity, KeyboardListener):
@@ -181,9 +181,9 @@ async def async_import_client_credential(
CONF_DOMAIN: domain,
CONF_CLIENT_ID: credential.client_id,
CONF_CLIENT_SECRET: credential.client_secret,
CONF_AUTH_DOMAIN: auth_domain if auth_domain else domain,
CONF_AUTH_DOMAIN: auth_domain or domain,
}
item[CONF_NAME] = credential.name if credential.name else DEFAULT_IMPORT_NAME
item[CONF_NAME] = credential.name or DEFAULT_IMPORT_NAME
await hass.data[DATA_COMPONENT].async_import_item(item)
@@ -168,7 +168,7 @@ class AprilaireCoordinator(BaseDataUpdateCoordinatorProtocol):
name = data.get(Attribute.NAME) if data else None
return name if name else "Aprilaire"
return name or "Aprilaire"
def get_hw_version(self, data: dict[str, Any]) -> str:
"""Get the hardware version."""
@@ -41,7 +41,7 @@ class APsystemsLocalAPIFlow(ConfigFlow, domain=DOMAIN):
)
try:
device_info = await api.get_device_info()
except (TimeoutError, ClientConnectionError):
except TimeoutError, ClientConnectionError:
errors["base"] = "cannot_connect"
else:
await self.async_set_unique_id(device_info.deviceId)
@@ -64,7 +64,7 @@ class ApSystemsDataCoordinator(DataUpdateCoordinator[ApSystemsSensorData]):
async def _async_setup(self) -> None:
try:
device_info = await self.api.get_device_info()
except (ConnectionError, TimeoutError):
except ConnectionError, TimeoutError:
raise UpdateFailed from None
self.api.max_power = device_info.maxPower
self.api.min_power = device_info.minPower
+1 -1
View File
@@ -49,7 +49,7 @@ class ApSystemsMaxOutputNumber(ApSystemsEntity, NumberEntity):
"""Set the state with the value fetched from the inverter."""
try:
status = await self._api.get_max_power()
except (TimeoutError, ClientConnectorError):
except TimeoutError, ClientConnectorError:
self._attr_available = False
else:
self._attr_available = True
+1 -1
View File
@@ -43,7 +43,7 @@ class ApSystemsInverterSwitch(ApSystemsEntity, SwitchEntity):
"""Update switch status and availability."""
try:
status = await self._api.get_device_power_status()
except (TimeoutError, ClientConnectionError, InverterReturnedError):
except TimeoutError, ClientConnectionError, InverterReturnedError:
self._attr_available = False
else:
self._attr_available = True
@@ -56,7 +56,7 @@ class AquaCellConfigFlow(ConfigFlow, domain=DOMAIN):
refresh_token = await api.authenticate(
user_input[CONF_EMAIL], user_input[CONF_PASSWORD]
)
except (ApiException, TimeoutError):
except ApiException, TimeoutError:
errors["base"] = "cannot_connect"
except AuthenticationFailed:
errors["base"] = "invalid_auth"
@@ -94,7 +94,7 @@ def _retry[_SharpAquosTVDeviceT: SharpAquosTVDevice, **_P](
try:
func(obj, *args, **kwargs)
break
except (OSError, TypeError, ValueError):
except OSError, TypeError, ValueError:
update_retries -= 1
if update_retries == 0:
obj.set_state(MediaPlayerState.OFF)
@@ -19,5 +19,5 @@
"documentation": "https://www.home-assistant.io/integrations/aranet",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["aranet4==2.5.1"]
"requirements": ["aranet4==2.6.0"]
}
+1 -1
View File
@@ -201,5 +201,5 @@ class ArwnSensor(SensorEntity):
ev: dict[str, Any] = {}
ev.update(event)
self._attr_extra_state_attributes = ev
self._attr_native_value = ev.get(self._state_key, None)
self._attr_native_value = ev.get(self._state_key)
self.async_write_ha_state()
@@ -969,7 +969,7 @@ class PipelineRun:
metadata,
self._speech_to_text_stream(audio_stream=stream, stt_vad=stt_vad),
)
except (asyncio.CancelledError, TimeoutError):
except asyncio.CancelledError, TimeoutError:
raise # expected
except hass_nabucasa.auth.Unauthenticated as src_error:
raise SpeechToTextError(
@@ -189,7 +189,7 @@ class AsusWrtFlowHandler(ConfigFlow, domain=DOMAIN):
try:
await api.async_connect()
except (AsusRouterError, OSError):
except AsusRouterError, OSError:
_LOGGER.error(
"Error connecting to the AsusWrt router at %s using protocol %s",
host,
+1 -1
View File
@@ -51,5 +51,5 @@ class AtagConfigFlow(ConfigFlow, domain=DOMAIN):
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(DATA_SCHEMA),
errors=errors if errors else {},
errors=errors or {},
)
@@ -30,6 +30,9 @@
"title": "Set up one-time password delivered by notify component"
},
"setup": {
"data": {
"code": "Code"
},
"description": "A one-time password has been sent via **notify.{notify_service}**. Please enter it below:",
"title": "Verify setup"
}
@@ -42,6 +45,9 @@
},
"step": {
"init": {
"data": {
"code": "Code"
},
"description": "To activate two-factor authentication using time-based one-time passwords, scan the QR code with your authentication app. If you don't have one, we recommend either [Google Authenticator]({google_authenticator_url}) or [Authy]({authy_url}).\n\n{qr_code}\n\nAfter scanning the code, enter the six-digit code from your app to verify the setup. If you have problems scanning the QR code, do a manual setup with code **`{code}`**.",
"title": "Set up two-factor authentication using TOTP"
}
@@ -14,7 +14,7 @@ import voluptuous as vol
from homeassistant.components import labs, websocket_api
from homeassistant.components.blueprint import CONF_USE_BLUEPRINT
from homeassistant.components.labs import async_listen as async_labs_listen
from homeassistant.components.labs import async_subscribe_preview_feature
from homeassistant.const import (
ATTR_AREA_ID,
ATTR_ENTITY_ID,
@@ -386,14 +386,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
schema=vol.Schema({vol.Optional(CONF_ID): str}),
)
@callback
def new_triggers_conditions_listener() -> None:
async def new_triggers_conditions_listener(
_event_data: labs.EventLabsUpdatedData,
) -> None:
"""Handle new_triggers_conditions flag change."""
hass.async_create_task(
reload_helper.execute_service(ServiceCall(hass, DOMAIN, SERVICE_RELOAD))
)
await reload_helper.execute_service(ServiceCall(hass, DOMAIN, SERVICE_RELOAD))
async_labs_listen(
async_subscribe_preview_feature(
hass,
DOMAIN,
NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG,
@@ -304,7 +304,7 @@ async def _try_async_validate_config_item(
"""Validate config item."""
try:
return await _async_validate_config_item(hass, config, False, True)
except (vol.Invalid, HomeAssistantError):
except vol.Invalid, HomeAssistantError:
return None
+8 -8
View File
@@ -297,14 +297,14 @@ class S3BackupAgent(BackupAgent):
return self._backup_cache
backups = {}
response = await self._client.list_objects_v2(Bucket=self._bucket)
# Filter for metadata files only
metadata_files = [
obj
for obj in response.get("Contents", [])
if obj["Key"].endswith(".metadata.json")
]
paginator = self._client.get_paginator("list_objects_v2")
metadata_files: list[dict[str, Any]] = []
async for page in paginator.paginate(Bucket=self._bucket):
metadata_files.extend(
obj
for obj in page.get("Contents", [])
if obj["Key"].endswith(".metadata.json")
)
for metadata_file in metadata_files:
try:
+1 -1
View File
@@ -52,7 +52,7 @@ from .const import (
from .errors import AuthenticationRequired, CannotConnect
from .hub import AxisHub, get_axis_api
AXIS_OUI = {"00:40:8c", "ac:cc:8e", "b8:a4:4f"}
AXIS_OUI = {"00:40:8c", "ac:cc:8e", "b8:a4:4f", "e8:27:25"}
DEFAULT_PORT = 443
DEFAULT_PROTOCOL = "https"
PROTOCOL_CHOICES = ["https", "http"]
@@ -16,12 +16,18 @@ CONNECTION_TIMEOUT = 120 # 2 minutes
# Default TIMEOUT_FOR_UPLOAD is 128 seconds, which is too short for large backups
TIMEOUT_FOR_UPLOAD = 43200 # 12 hours
# Reduced retry count for download operations
# Default is 20 retries with exponential backoff, which can hang for 30+ minutes
# when there are persistent connection errors (e.g., SSL failures)
TRY_COUNT_DOWNLOAD = 3
class B2Http(BaseB2Http): # type: ignore[misc]
"""B2Http with extended timeouts for backup operations."""
CONNECTION_TIMEOUT = CONNECTION_TIMEOUT
TIMEOUT_FOR_UPLOAD = TIMEOUT_FOR_UPLOAD
TRY_COUNT_DOWNLOAD = TRY_COUNT_DOWNLOAD
class B2Session(BaseB2Session): # type: ignore[misc]
+52 -20
View File
@@ -40,6 +40,10 @@ CACHE_TTL = 300
# This prevents uploads from hanging indefinitely
UPLOAD_TIMEOUT = 43200 # 12 hours (matches B2 HTTP timeout)
# Timeout for metadata download operations (in seconds)
# This prevents the backup system from hanging when B2 connections fail
METADATA_DOWNLOAD_TIMEOUT = 60
def suggested_filenames(backup: AgentBackup) -> tuple[str, str]:
"""Return the suggested filenames for the backup and metadata files."""
@@ -413,12 +417,21 @@ class BackblazeBackupAgent(BackupAgent):
backups = {}
for file_name, file_version in all_files_in_prefix.items():
if file_name.endswith(METADATA_FILE_SUFFIX):
backup = await self._hass.async_add_executor_job(
self._process_metadata_file_sync,
file_name,
file_version,
all_files_in_prefix,
)
try:
backup = await asyncio.wait_for(
self._hass.async_add_executor_job(
self._process_metadata_file_sync,
file_name,
file_version,
all_files_in_prefix,
),
timeout=METADATA_DOWNLOAD_TIMEOUT,
)
except TimeoutError:
_LOGGER.warning(
"Timeout downloading metadata file %s", file_name
)
continue
if backup:
backups[backup.backup_id] = backup
self._backup_list_cache = backups
@@ -442,10 +455,18 @@ class BackblazeBackupAgent(BackupAgent):
if not file or not metadata_file_version:
raise BackupNotFound(f"Backup {backup_id} not found")
metadata_content = await self._hass.async_add_executor_job(
self._download_and_parse_metadata_sync,
metadata_file_version,
)
try:
metadata_content = await asyncio.wait_for(
self._hass.async_add_executor_job(
self._download_and_parse_metadata_sync,
metadata_file_version,
),
timeout=METADATA_DOWNLOAD_TIMEOUT,
)
except TimeoutError:
raise BackupAgentError(
f"Timeout downloading metadata for backup {backup_id}"
) from None
_LOGGER.debug(
"Successfully retrieved metadata for backup ID %s from file %s",
@@ -468,16 +489,27 @@ class BackblazeBackupAgent(BackupAgent):
# Process metadata files sequentially to avoid exhausting executor pool
for file_name, file_version in all_files_in_prefix.items():
if file_name.endswith(METADATA_FILE_SUFFIX):
(
result_backup_file,
result_metadata_file_version,
) = await self._hass.async_add_executor_job(
self._process_metadata_file_for_id_sync,
file_name,
file_version,
backup_id,
all_files_in_prefix,
)
try:
(
result_backup_file,
result_metadata_file_version,
) = await asyncio.wait_for(
self._hass.async_add_executor_job(
self._process_metadata_file_for_id_sync,
file_name,
file_version,
backup_id,
all_files_in_prefix,
),
timeout=METADATA_DOWNLOAD_TIMEOUT,
)
except TimeoutError:
_LOGGER.warning(
"Timeout downloading metadata file %s while searching for backup %s",
file_name,
backup_id,
)
continue
if result_backup_file and result_metadata_file_version:
return result_backup_file, result_metadata_file_version
@@ -44,7 +44,7 @@ async def async_get_config_entry_diagnostics(
account_data["allowed"], TO_REDACT_ACCOUNT_DATA_ALLOWED
)
except (AttributeError, TypeError, ValueError, KeyError):
except AttributeError, TypeError, ValueError, KeyError:
bucket_info = {"name": "unknown", "id": "unknown"}
account_data = {"error": "Failed to retrieve detailed account information"}
+1
View File
@@ -26,6 +26,7 @@ EXCLUDE_FROM_BACKUP = [
"tmp_backups/*.tar",
"OZW_Log.txt",
"tts/*",
".cache/*",
]
EXCLUDE_DATABASE_FROM_BACKUP = [
+12 -5
View File
@@ -1,6 +1,7 @@
"""Support for Baidu speech service."""
import logging
from typing import Any
from aip import AipSpeech
import voluptuous as vol
@@ -9,6 +10,7 @@ from homeassistant.components.tts import (
CONF_LANG,
PLATFORM_SCHEMA as TTS_PLATFORM_SCHEMA,
Provider,
TtsAudioType,
)
from homeassistant.const import CONF_API_KEY
from homeassistant.helpers import config_validation as cv
@@ -85,17 +87,17 @@ class BaiduTTSProvider(Provider):
}
@property
def default_language(self):
def default_language(self) -> str:
"""Return the default language."""
return self._lang
@property
def supported_languages(self):
def supported_languages(self) -> list[str]:
"""Return a list of supported languages."""
return SUPPORTED_LANGUAGES
@property
def default_options(self):
def default_options(self) -> dict[str, Any]:
"""Return a dict including default options."""
return {
CONF_PERSON: self._speech_conf_data[_OPTIONS[CONF_PERSON]],
@@ -105,11 +107,16 @@ class BaiduTTSProvider(Provider):
}
@property
def supported_options(self):
def supported_options(self) -> list[str]:
"""Return a list of supported options."""
return SUPPORTED_OPTIONS
def get_tts_audio(self, message, language, options):
def get_tts_audio(
self,
message: str,
language: str,
options: dict[str, Any],
) -> TtsAudioType:
"""Load TTS from BaiduTTS."""
aip_speech = AipSpeech(
@@ -145,7 +145,7 @@ class BeoConfigFlowHandler(ConfigFlow, domain=DOMAIN):
async with self._client:
try:
await self._client.get_beolink_self(_request_timeout=3)
except (ClientConnectorError, TimeoutError):
except ClientConnectorError, TimeoutError:
return self.async_abort(reason="invalid_address")
self._model = discovery_info.hostname[:-16].replace("-", " ")
+1 -15
View File
@@ -6,16 +6,9 @@ from typing import Any
from blinkpy.auth import Auth
from blinkpy.blinkpy import Blink
import voluptuous as vol
from homeassistant.components import persistent_notification
from homeassistant.const import (
CONF_FILE_PATH,
CONF_FILENAME,
CONF_NAME,
CONF_PIN,
CONF_SCAN_INTERVAL,
)
from homeassistant.const import CONF_SCAN_INTERVAL
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
@@ -27,13 +20,6 @@ from .services import async_setup_services
_LOGGER = logging.getLogger(__name__)
SERVICE_SAVE_VIDEO_SCHEMA = vol.Schema(
{vol.Required(CONF_NAME): cv.string, vol.Required(CONF_FILENAME): cv.string}
)
SERVICE_SEND_PIN_SCHEMA = vol.Schema({vol.Optional(CONF_PIN): cv.string})
SERVICE_SAVE_RECENT_CLIPS_SCHEMA = vol.Schema(
{vol.Required(CONF_NAME): cv.string, vol.Required(CONF_FILE_PATH): cv.string}
)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
+1 -27
View File
@@ -9,35 +9,23 @@ from typing import Any
from blinkpy.auth import UnauthorizedError
from blinkpy.camera import BlinkCamera as BlinkCameraAPI
from requests.exceptions import ChunkedEncodingError
import voluptuous as vol
from homeassistant.components.camera import Camera
from homeassistant.const import CONF_FILE_PATH, CONF_FILENAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import (
ConfigEntryAuthFailed,
HomeAssistantError,
ServiceValidationError,
)
from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
DEFAULT_BRAND,
DOMAIN,
SERVICE_RECORD,
SERVICE_SAVE_RECENT_CLIPS,
SERVICE_SAVE_VIDEO,
SERVICE_TRIGGER,
)
from .const import DEFAULT_BRAND, DOMAIN
from .coordinator import BlinkConfigEntry, BlinkUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
ATTR_VIDEO_CLIP = "video"
ATTR_IMAGE = "image"
PARALLEL_UPDATES = 1
@@ -56,20 +44,6 @@ async def async_setup_entry(
async_add_entities(entities)
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(SERVICE_RECORD, None, "record")
platform.async_register_entity_service(SERVICE_TRIGGER, None, "trigger_camera")
platform.async_register_entity_service(
SERVICE_SAVE_RECENT_CLIPS,
{vol.Required(CONF_FILE_PATH): cv.string},
"save_recent_clips",
)
platform.async_register_entity_service(
SERVICE_SAVE_VIDEO,
{vol.Required(CONF_FILENAME): cv.string},
"save_video",
)
class BlinkCamera(CoordinatorEntity[BlinkUpdateCoordinator], Camera):
"""An implementation of a Blink Camera."""
-5
View File
@@ -20,11 +20,6 @@ TYPE_TEMPERATURE = "temperature"
TYPE_BATTERY = "battery"
TYPE_WIFI_STRENGTH = "wifi_strength"
SERVICE_RECORD = "record"
SERVICE_TRIGGER = "trigger_camera"
SERVICE_SAVE_VIDEO = "save_video"
SERVICE_SAVE_RECENT_CLIPS = "save_recent_clips"
SERVICE_SEND_PIN = "send_pin"
PLATFORMS = [
Platform.ALARM_CONTROL_PANEL,
+50 -3
View File
@@ -4,13 +4,27 @@ from __future__ import annotations
import voluptuous as vol
from homeassistant.const import ATTR_CONFIG_ENTRY_ID, CONF_PIN
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
from homeassistant.const import (
ATTR_CONFIG_ENTRY_ID,
CONF_FILE_PATH,
CONF_FILENAME,
CONF_PIN,
)
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, issue_registry as ir
from homeassistant.helpers import config_validation as cv, issue_registry as ir, service
from .const import DOMAIN, SERVICE_SEND_PIN
from .const import DOMAIN
SERVICE_RECORD = "record"
SERVICE_TRIGGER = "trigger_camera"
SERVICE_SAVE_VIDEO = "save_video"
SERVICE_SAVE_RECENT_CLIPS = "save_recent_clips"
# Deprecated
SERVICE_SEND_PIN = "send_pin"
SERVICE_SEND_PIN_SCHEMA = vol.Schema(
{
vol.Required(ATTR_CONFIG_ENTRY_ID): vol.All(cv.ensure_list, [cv.string]),
@@ -52,3 +66,36 @@ def async_setup_services(hass: HomeAssistant) -> None:
_send_pin,
schema=SERVICE_SEND_PIN_SCHEMA,
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_RECORD,
entity_domain=CAMERA_DOMAIN,
schema=None,
func="record",
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_TRIGGER,
entity_domain=CAMERA_DOMAIN,
schema=None,
func="trigger_camera",
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_SAVE_RECENT_CLIPS,
entity_domain=CAMERA_DOMAIN,
schema={vol.Required(CONF_FILE_PATH): cv.string},
func="save_recent_clips",
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
SERVICE_SAVE_VIDEO,
entity_domain=CAMERA_DOMAIN,
schema={vol.Required(CONF_FILENAME): cv.string},
func="save_video",
)
@@ -80,18 +80,16 @@ SWITCHES = (
key=PLUG_AND_CHARGE,
translation_key=PLUG_AND_CHARGE,
function=set_plug_and_charge,
turn_on_off_fn=lambda evse_id, connector: (
update_on_value_and_activity(PLUG_AND_CHARGE, evse_id, connector)
turn_on_off_fn=lambda evse_id, connector: update_on_value_and_activity(
PLUG_AND_CHARGE, evse_id, connector
),
),
BlueCurrentSwitchEntityDescription(
key=LINKED_CHARGE_CARDS,
translation_key=LINKED_CHARGE_CARDS,
function=set_linked_charge_cards,
turn_on_off_fn=lambda evse_id, connector: (
update_on_value_and_activity(
PUBLIC_CHARGING, evse_id, connector, reverse_is_on=True
)
turn_on_off_fn=lambda evse_id, connector: update_on_value_and_activity(
PUBLIC_CHARGING, evse_id, connector, reverse_is_on=True
),
),
BlueCurrentSwitchEntityDescription(
@@ -148,8 +148,10 @@ SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
device_class=BinarySensorDeviceClass.LOCK,
# device class lock: On means unlocked, Off means locked
# Possible values: LOCKED, SECURED, SELECTIVE_LOCKED, UNLOCKED
value_fn=lambda v: v.doors_and_windows.door_lock_state
not in {LockState.LOCKED, LockState.SECURED},
value_fn=lambda v: (
v.doors_and_windows.door_lock_state
not in {LockState.LOCKED, LockState.SECURED}
),
attr_fn=lambda v, u: {
"door_lock_state": v.doors_and_windows.door_lock_state.value
},
@@ -189,9 +191,11 @@ SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
BMWBinarySensorEntityDescription(
key="is_pre_entry_climatization_enabled",
translation_key="is_pre_entry_climatization_enabled",
value_fn=lambda v: v.charging_profile.is_pre_entry_climatization_enabled
if v.charging_profile
else False,
value_fn=lambda v: (
v.charging_profile.is_pre_entry_climatization_enabled
if v.charging_profile
else False
),
is_available=lambda v: v.has_electric_drivetrain,
),
)

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