Compare commits

..

558 Commits

Author SHA1 Message Date
farmio
04727f6672 Fix title string 2025-12-17 11:24:04 +01:00
farmio
f260eb1d42 add sync_state 2025-12-16 21:30:31 +01:00
farmio
61e4b00ce5 Update test_websocket.ambr 2025-12-16 11:33:33 +01:00
farmio
894b2b5fc3 Update fan.py 2025-12-16 11:31:03 +01:00
farmio
52e07d00ca Support KNX fan entity configuration from UI 2025-12-16 11:16:02 +01:00
Allen Porter
2679ac3f5e Add support for dynamic nest devices and remove stale devices (#159060)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 19:58:25 +01:00
Retha Runolfsson
47f476af32 Remove the restriction that Bluetooth login to the Switchbot account is only possible in active mode (#157154) 2025-12-15 19:55:43 +01:00
Pete Sage
ca3d03131e Bump soco to 0.30.13 for Sonos (#159123) 2025-12-15 19:50:39 +01:00
Josef Zweck
a3f3586b02 Add option to enable offline mode to lamarzocco (#159094)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 19:22:50 +01:00
Abílio Costa
0ced960d1d Add button pressed trigger (#158745) 2025-12-15 18:02:30 +00:00
Michael
78f1b434b3 Add update became available trigger (#158984) 2025-12-15 18:31:51 +01:00
Joost Lekkerkerker
563fa8f958 Add integration_type device to enphase_envoy (#159006)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 18:11:45 +01:00
RSDynamics
8de6f04829 Change Lektrico lifetime_energy sensor to float (#158880) 2025-12-15 17:42:42 +01:00
epenet
f74128de49 Drop supports_action in Tuya alarm_control_panel wrapper (#159118) 2025-12-15 17:41:47 +01:00
epenet
25e1cc42eb Make valid options an attribute of Tuya device wrapper (#159109) 2025-12-15 17:27:51 +01:00
epenet
245d57be1a Make min/max/step attributes of Tuya device wrapper (#159116) 2025-12-15 17:27:13 +01:00
Joost Lekkerkerker
c09c016299 Add integration_type service to apcupsd (#158844)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2025-12-15 17:27:01 +01:00
Joost Lekkerkerker
d9283ad4cd Add integration_type service to autarco (#158854)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 17:23:24 +01:00
Joost Lekkerkerker
11f319c79c Add integration_type device to fjaraskupan (#159017)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 17:23:12 +01:00
Joost Lekkerkerker
cc5d98fe8b Add integration_type device to coolmaster (#158925)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 17:22:52 +01:00
Andrew Jackson
3e1f9de0de Add new Mealie meal plan types to calendar and services (#158987) 2025-12-15 17:18:59 +01:00
Joost Lekkerkerker
34212c6e65 Add integration_type service to duke_energy (#158934)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 17:18:09 +01:00
Joost Lekkerkerker
10f02d040f Add integration_type device to directv (#158929)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 17:03:53 +01:00
Pete Sage
1114ce8509 Sonos increase wait for groups timeout (#159108) 2025-12-15 16:57:11 +01:00
Denis Shulyaka
8687a7b306 Add GPT-5.2 support (#158783) 2025-12-15 16:39:01 +01:00
Abílio Costa
d325f677df Deprecate TargetSelectorData in favor of TargetSelection (#158734)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 14:45:35 +00:00
Petro31
f786ec18a9 Add common template test framework to vacuum platform (#157846) 2025-12-15 15:22:56 +01:00
Kamil Breguła
ef0add1d6c Set station name as device name in GIOS (#155762)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 14:55:48 +01:00
hanwg
46f56c60f2 Remove deprecated yaml import from Telegram bot (#158520) 2025-12-15 12:57:41 +01:00
dependabot[bot]
060b258921 Bump actions/upload-artifact from 5.0.0 to 6.0.0 (#159066)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-12-15 12:54:19 +01:00
Aidan Timson
8eb3e63d9d Update systembridgeconnector to 5.2.4, fix media source (#158917) 2025-12-15 12:47:34 +01:00
Joost Lekkerkerker
6c96acda82 Add integration_type device to harmony (#159091) 2025-12-15 12:34:20 +01:00
Jan Čermák
c82b179e03 Bump Docker base image to 2025.12.0 (#159077) 2025-12-15 12:29:16 +01:00
Joost Lekkerkerker
1e1265c99c Add integration_type device to goodwe (#159083) 2025-12-15 12:25:20 +01:00
Joost Lekkerkerker
22e975f911 Add integration_type device to govee_ble (#159087) 2025-12-15 12:23:55 +01:00
Joost Lekkerkerker
b1e3f8d4f4 Add integration_type service to google_tasks (#159085) 2025-12-15 12:23:35 +01:00
Joost Lekkerkerker
95fe573620 Add integration_type hub to growatt_server (#159088) 2025-12-15 12:23:09 +01:00
Joost Lekkerkerker
d29d82cf20 Add integration_type service to google_photos (#159084) 2025-12-15 12:22:12 +01:00
Joost Lekkerkerker
23459d69c9 Add integration_type hub to hanna (#159090) 2025-12-15 12:21:26 +01:00
Joost Lekkerkerker
5209f4d296 Add integration_type service to here_travel_time (#159092) 2025-12-15 12:20:55 +01:00
Joost Lekkerkerker
39c5983571 Add integration_type service to google_travel_time (#159086) 2025-12-15 12:20:30 +01:00
Robert Resch
b5015faffe Revert "Pin pycares to 4.11.0" (#159076) 2025-12-15 12:17:49 +01:00
hanwg
16d3707d13 Add subentry description for Telegram bot (#158761) 2025-12-15 11:50:44 +01:00
TimL
9bb6d740e0 Bump pysmlight to v0.2.13 (#159075)
Co-authored-by: Tim Lunn <tim@feathertop.org>
2025-12-15 11:46:32 +01:00
mithomas
f640795de1 Bump aiodns to 3.6.1 (#159073) 2025-12-15 11:12:10 +01:00
Robert Resch
c1b512d50a Bump uv to 0.9.17 (#159044)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-12-15 11:10:50 +01:00
Raphael Hehl
0ba43b22a9 Improve entity names for unifiprotect sensors (#158803)
Co-authored-by: RaHehl <rahehl@users.noreply.github.com>
2025-12-15 10:43:09 +01:00
Kai Winter
b11b790958 Increase http timeout in wolflink (#158912) 2025-12-15 10:26:51 +01:00
dependabot[bot]
81fb769233 Bump dessant/lock-threads from 5.0.1 to 6.0.0 (#159065)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 10:13:30 +01:00
dependabot[bot]
c5ac806832 Bump actions/download-artifact from 6.0.0 to 7.0.0 (#159064)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 10:07:11 +01:00
dependabot[bot]
256baf5097 Bump actions/cache from 5.0.0 to 5.0.1 (#159063)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 10:06:31 +01:00
Paul Tarjan
cccefddb72 Set default RTSP transport protocol to TCP in Generic Camera (#159061) 2025-12-15 10:06:09 +01:00
dependabot[bot]
85294b1d96 Bump github/codeql-action from 4.31.7 to 4.31.8 (#159062)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 10:05:18 +01:00
Allen Porter
ffcde8dd74 Fix slow event state updates for remote calendar (#159058) 2025-12-15 10:02:24 +01:00
Joost Lekkerkerker
13b50b355e Add integration_type hub to elkm1 (#159001) 2025-12-15 09:58:25 +01:00
Joost Lekkerkerker
7a2592173b Add integration_type service to emoncms (#159003) 2025-12-15 09:57:53 +01:00
Joost Lekkerkerker
d3b36d0081 Add integration_type device to emonitor (#159004) 2025-12-15 09:57:20 +01:00
Joost Lekkerkerker
5bea0d57ec Add integration_type device to epson (#159008) 2025-12-15 09:49:19 +01:00
Joost Lekkerkerker
903c73b5dd Add integration_type device to escea (#159009) 2025-12-15 09:48:47 +01:00
Joost Lekkerkerker
603c664c9b Add integration_type device to evil_genius_labs (#159010) 2025-12-15 09:48:07 +01:00
epenet
43d0d582ef Cleanup deprecated hassio constants and functions (#158802) 2025-12-15 09:45:38 +01:00
Joost Lekkerkerker
c12d2ec0bd Add integration_type service to faa_delays (#159011) 2025-12-15 09:44:37 +01:00
Joost Lekkerkerker
bfedcef9b9 Add integration_type service to fing (#159012) 2025-12-15 09:44:00 +01:00
Joost Lekkerkerker
d41d93c44e Add integration_type service to fireservicerota (#159014) 2025-12-15 09:41:13 +01:00
Joost Lekkerkerker
11cc8beac1 Add integration_type service to fivem (#159016) 2025-12-15 09:40:48 +01:00
Joost Lekkerkerker
0f827403c5 Add integration_type hub to flipr (#159018) 2025-12-15 09:39:11 +01:00
Joost Lekkerkerker
4827a603e5 Add integration_type hub to flo (#159019) 2025-12-15 09:38:18 +01:00
Joost Lekkerkerker
e3f3861d4e Add integration_type hub to flume (#159020) 2025-12-15 09:37:48 +01:00
Joost Lekkerkerker
60df4433ca Add integration_type device to foscam (#159021) 2025-12-15 09:37:18 +01:00
Josef Zweck
46b6557348 Fix CI by patching correctly in ekeybionyx test (#159070) 2025-12-15 09:29:39 +01:00
Brett Adams
639e736c66 Bump teslemetry-stream to 0.8.2 (#159056) 2025-12-15 09:27:52 +01:00
Ludovic BOUÉ
8a198401a7 Add IKEA ALPSTUGA air quality monitor Matter fixture (#158986) 2025-12-15 09:23:13 +01:00
Jordan Harvey
c917dfeed9 Update pyanglianwater requirement to version 3.1.0 (#159046) 2025-12-15 06:59:16 +01:00
Allen Porter
25155de30c Bump ical to 12.1.2 (#158965) 2025-12-14 21:18:05 -08:00
Richard Polzer
6a927c37be Improve auth handling and test coverage for ekeybionyx (#159057) 2025-12-14 21:17:00 -08:00
Brett Adams
9b41bb09a7 Bump Tesla Fleet to 1.3.0 (#159048) 2025-12-14 18:34:11 -08:00
Xidorn Quan
e58fc6976d Bump aioasuswrt to 1.5.4 (#159038) 2025-12-15 01:04:42 +01:00
Kevin Fronczak
9def627a57 Bump blinkpy to 0.25.2 (#159049) 2025-12-15 00:57:21 +01:00
Paul Tarjan
9b56759c1e Add 'task:' label to exception handler log messages (#158674) 2025-12-14 23:55:13 +01:00
Joost Lekkerkerker
c3f743cafd Add integration_type hub to fujitsu_fglair (#159026) 2025-12-14 23:51:59 +01:00
Joost Lekkerkerker
160c495ddc Add integration_type hub to freedompro (#159024) 2025-12-14 23:50:05 +01:00
Ludovic BOUÉ
9a1cd8545d Add Ikea scroll wheel Matter fixture (#159037) 2025-12-14 23:49:55 +01:00
Joost Lekkerkerker
fa81e6cd04 Add integration_type device to frontier_silicon (#159025) 2025-12-14 23:49:38 +01:00
Joost Lekkerkerker
746f4ef1e2 Add integration_type service to glances (#159033) 2025-12-14 23:49:31 +01:00
Joost Lekkerkerker
0149de6ba6 Add integration_type service to anglian_water (#158839) 2025-12-14 21:16:52 +01:00
Joost Lekkerkerker
1df2f18e0a Add integration_type service to environment_canada (#159007) 2025-12-14 21:12:54 +01:00
Joost Lekkerkerker
5800824893 Add integration_type service to firefly_iii (#159013) 2025-12-14 21:12:23 +01:00
Joost Lekkerkerker
aac07b6b4b Add integration_type device to fully_kiosk (#159027) 2025-12-14 21:10:29 +01:00
Joost Lekkerkerker
2448ce1970 Add integration_type service to garages_amsterdam (#159028) 2025-12-14 21:08:34 +01:00
Joost Lekkerkerker
7b40e3b8a7 Add integration_type service to geocaching (#159030) 2025-12-14 21:07:31 +01:00
Joost Lekkerkerker
29d06cfcc9 Add integration_type service to github (#159032) 2025-12-14 19:29:44 +01:00
Joost Lekkerkerker
365d168ddd Add integration_type device to gardena_bluetooth (#159029) 2025-12-14 19:20:54 +01:00
Joost Lekkerkerker
234191336e Add integration_type service to fitbit (#159015) 2025-12-14 10:19:34 -08:00
Joost Lekkerkerker
ba57b72658 Add integration_type service to elvia (#159002) 2025-12-14 19:09:12 +01:00
Allen Porter
bb08b315b8 Add exception handling for rate limited or unauthorized MQTT requests (#158997) 2025-12-14 18:45:12 +01:00
Petro31
50621df244 Update unnecessary error logging of unknown and unavailable source states from mold indicator (#158979) 2025-12-14 16:52:38 +01:00
Jan Bouwhuis
2db7b5c99f Assume cover or valve is always "running" in google assistant when the state is assumed or the position is reported to allow it to be be stopped (#158919) 2025-12-14 10:24:40 -05:00
Michael
78af3acf35 Bump pyfritzhome to 0.6.18 (#158877) 2025-12-14 08:12:25 +01:00
Joost Lekkerkerker
b72f04d44e Add integration_type hub to electrasmart (#158942) 2025-12-14 07:17:50 +01:00
Joost Lekkerkerker
35f287e330 Add integration_type hub to ekeybionyx (#158941) 2025-12-14 07:16:40 +01:00
Joost Lekkerkerker
0a55f83b46 Add integration_type hub to econet (#158940) 2025-12-14 07:14:44 +01:00
Joost Lekkerkerker
5030d0ba90 Add integration_type device to ecoforest (#158939) 2025-12-14 07:13:44 +01:00
Joost Lekkerkerker
f582f06ee4 Add integration_type service to eafm (#158937) 2025-12-14 06:59:46 +01:00
Joost Lekkerkerker
662bada5d8 Add integration_type hub to duotecno (#158936) 2025-12-14 06:59:13 +01:00
Joost Lekkerkerker
3ca338dd25 Add integration_type device to dunehd (#158935) 2025-12-14 06:58:03 +01:00
Joost Lekkerkerker
9337a0e71b Add integration_type device to droplet (#158933) 2025-12-14 06:56:08 +01:00
Joost Lekkerkerker
ccbb00197d Add integration_type hub to drop_connect (#158932) 2025-12-14 06:55:22 +01:00
Joost Lekkerkerker
0f59c17e61 Add integration_type service to dexcom (#158928) 2025-12-14 06:42:34 +01:00
Joost Lekkerkerker
6253ade3e2 Add integration_type service to datadog (#158927) 2025-12-14 06:40:48 +01:00
Joost Lekkerkerker
e5890378a1 Add integration_type device to daikin (#158926) 2025-12-14 06:40:29 +01:00
Joost Lekkerkerker
b8ab0bcadf Add integration_type service to dnsip (#158930) 2025-12-13 16:25:51 -06:00
Joost Lekkerkerker
19cb827577 Add integration_type device to doorbird (#158931) 2025-12-13 16:23:37 -06:00
Joost Lekkerkerker
03676d7e5a Add integration_type hub to ecobee (#158938) 2025-12-13 16:23:15 -06:00
Magnus
13f3b49b96 Bump aioasuswrt 1.5.3 (#158882) 2025-12-13 22:43:21 +01:00
Allen Porter
90c8c56a06 Suppress roborock failures under some unavailability threshold (#158673)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 22:30:21 +01:00
Josef Zweck
afb9e18a7d Add brew by weight controls to lamarzocco (#158169) 2025-12-13 22:28:11 +01:00
Andrew Jackson
2c2934065f Bump aiomealie to 1.1.1 and statically define mealplan entry types (#158907) 2025-12-13 22:26:31 +01:00
mettolen
0bead67df9 Add device uptime to Airobot integration (#158516) 2025-12-13 22:20:52 +01:00
James Cole
2895849203 Update strings for Firefly III integration (#158911) 2025-12-13 22:20:30 +01:00
David Recordon
b2400708ac Add myself as a maintainer for Control4 (#158948) 2025-12-13 22:15:35 +01:00
Anthony Garera
0bed9c20b3 Bump python-overseerr to 0.8.0 (#158924) 2025-12-13 19:31:21 +01:00
Brett Adams
d3fb7a7b87 Bump tesla-fleet-api to 1.2.7 (#158904) 2025-12-13 15:02:19 +01:00
Bouwe Westerdijk
60dcca4143 Show Plugwise configuration-link on gateway only (#158094) 2025-12-13 11:38:23 +01:00
Paul Tarjan
01f498f239 Clarify previous state in total_increasing warning message (#158805) 2025-12-13 11:15:37 +01:00
Andre Lengwenus
15055b8e8e Fix race condition in LCN climate and cover entites (#158894) 2025-12-13 11:12:20 +01:00
Bouwe Westerdijk
6826619e12 Revert adding entity_category to Plugwise thermostat schedule select (#158901) 2025-12-13 11:08:17 +01:00
Joost Lekkerkerker
b50a8e04a8 Add integration_type hub to airtouch5 (#158834)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:47:27 +01:00
Joost Lekkerkerker
c6c67c5357 Add integration_type hub to blue_current (#158863) 2025-12-13 10:46:12 +01:00
Joost Lekkerkerker
c82803d1e2 Add integration_type hub to agent_dvr (#158829)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:45:09 +01:00
Joost Lekkerkerker
732b30f181 Add integration_type hub to airzone (#158835)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:44:05 +01:00
Joost Lekkerkerker
0e2e57a657 Add integration_type device to android_ip_webcam (#158838)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:42:39 +01:00
Joost Lekkerkerker
f00b0080a9 Add integration_type device to advantage_air (#158826)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:39:58 +01:00
Joost Lekkerkerker
ad970c1234 Add integration_type hub to cert_expiry (#158897) 2025-12-13 10:39:14 +01:00
Joost Lekkerkerker
02ec56bffa Add integration_type device to ccm15 (#158896)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:37:36 +01:00
Joost Lekkerkerker
8388c290bf Add integration_type hub to canary (#158895) 2025-12-13 09:41:01 +01:00
Joost Lekkerkerker
576ee99faf Add integration_type hub to control4 (#158900) 2025-12-13 09:36:36 +01:00
Joost Lekkerkerker
8a3534c345 Add integration_type service to coinbase (#158899) 2025-12-13 09:31:54 +01:00
Joost Lekkerkerker
e1e91c5568 Add integration_type service to cloudflare (#158898) 2025-12-13 09:31:25 +01:00
epenet
1e09bddb1d Cleanup deprecated alias in core (#158799) 2025-12-13 09:29:15 +01:00
Joost Lekkerkerker
90e4340595 Add integration_type hub to brunt (#158870)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2025-12-13 09:04:05 +01:00
Joost Lekkerkerker
120b17349c Add integration_type service to aussie_broadband (#158853) 2025-12-13 08:56:35 +01:00
Joost Lekkerkerker
8a26961304 Add integration_type service to aurora (#158852) 2025-12-13 08:56:01 +01:00
Joost Lekkerkerker
407b675080 Add integration_type device to atag (#158850) 2025-12-13 08:55:35 +01:00
Joost Lekkerkerker
274844271b Add integration_type hub to aseko_pool_live (#158849) 2025-12-13 08:54:46 +01:00
Joost Lekkerkerker
f11e4e7bda Add integration_type hub to aosmith (#158843) 2025-12-13 08:52:45 +01:00
Joost Lekkerkerker
96f8c39c6f Add integration_type device to anthemav (#158841) 2025-12-13 08:51:25 +01:00
Joost Lekkerkerker
77b79fef8d Add integration_type hub to anova (#158840) 2025-12-13 08:50:24 +01:00
mkmer
a0d2f285f3 blink: Remove mkmer as codeowner (#158884) 2025-12-13 08:45:13 +01:00
Joost Lekkerkerker
3aef05d1ec Add integration_type hub to airzone_cloud (#158836) 2025-12-13 08:43:57 +01:00
Joost Lekkerkerker
510e391ee4 Add integration_type device to airtouch4 (#158833) 2025-12-13 08:41:17 +01:00
Joost Lekkerkerker
54adfdd694 Add integration_type device to bluesound (#158865) 2025-12-13 08:38:48 +01:00
Joost Lekkerkerker
d45f920b4a Add integration_type service to amberelectric (#158837) 2025-12-13 08:37:16 +01:00
Joost Lekkerkerker
3080ef9a4a Add integration_type device to airthings_ble (#158832) 2025-12-13 08:36:06 +01:00
Joost Lekkerkerker
51cebb52f3 Add integration_type hub to airthings (#158831) 2025-12-13 08:34:28 +01:00
Joost Lekkerkerker
7b0d4c47b7 Add integration_type service to airnow (#158830) 2025-12-13 08:33:53 +01:00
Joost Lekkerkerker
a660ab3f97 Add integration_type service to aftership (#158828) 2025-12-13 08:32:31 +01:00
Joost Lekkerkerker
dd8fc16788 Add integration_type service to aemet (#158827) 2025-12-13 08:32:01 +01:00
Joost Lekkerkerker
2b0fab0468 Add integration_type service to brottsplatskartan (#158869) 2025-12-13 08:30:59 +01:00
Joost Lekkerkerker
3bb88ed433 Add integration_type hub to bosch_shc (#158868) 2025-12-13 08:30:04 +01:00
Joost Lekkerkerker
984385cd98 Add integration_type service to buienradar (#158871) 2025-12-13 08:27:55 +01:00
Joost Lekkerkerker
09de108676 Add integration_type service to caldav (#158872) 2025-12-13 08:26:40 +01:00
Joost Lekkerkerker
ebc7581718 Add integration_type hub to bmw_connected_drive (#158866) 2025-12-13 08:26:16 +01:00
Joost Lekkerkerker
e55162812d Add integration_type hub to blink (#158862) 2025-12-13 08:22:22 +01:00
Joost Lekkerkerker
aa6ccaa024 Add integration_type device to blebox (#158860) 2025-12-13 08:21:25 +01:00
Joost Lekkerkerker
e1b009a6de Add integration_type device to balboa (#158859) 2025-12-13 08:20:12 +01:00
Joost Lekkerkerker
91ddc525b0 Add integration_type service to azure_event_hub (#158857) 2025-12-13 08:18:56 +01:00
Joost Lekkerkerker
d7d7954ac2 Add integration_type service to azure_devops (#158856) 2025-12-13 08:18:35 +01:00
Joost Lekkerkerker
e87c260df7 Add integration_type service to azure_data_explorer (#158855) 2025-12-13 08:18:13 +01:00
Joost Lekkerkerker
5185c6cd68 Add integration_type hub to arve (#158848) 2025-12-13 08:17:37 +01:00
Joost Lekkerkerker
7599c918e2 Add integration_type hub to august (#158851) 2025-12-12 23:00:06 +01:00
Joost Lekkerkerker
fa7e22ec91 Add integration_type device to arcam_fmj (#158846) 2025-12-12 22:59:47 +01:00
Joost Lekkerkerker
606519e51b Add integration_type device to baf (#158858) 2025-12-12 22:59:28 +01:00
Joost Lekkerkerker
8e39e010f7 Add integration_type device to bluemaestro (#158864) 2025-12-12 22:59:13 +01:00
Joost Lekkerkerker
dc01cf49a0 Add integration_type hub to bond (#158867) 2025-12-12 22:58:57 +01:00
Joost Lekkerkerker
1f3ad382f1 Set Denon AVR integration type to device (#158815) 2025-12-12 20:33:56 +01:00
Joost Lekkerkerker
2595c7dcb2 Set Actron Air integration type to hub (#158816) 2025-12-12 20:33:25 +01:00
Kamil Breguła
d445b320de Accept URLs in WLED Host input (#157793)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
2025-12-12 18:55:03 +01:00
epenet
7b6df1a8a0 Cleanup deprecated typing helpers (#158806) 2025-12-12 17:04:41 +01:00
Manu
2a151dcd19 Add tests for discovery to Xbox integration (#158808) 2025-12-12 17:02:32 +01:00
epenet
adbab150af Move blue_current services to separate module (#158389) 2025-12-12 16:50:34 +01:00
Allen Porter
d20edf7928 Improve Roborock exception logging behavior for Zeo/Dyad devices (#158465)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-12 16:43:45 +01:00
Ludovic BOUÉ
7d6d37fe76 Fix Matter Door Lock Operating Mode select entity (#158468) 2025-12-12 16:30:48 +01:00
Ludovic BOUÉ
228e0453a7 Add Matter Thermostat remote sensing status (#157650) 2025-12-12 16:26:27 +01:00
Raphael Hehl
1da31c0530 Move icons to icons.json for unifiprotect (#158800)
Co-authored-by: RaHehl <rahehl@users.noreply.github.com>
2025-12-12 16:23:11 +01:00
Joost Lekkerkerker
41ad15e577 Bump pySmartThings to 3.5.1 (#158795) 2025-12-12 15:45:08 +01:00
Markus Jacobsen
421af881fe Add video source reporting to Bang & Olufsen (#158675) 2025-12-12 15:40:12 +01:00
Klaas Schoute
715a484f7e Add AutarcoSensorBase class for Autarco sensors (#158691)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-12-12 15:39:18 +01:00
Samuel Xiao
0a789f51b8 Switchbot Cloud: Fixed binary sensors didn't update automatically (#158434)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-12-12 15:39:08 +01:00
epenet
fa25d45123 Remove incorrect bring test (#158797) 2025-12-12 15:32:27 +01:00
johanzander
6d255b2521 Add state_class to Growatt power and energy sensors (#158705)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-12 15:27:47 +01:00
peteS-UK
5ffb39f064 Trap for missing UUID in config_flow for Squeezebox (#158721)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-12-12 15:15:04 +01:00
Zoltán Farkasdi
d642109436 Netatmo NOCamera on/off fix (#158741) 2025-12-12 14:57:57 +01:00
Heindrich Paul
10f6d8d14f Add diagnostics support for Nederlandse Spoorwegen integration (#158722)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-12 14:36:35 +01:00
Thomas55555
a94678cb06 Bump google air quality api to 2.0.2 (#158742) 2025-12-12 14:35:07 +01:00
Manu
0d8d466003 Increase Xbox update interval to 15 seconds and refactor title data handling (#158780) 2025-12-12 14:04:25 +01:00
Marc Mueller
8ddf3e1734 Update pytest warnings filter (#158790) 2025-12-12 13:54:00 +01:00
cdutr
d88047a750 Migrate Blink component to use hardware_id instead of device_id (#158765) 2025-12-12 13:49:19 +01:00
Jordan Harvey
61c7ac81d6 Bump pynintendoparental to 2.1.1 (#158779) 2025-12-12 13:45:48 +01:00
Josef Zweck
bbe07bddb0 Bump pylamarzocco to 2.2.4 (#158774) 2025-12-12 13:45:14 +01:00
Denis Shulyaka
a3afc2beb1 Bump openai to 2.11.0 (#158785) 2025-12-12 13:40:43 +01:00
epenet
374cd93d3d Replace Tuya remap methods with helper class (#158718) 2025-12-12 13:37:29 +01:00
Maciej Bieniek
6e99411084 Add get_kvs_value and set_kvs_value actions for Shelly RPC devices (#157349) 2025-12-12 13:15:25 +01:00
dependabot[bot]
41d5415c86 Bump actions/cache from 4.3.0 to 5.0.0 (#158771) 2025-12-12 10:39:58 +01:00
Allen Porter
052d56f358 Bump ical to 12.1.1 (#158770) 2025-12-12 08:34:22 +01:00
Abílio Costa
0a676b5812 Remove alarm panel test from text tests (#158743) 2025-12-12 02:18:40 +01:00
Michael
1f4cf67daa Add turned off and turned on triggers to switch platform (#158688)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-11 22:02:22 +00:00
Maikel Punie
bb4ec229ce Add Velbus VLP file loading (#154883) 2025-12-11 22:53:01 +01:00
ndrwrbgs
ff62b460d5 Update advanced_options display text for MQTT (#158728) 2025-12-11 22:16:35 +01:00
Willem-Jan van Rootselaar
9b48e92940 Bump python-bsblan to 3.1.4 (#158725)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-12-11 18:04:57 +00:00
Magnus
c03b9d1f87 Bump aioasuswrt to 1.5.2 (#158727) 2025-12-11 17:31:46 +00:00
Koknico
3f30df203c Add support for AtlanticDomesticHotWaterProductionV2_CETHI_V4_IOComponent to Overkiz (#157872) 2025-12-11 13:10:37 +01:00
epenet
7fe0d96c88 Remove unnecessary wrapper base method in Tuya (#158708) 2025-12-11 10:13:24 +01:00
Joost Lekkerkerker
cdc2192bba Clean up Homelink tests (#158685)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-11 09:10:02 +01:00
Matt Zimmerman
74b1c1f6fd Bump python-smarttub to 0.0.46 (#158702) 2025-12-11 09:07:46 +01:00
J. Nick Koston
69c7a7b0ab Pin pycares to 4.11.0 (#158695) 2025-12-10 22:00:59 -05:00
Norbert Rittel
ef302215cc Add two common config flow strings in energyid (#158680) 2025-12-10 21:23:18 +01:00
Norbert Rittel
6378f5f02a Use common reauth_successful string in rituals_perfume_genie (#158684) 2025-12-10 21:14:25 +01:00
Bouwe Westerdijk
79245195cd Bump Plugwise to v1.11.0 (#158067) 2025-12-10 21:03:27 +01:00
epenet
d0e33a6e04 Use process_raw_value in Tuya JsonTypeInformation (#158517) 2025-12-10 20:13:16 +01:00
Joost Lekkerkerker
f55fc788db Cleanup homelink config flow (#158479) 2025-12-10 18:39:44 +01:00
epenet
6152e0fa27 Split action and state wrapper in Tuya alarm control panel (#158532) 2025-12-10 18:37:04 +01:00
Matthias Alphart
f1a89741c0 Add counter for KNX DataSecure undecodable telegrams (#157844) 2025-12-10 17:59:00 +01:00
Paul Tarjan
7629c9f280 Fix flaky test_stream_source timeout in generic camera tests (#158506) 2025-12-10 17:49:27 +01:00
Abílio Costa
6b8650c6d9 Remove uneeded check in whirlpool oven temperature sensors (#157997) 2025-12-10 17:45:34 +01:00
Paul Tarjan
48f186368a Fix flaky playstation_network test_image_platform test (#158296) 2025-12-10 17:07:58 +01:00
Allen Porter
d65baac8d4 Bump python-roborock to 3.12.2 (#158572) 2025-12-10 17:05:57 +01:00
Paul Tarjan
d57801407b Fix flaky test_calls_not_allowed by using thread-safe event signaling (#158504) 2025-12-10 16:38:34 +01:00
Markus Jacobsen
4495a76557 Change Bang & Olufsen "stopped" state translation (#158534) 2025-12-10 16:37:48 +01:00
Paul Tarjan
99dfb93ac0 Fix flaky test_rename_entity_collision test (#158297) 2025-12-10 16:36:52 +01:00
Abílio Costa
7c7c0aad25 Rename trigger helper state checkers (#158537)
Co-authored-by: Robert Resch <robert@resch.dev>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-10 14:56:56 +00:00
Andrew Jackson
5992898340 Add measurement state class to ohme sensors (#158541) 2025-12-10 15:35:24 +01:00
Sander Blomvågnes
4f2ff9a4f4 Add codeowner and integration_type to Entur manifest (#158543) 2025-12-10 15:26:24 +01:00
bestycame
a8a135c2ca Bump hanna-cloud to version 0.0.7 (#158536)
Co-authored-by: Olivier d'Otreppe <odotreppe@abbove.com>
2025-12-10 14:50:05 +01:00
epenet
43e241ee39 Use process_raw_value in Tuya RawTypeInformation (#158521) 2025-12-10 10:44:49 +01:00
Kinachi249
6af7052b9d Bump PyCync to 0.5.0 (#158509) 2025-12-10 08:15:47 +01:00
dependabot[bot]
c0aa35ff6d Bump codecov/codecov-action from 5.5.1 to 5.5.2 (#158515) 2025-12-10 07:27:42 +01:00
Ludovic BOUÉ
2c7763e350 Fix Matter epoch timestamp sensors (#157600) 2025-12-10 07:13:21 +01:00
Joost Lekkerkerker
95e344ea44 Cleanup homelink (#158477) 2025-12-10 01:09:23 +01:00
Yevhenii Vaskivskyi
7ed8613411 Bump asusrouter to 1.21.3 (#158492) 2025-12-09 22:56:11 +01:00
Anton Dalgren
4ac0567ccc Add AirPatrol integration (#149247)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-12-09 21:26:21 +01:00
epenet
bc031e7a81 Improve Tuya HVACMode handling (#158042)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-09 21:17:57 +01:00
Raphael Hehl
ad1ba629c5 Fix typos in UniFi Protect integration (#158478) 2025-12-09 21:13:38 +01:00
Paul Tarjan
0c2cb460cb Fix flaky laundrify coordinator test (#158460) 2025-12-09 21:12:55 +01:00
Kira
5388740c83 Bump blinkpy to 0.25.1 (#158135)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-12-09 20:53:59 +01:00
Raphael Hehl
2a54d4c3a9 Add model_id to NVR device info in UniFi Protect (#158481)
Co-authored-by: RaHehl <rahehl@users.noreply.github.com>
2025-12-09 20:18:04 +01:00
Steve Easley
2008972215 Bump kaleidescape requirement version to v1.0.2 (#158068) 2025-12-09 20:12:55 +01:00
Jordan Harvey
39004bd0a2 Update pynintendoparental to 2.1.0 (#158487) 2025-12-09 20:11:28 +01:00
Michael Hansen
bb847ce3ff Bump pysilero-vad to 3.0.1 (#158486) 2025-12-09 13:08:34 -06:00
Denis Shulyaka
05920a9c73 Bump openai to 2.9.0 (#158476) 2025-12-09 12:30:57 -05:00
epenet
61499a5ad4 Fix Tuya BitmapTypeInformation parsing (#158474) 2025-12-09 17:39:54 +01:00
epenet
0076aafa6e Move color_extractor services to separate module (#158341) 2025-12-09 17:32:03 +01:00
epenet
c50f4d6d2d Add Tuya local_strategy to Tuya diagnostic (#158450) 2025-12-09 17:29:11 +01:00
hanwg
68036099a2 Remove timeout parameter for Telegram bot actions (#155198)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-12-09 16:53:02 +01:00
Willem-Jan van Rootselaar
180053fe98 Bump python-bsblan to v3.1.3 (#157626) 2025-12-09 15:33:04 +01:00
Thomas D
280c25cb85 Enable volvo engine status for all engine types (#158437) 2025-12-09 14:35:02 +01:00
Petro31
4064b6d28c Sort weather platform keys (#158106)
Co-authored-by: Josef Zweck <josef@zweck.dev>
2025-12-09 14:29:01 +01:00
epenet
ff25809a3e Do not unregister google_mail services (#158431) 2025-12-09 13:52:37 +01:00
mettolen
245f47c7fb Add diagnostics to Airobot integration (#158247) 2025-12-09 12:55:37 +01:00
Andre Lengwenus
86135a19d1 Bump pypck to 0.9.7 (#158089) 2025-12-09 12:43:21 +01:00
Simon Lamon
2e038250a9 Bump doorbirdpy to v3.0.11 (#151178)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-12-09 10:37:18 +01:00
Jordan Harvey
88c7c6fc8a Update pynintendoparental to 2.0.0 (#158285) 2025-12-09 08:47:52 +01:00
epenet
d691862d0d Bump heatmiserV3 to 2.0.4 (#158304) 2025-12-09 08:47:16 +01:00
Allen Porter
cceaff7bc6 Fix roborock off peak electricity timer (#158292) 2025-12-09 08:24:04 +01:00
Michael Hansen
079c6daa63 Replace microVAD with Silero VAD (ggml) (#158282) 2025-12-08 20:02:14 -06:00
Michel D'Astous
b120ae827f Fix webhook exception when empty json data is sent (#158254) 2025-12-08 23:44:59 +01:00
Tsvi Mostovicz
c1227aaf1f Jewish Calendar coordinator (#152434) 2025-12-08 22:41:58 +01:00
Artur Pragacz
c0365dfe99 Query state after turn on in Onkyo (#158093) 2025-12-08 21:49:00 +01:00
Petro31
02aa3fc906 Fix legacy template entity_id field in migration (#158105)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-12-08 21:07:40 +01:00
Marcel van der Veldt
42e55491cc Skip check for onboarding done in Music Assistant integration (#158270) 2025-12-08 20:28:02 +01:00
Harvey
33e09c4967 Bump HueBLE to 2.1.0 (#158197) 2025-12-08 19:55:55 +01:00
Petro31
6f5507670f Fix multiple top-level support for template integration (#158244) 2025-12-08 19:19:52 +01:00
Paul Bottein
765be3f047 Update frontend to 20251203.2 (#158259) 2025-12-08 18:08:03 +01:00
omrishiv
12bc9e9f68 fix Lutron Caseta smart away subscription (#158082)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-08 17:45:36 +01:00
Nic Eggert
2617c4a453 Add eGauge integration (#155279)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-08 17:33:11 +01:00
andreimoraru
0e6d9ecbdc Bump yt-dlp to 2025.12.08 (#158253) 2025-12-08 16:45:23 +01:00
Sander Blomvågnes
5cdbbe999d Move Entur constants to separate module (#158256) 2025-12-08 16:40:54 +01:00
Yevhenii Vaskivskyi
5ca61386f8 Bump asusrouter to 1.21.1 (#158192) 2025-12-08 16:16:25 +01:00
Thomas55555
6d6ee866a6 Remove stale fixture in Google Air Quality (#158235) 2025-12-08 15:44:05 +01:00
Paul Bottein
eeb2b2febc Be more specific about winter mode in the description (#158230)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-12-08 15:28:17 +01:00
Thomas55555
a6c7bd76eb Bump google air quality api to 2.0.0 (#158234) 2025-12-08 13:41:28 +01:00
epenet
470f5a2396 Validate action translation placeholders (#158225)
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
2025-12-08 13:40:53 +01:00
Marc Mueller
d934fd974d Update Python to 3.13.11 and 3.14.2 in CI (#158238) 2025-12-08 13:30:45 +01:00
epenet
edc81b706d Fix teslemetry service description placeholders (#158240) 2025-12-08 12:50:23 +01:00
epenet
03aaebe718 Fix zwave_js service description placeholders (#158236) 2025-12-08 12:47:35 +01:00
epenet
98d61aa5b2 Fix yeelight service description placeholders (#158239) 2025-12-08 12:46:33 +01:00
Jan Bouwhuis
fe5d411856 Fix description placeholders for system_bridge (#158232) 2025-12-08 12:26:46 +01:00
Petar Petrov
efa5a773eb Add query params handling for requests in Supervisor API (#157832)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2025-12-08 12:09:59 +01:00
Jordan Harvey
32399de5f1 Bump pyanglianwater to 3.0.0 (#158121) 2025-12-08 11:01:41 +01:00
Klaas Schoute
a1ad28c066 Update powerfox to v2.0.0 (#158223) 2025-12-08 10:59:59 +01:00
Álvaro Fernández Rojas
6faccf4327 Update aioairzone to v1.0.4 (#158208)
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2025-12-08 10:28:26 +01:00
Allen Porter
2ac15ab67d Ensure Roborock disconnects mqtt on unload/stop (#158144)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-08 09:36:34 +01:00
dependabot[bot]
d599bb9553 Bump github/codeql-action from 4.31.6 to 4.31.7 (#158218)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 08:51:12 +01:00
Klaas Schoute
92ee37017d Update energyzero to v4.0.1 (#158211) 2025-12-08 08:50:14 +01:00
Allen Porter
adf698d570 Bump python-roborock to 3.10.10 (#158212) 2025-12-07 20:06:50 -08:00
taltenbach
6ce9a13816 Add Roborock attach/detach mop status translations (#158184) 2025-12-07 16:33:24 -08:00
epenet
9cb9efeb88 Make Tuya find_dpcode a class method (#158028) 2025-12-07 22:32:14 +01:00
J. Nick Koston
ca31134caa Keep persistent BLE connection during Shelly WiFi provisioning (#158145)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-07 14:28:53 -06:00
Raphael Hehl
769578dc51 UnifiProtect: Create NVR device before loading platforms to fix via_device references (#158191) 2025-12-07 21:22:39 +01:00
Thomas55555
9dcabfe804 Use SectionConfig in Google Air Quality (#158188) 2025-12-07 19:49:44 +01:00
Åke Strandberg
dc6c23a58c Add program id codes for Miele WQ1000 (#158175) 2025-12-07 19:34:35 +01:00
Álvaro Fernández Rojas
6ec7efc2b8 Update aioairzone to v1.0.3 (#158181) 2025-12-07 11:54:04 -06:00
Åke Strandberg
97e5b7954e Bump pymiele dependency to 0.6.1 (#158177) 2025-12-07 18:35:28 +01:00
J. Nick Koston
25505752b7 Use "Output" for Shelly RPC switch sub-device names (#158139) 2025-12-07 11:33:00 -06:00
J. Nick Koston
95a347dcf8 Bump aioshelly to 13.23.0 (#158183) 2025-12-07 11:18:53 -06:00
Manu
8c0f3014f7 Fix secure URLs for promotional game media in Xbox integration (#158162) 2025-12-07 11:34:18 +01:00
Josef Zweck
bb3cd3ebd3 Bump pylamarzocco to 2.2.3 (#158104) 2025-12-07 08:57:02 +01:00
Philip Cheong
319d6711c4 Add support for LockStatus.JAMMED to yalexs_ble (#157551)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-06 13:17:09 -06:00
J. Nick Koston
ea3f76c315 Bump yalexs-ble to 3.2.2 (#158124) 2025-12-06 12:16:52 -06:00
Shay Levy
b892cc1cad Revert "Remove Shelly redundant device entry check for sleepy devices" (#158108) 2025-12-06 19:40:05 +02:00
Marc Mueller
3046c7afd8 Fix shelly RuntimeWarnings in tests (#158101) 2025-12-06 11:34:24 -06:00
Raphael Hehl
73dc81034e Implement reconfiguration flow for UniFi Protect integration (#157532)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-06 11:32:43 -06:00
Jesse Hills
f306cde3b6 Add response support to esphome custom actions (#157393)
Co-authored-by: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-06 09:48:20 -06:00
Kevin Stillhammer
38c5e483a8 add entity_picture to fressnapf_tracker (#158099) 2025-12-06 13:28:53 +01:00
Michael
ce14544ec1 Add packet loss sensor to Ping integration (#158081) 2025-12-06 10:57:31 +01:00
mettolen
87b9c3193e Add sensor entities to Airobot integration (#157938) 2025-12-06 07:57:03 +01:00
Adam Goode
061c38d2a7 Make unifi LEDs EntityCategory.CONFIG (#158088) 2025-12-06 07:51:09 +01:00
Allen Porter
e1720be5a4 Update roborock quality scale (#158024) 2025-12-05 22:52:38 +01:00
Paul Bottein
2d13a92496 Update frontend to 20251203.1 (#158069) 2025-12-05 21:25:01 +01:00
Artur Pragacz
b06bffa815 Add ai_task to core files (#158058) 2025-12-05 21:14:49 +01:00
Joost Lekkerkerker
b8f4b9515b Prevent entsoe from loading (#158036)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-12-05 21:08:57 +01:00
Petro31
3c10e9f1c0 Fix inverted kelvin issue (#158054) 2025-12-05 19:12:12 +00:00
Artur Pragacz
2dec3befcd Assign hass in Condition init (#158062) 2025-12-05 19:04:11 +00:00
J. Nick Koston
7d065bf314 Bump aiodns to 3.6.0 (#158063) 2025-12-05 20:00:09 +01:00
Raphael Hehl
3315680d0b Bump uiprotect to 7.33.2 (#158057) 2025-12-05 19:43:44 +01:00
Markus Jacobsen
ce48c89a26 Fix button event entity creation in Bang & Olufsen (#157982)
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2025-12-05 18:39:58 +00:00
Jan Bouwhuis
f67a926f56 Move lametric URLs out of strings.json (#158051) 2025-12-05 19:35:07 +01:00
Paulus Schoutsen
e0a9d305b2 Use multiple selector for validation in AI task (#158056) 2025-12-05 18:51:18 +01:00
Jan Bouwhuis
4ff141d35e Move example image path out of translatable strings (#158053) 2025-12-05 18:05:09 +01:00
Artur Pragacz
f12a43b2b7 Mark reauthentication in music assistant quality scale (#158055) 2025-12-05 18:02:16 +01:00
Paul Tarjan
35e6f504a3 Fix doorbird duplicate unique ID generation (#158013)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-05 10:17:43 -06:00
Denis Shulyaka
1f68809cf9 Replace deprecated preview image model (#158048) 2025-12-05 07:55:05 -08:00
Paul Bottein
66bddebca1 Add subscribe preview feature endpoint to labs (#157976) 2025-12-05 16:36:56 +01:00
TheJulianJES
2280d779a8 Change ZHA strings for incorrect adapter state (#158021)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-12-05 16:35:34 +01:00
Maciej Bieniek
ebc608845c Do not create restart button for sleeping gen2+ Shelly devices (#158047) 2025-12-05 16:33:11 +01:00
Max Michels
5d13a41926 Move telegram-bot URLs out of strings.json (#155130)
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
Co-authored-by: jbouwh <jan@jbsoft.nl>
2025-12-05 16:33:01 +01:00
Quentin Ulmer
630b40fbba Fix Rituals Perfume Genie (#151537)
Co-authored-by: Joostlek <joostlek@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-05 16:16:51 +01:00
Manu
7fd440c4a0 Add coordinator to Duck DNS integration (#158041) 2025-12-05 15:49:48 +01:00
Petro31
2a116a2a11 Fix missing template key in deprecation repair (#158033) 2025-12-05 15:30:39 +01:00
David Bonnes
f189e3b5ca Bump evohome-async to 1.0.6 (#158005) 2025-12-05 13:27:38 +01:00
wollew
4cd460351d Add Squeezebox binary sensors for player alarm status (#154491)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-12-05 11:43:19 +01:00
Johnny Willemsen
afea571c2c Enhance migration logging for home_connect (#158027) 2025-12-05 11:30:10 +01:00
Manu
e4aadd675e Add reconfigure flow to Duck DNS (#157948) 2025-12-05 10:19:05 +01:00
Abílio Costa
a47255c233 Bump whirlpool-sixth-sense to 1.0.3 (#157996) 2025-12-05 08:27:31 +01:00
hanwg
c1e7492743 Improve action descriptions for Telegram bot (#158022) 2025-12-05 08:26:42 +01:00
Kevin Stillhammer
63e8cf582f Set PARALLEL_UPDATES in fressnapf_tracker (#158008) 2025-12-05 08:21:48 +01:00
Allen Porter
73f23168a2 Bump python-roborock to 3.10.2 (#158020) 2025-12-05 08:20:41 +01:00
Mark Adkins
20d8176515 SharkIQ dep upgrade v1.5.0 (#158015) 2025-12-04 22:00:47 -05:00
Ezra Freedman
c9351a022e Add HassStopMoving intent for covers and valves (#155267)
Co-authored-by: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com>
2025-12-04 22:23:49 +01:00
epenet
4e8a31a4e2 Improve Tuya data validation (#157968)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 22:20:05 +01:00
johanzander
2beb551db3 Replace bare Exception with specific exceptions in Growatt (#157790) 2025-12-04 20:44:41 +01:00
Markus Jacobsen
90cea0325f Bump mozart_api to 5.3.1.108.0 (#157983) 2025-12-04 19:29:35 +00:00
dontinelli
f5dd9d83ac Bump solarlog_cli to 0.6.1 (#157845) 2025-12-04 19:24:33 +00:00
Alsatian67
e0484ba1ff Improve dev error message for YAML platform setup missing method (#155505)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-12-04 20:06:37 +01:00
Kevin Stillhammer
62f758f695 mark quality_scale rules done for fressnapf_tracker (#157990) 2025-12-04 20:03:53 +01:00
Abílio Costa
20d2115122 Bump oralb-ble to 1.0.2 (#157992) 2025-12-04 18:51:16 +01:00
Jan Bouwhuis
2bed7afe0e Move out example URL and IP of strings.json for reolink (#157970) 2025-12-04 18:37:30 +01:00
Petro31
2eeac5f9c9 Update template deprecation to be more explicit (#157965) 2025-12-04 18:34:01 +01:00
Abílio Costa
a35af9097b Remove uneeded async_setup_component from trigger/condition tests (#157873) 2025-12-04 17:21:30 +00:00
Luke Lashley
710b7c2b41 Bump python-Roborock to 3.10.0 (#157980) 2025-12-04 17:26:41 +01:00
Abílio Costa
c058810461 Cache flattened service descriptions in websocket api (#157510)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-12-04 16:05:49 +00:00
Kevin Stillhammer
0ccfd77fef add switch platform to fressnapf_tracker (#157971) 2025-12-04 16:44:53 +01:00
epenet
4805b33a27 Fix unit parsing in Tuya climate entities (#157964) 2025-12-04 16:17:39 +01:00
Hem Bhagat
c333036959 Move translatable URL out of strings.json for ntfy integration (#155859) 2025-12-04 16:17:16 +01:00
Petro31
002eed24f1 Fix template migration errors (#157949) 2025-12-04 16:16:58 +01:00
Jan Bouwhuis
9a9f8271b3 Move pilight URL out of strings.json (#157967) 2025-12-04 16:02:28 +01:00
Paulus Schoutsen
855d7c6e16 Extract WebRTC integration (#157648) 2025-12-04 09:44:24 -05:00
Jordan Harvey
837de55ce6 Set account number as required for Anglian Water config entry (#157939) 2025-12-04 15:39:52 +01:00
epenet
81ed259c59 Move Tuya type information classes to separate module (#157958)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 15:34:04 +01:00
Manu
5f00452c96 Convert image URLs to secure URLs in Xbox integration (#157945) 2025-12-04 15:12:33 +01:00
Jan Bouwhuis
06a44de3fb Move Yeelight URLs out of translatable strings for action descriptions (#157957) 2025-12-04 15:10:50 +01:00
Jan Bouwhuis
11b4d75cfb Move out zwave_js api docs url from strings.json (#157959) 2025-12-04 15:10:26 +01:00
David Rapan
845c9ee05f Fix Starlink's ever updating uptime (#155574)
Signed-off-by: David Rapan <david@rapan.cz>
2025-12-04 14:44:23 +01:00
Jordan Harvey
dedf6b1223 Add pyanglianwater to Anglian Water loggers (#157947) 2025-12-04 13:55:24 +01:00
Felipe Santos
c1b631d049 Remove Intellicode extension from devcontainer (#157894) 2025-12-04 13:43:01 +01:00
milanhin
6cc645bc6c Remove deprecation warning of step_id in ConfigFlow class (#157925) 2025-12-04 13:41:52 +01:00
Jan Bouwhuis
f10866395d Move out URL of Xiaomy_aquara from strings.json (#157937)
Co-authored-by: Michelle "MishManners®™" Duke <36594527+mishmanners@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 12:59:55 +01:00
Jan Bouwhuis
df68448b27 Move translatable URL from rainmachine push_weather_data action description (#157941)
Co-authored-by: Michelle "MishManners®™" Duke <36594527+mishmanners@users.noreply.github.com>
Co-authored-by: Josef Zweck <josef@zweck.dev>
2025-12-04 12:59:15 +01:00
Abílio Costa
bf7b96622c Correct websocket commands test name (#157870) 2025-12-04 11:14:34 +00:00
Kevin Stillhammer
53c644ac5b add light platform to fressnapf_tracker (#157865) 2025-12-04 11:09:53 +01:00
starkillerOG
5e9107e52b Bump reolink_aio to 0.17.1 (#157929) 2025-12-04 10:58:25 +01:00
Jan Bouwhuis
ca9ea267c7 Move teslemetry time-of-use URL out of strings.json (#157874) 2025-12-04 10:34:51 +01:00
ryanjones-gentex
f1bfe2f11e Add HomeLink integration (#136460)
Co-authored-by: Nicholas Aelick <niaexa@syntronic.com>
2025-12-04 10:32:02 +01:00
Franck Nijhof
34cc6036b9 Merge branch 'master' into dev 2025-12-04 09:12:55 +00:00
cdnninja
2facfbadaa Add VeSync type hints and returns (#157900)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2025-12-04 09:19:48 +01:00
cdnninja
1b1dface35 Fix VeSync binary sensor discovery (#157898) 2025-12-04 09:14:35 +01:00
TheJulianJES
3c0cfd5e0c Display error when forming new ZHA network fails (#157863) 2025-12-03 22:37:52 -05:00
Luke Lashley
69f66ffef4 Correctly pass MopParserConfig for Roborock (#157891) 2025-12-03 17:35:51 -08:00
Norbert Rittel
d2c3543b6c Consistently use "Labs" as name in kitchen_sink (#157875) 2025-12-04 00:19:24 +01:00
Franck Nijhof
ca4a2d441e 2025.12.0 (#157330) 2025-12-03 19:06:27 +01:00
Joost Lekkerkerker
f42fe9cee3 Add button to reset hood filter to SmartThings (#157847) 2025-12-03 18:38:23 +01:00
Kevin Stillhammer
b67873f40c bump fressnapftracker to 0.2.0 (#157868) 2025-12-03 18:29:20 +01:00
Markus Jacobsen
ecc08fce0f Reduce naming verbosity in Bang & Olufsen (#157825) 2025-12-03 17:46:18 +01:00
Ludovic BOUÉ
375f536b15 Add Matter DoorPositionSensor open/closed count sensors (#155809) 2025-12-03 17:35:47 +01:00
Kevin Stillhammer
5cff813eac remove deep_sleep binary_sensor from fressnapf_tracker (#157857) 2025-12-03 17:28:59 +01:00
Franck Nijhof
c2ce322af1 Bump version to 2025.12.0 2025-12-03 16:28:33 +00:00
Thomas55555
079f306a65 Fix strings in Google Air Quality (#157862) 2025-12-03 16:28:06 +00:00
Thomas55555
9129665c64 Fix strings in Google Air Quality (#157862) 2025-12-03 17:26:21 +01:00
Franck Nijhof
7bf60f9d15 Bump version to 2025.12.0b9 2025-12-03 15:57:15 +00:00
Robert Resch
7dddd89ac2 Add retry logic to docker.io image push step (#157859) 2025-12-03 15:57:03 +00:00
Luke Lashley
a2322ef3c7 Bump Roborock to 3.9.3 (#157852) 2025-12-03 15:57:01 +00:00
Bram Kragten
5f6ef2109a Update frontend to 20251203.0 (#157851) 2025-12-03 15:57:00 +00:00
starkillerOG
44f0a8899a Bump reolink_aio to 0.17.0 (#157850) 2025-12-03 15:56:58 +00:00
Robert Resch
78fa29b41f Bump deebot-client to 17.0.0 (#157836) 2025-12-03 15:56:57 +00:00
Manu
06d4f085c0 Prevent startup blocking when a friend’s trophy summary is private on PlayStation Network (#157597)
Co-authored-by: Robert Resch <robert@resch.dev>
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2025-12-03 15:56:55 +00:00
Robert Resch
f4e11da1a6 Add retry logic to docker.io image push step (#157859) 2025-12-03 16:53:45 +01:00
Bram Kragten
e0238b5ab2 Update frontend to 20251203.0 (#157851) 2025-12-03 10:40:05 -05:00
Luke Lashley
352f3813e2 Bump Roborock to 3.9.3 (#157852) 2025-12-03 16:37:59 +01:00
Manu
b1399a5541 Prevent startup blocking when a friend’s trophy summary is private on PlayStation Network (#157597)
Co-authored-by: Robert Resch <robert@resch.dev>
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2025-12-03 16:29:51 +01:00
J. Nick Koston
316cddec86 Bump bleak to 2.0.0 (#157766) 2025-12-03 15:25:42 +00:00
starkillerOG
2f71aec26f Bump reolink_aio to 0.17.0 (#157850) 2025-12-03 16:22:02 +01:00
Joost Lekkerkerker
aa72b76ee7 Add cooktop fixture to SmartThings (#157842) 2025-12-03 15:36:29 +01:00
Erik Montnemery
e009898107 Remove template config entry from source device (#157814)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-12-03 15:24:48 +01:00
Artur Pragacz
ceb13e70b9 Add integration type to wake_on_lan (#157726)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 15:14:57 +01:00
Robert Resch
498a80ac7f Bump deebot-client to 17.0.0 (#157836) 2025-12-03 15:12:31 +01:00
victorigualada
a9deb2a08a Bump hass-nabucasa from 1.6.2 to 1.7.0 (#157834) 2025-12-03 13:56:01 +00:00
victorigualada
0d26d22986 Allow non strict response_format structures for Cloud LLM generation (#157822) 2025-12-03 13:55:09 +00:00
Erik Montnemery
062366966b Pin Python point release used in CI (#157819) 2025-12-03 13:53:30 +00:00
Franck Nijhof
1b8a50e80a Bump version to 2025.12.0b8 2025-12-03 12:16:30 +00:00
Franck Nijhof
59761385f0 Add final learn more and feedback links for purpose-specific triggers and conditions preview feature (#157830) 2025-12-03 12:16:21 +00:00
Robert Resch
6536d348e5 Prioritize default stun port over alternative (#157829) 2025-12-03 12:16:20 +00:00
Michael
c157c83d54 Add integration_type to Oralb (#157828) 2025-12-03 12:16:18 +00:00
torben-iometer
77425cc40f bump iometer to v0.3.0 (#157826) 2025-12-03 12:16:16 +00:00
Franck Nijhof
c4b67329c3 Bump version to 2025.12.0b7 2025-12-03 10:42:56 +00:00
Allen Porter
c1f8c89bd0 Bump python-roborock to 3.9.2 (#157815)
Co-authored-by: Robert Resch <robert@resch.dev>
2025-12-03 10:42:32 +00:00
Allen Porter
b1bf6f5678 Bump google-nest-sdm to 9.1.2 (#157812)
Co-authored-by: Josef Zweck <josef@zweck.dev>
Co-authored-by: Robert Resch <robert@resch.dev>
2025-12-03 10:42:30 +00:00
Josef Zweck
d347136188 Mark nordpool as service integration_type (#157810) 2025-12-03 10:42:29 +00:00
Kamil Breguła
a4319f3bf8 Update release URL in WLED (#157801) 2025-12-03 10:42:27 +00:00
Marc Mueller
db27aee62a Fix ping TypeError when killing the process (#157794) 2025-12-03 10:42:26 +00:00
Joost Lekkerkerker
a7446b3da9 Make occupancy trigger check occupancy instead of presence (#157791) 2025-12-03 10:42:24 +00:00
Stefan Agner
7fc5464621 Add storage link to low disk space repair issue (#157786)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2025-12-03 10:42:23 +00:00
hanwg
a00b50c195 Fix bug in group notify entities when title is missing (#157171)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-12-03 10:42:21 +00:00
Franck Nijhof
738fb59efa Bump version to 2025.12.0b6 2025-12-02 21:23:23 +00:00
Joris Pelgröm
04e512a48e Bump letpot to 0.6.4 (#157781) 2025-12-02 21:23:12 +00:00
Michael Hansen
c63aca2d9b Bump hassil to 3.5.0 (#157780) 2025-12-02 21:23:11 +00:00
Kamil Breguła
c95203e095 Handle unsupported version in WLED (#157778)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
2025-12-02 21:23:09 +00:00
Josef Zweck
259235ceeb Add integration_type for tedee (#157776) 2025-12-02 21:23:08 +00:00
Paulus Schoutsen
c7f1729300 Allow fetching the Cloud ICE servers (#157774) 2025-12-02 21:23:06 +00:00
puddly
065329e668 Fix ZHA network formation (#157769) 2025-12-02 21:23:05 +00:00
Marcel van der Veldt
a93ed69fe4 Let AuthenticationRequired also trigger the reauth flow in MusicAssistant (#157580) 2025-12-02 21:23:04 +00:00
Sab44
189497622d Fix orphaned devices not being removed during integration startup (#155900) 2025-12-02 21:23:02 +00:00
Franck Nijhof
a466fc4a01 Bump version to 2025.12.0b5 2025-12-02 18:19:42 +00:00
Matthias Alphart
8a968b5d0e Add integration_type for Fronius (#157760) 2025-12-02 18:19:13 +00:00
Michael Hansen
3baee5c4ac Bump intents to 2025.12.2 (#157758) 2025-12-02 18:17:57 +00:00
Bram Kragten
f624a43770 Update frontend to 20251202.0 (#157755)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-12-02 18:16:17 +00:00
Artur Pragacz
242935774b Add integration type to ping (#157730)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 18:14:17 +00:00
Artur Pragacz
051ad5878f Add integration type to rest (#157728)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 18:14:16 +00:00
Artur Pragacz
b2156c1d4c Add integration type to speedtestdotnet (#157727)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 18:14:15 +00:00
Artur Pragacz
7d4394f7ed Add integration type to google_translate (#157718)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 18:14:14 +00:00
Brett Adams
4df172374c Add integration_type to Tesla Fleet manifest (#157679) 2025-12-02 18:14:13 +00:00
Brett Adams
c97755472e Add integration_type to Teslemetry manifest (#157677) 2025-12-02 18:14:11 +00:00
Erik Montnemery
ebc9060b01 Improve trigger descriptions (#157643)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-12-02 18:14:10 +00:00
Erik Montnemery
bbcc2a94b3 Add occupancy binary sensor triggers (#157631) 2025-12-02 18:14:09 +00:00
victorigualada
692188fa85 Don't register Home Assistant Cloud LLM platforms if not logged in (#157630) 2025-12-02 18:14:08 +00:00
Jordan Harvey
2c993ea5a2 Fix Anglian Water sensor setup (#157457) 2025-12-02 18:14:06 +00:00
Franck Nijhof
c765776726 Bump version to 2025.12.0b4 2025-12-02 12:42:32 +00:00
Robert Resch
723365d8e6 Create the go2rtc unix socket inside a temporary folder (#157742) 2025-12-02 12:42:13 +00:00
Artur Pragacz
3d8e136049 Add integration type to xiaomi_ble (#157740)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:11 +00:00
Artur Pragacz
2fe9fc7ee3 Add integration type to broadlink (#157739)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:10 +00:00
Artur Pragacz
e11e31a1a0 Add integration type to ring (#157738)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:09 +00:00
Artur Pragacz
989407047d Add integration type to roborock (#157737)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:08 +00:00
Artur Pragacz
6d3087c5a4 Add integration type to webostv (#157736)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:06 +00:00
Artur Pragacz
9bd3c35231 Add integration type to tplink (#157735)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:05 +00:00
Artur Pragacz
b7e97971cf Add integration type to ibeacon (#157734)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:04 +00:00
Artur Pragacz
4d232c63f8 Add integration type to dlna_dmr (#157733)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:03 +00:00
Artur Pragacz
6fc000ee2a Add integration type to google (#157729)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:02 +00:00
Artur Pragacz
623d3ecde5 Add integration type to music_assistant (#157725)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:42:00 +00:00
Artur Pragacz
0fbb3215b4 Add integration type to dlna_dms (#157723)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:59 +00:00
Artur Pragacz
c82ce1ff89 Add integration type to met (#157720)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:58 +00:00
Franck Nijhof
8c891a20e5 Rename preview feature to purpose-specific triggers and conditions (#157717) 2025-12-02 12:41:57 +00:00
Erik Montnemery
97c50b2d86 Improve helpers.condition.async_subscribe_platform_events (#157710) 2025-12-02 12:41:55 +00:00
Erik Montnemery
ef4062a565 Improve helpers.trigger.async_subscribe_platform_events (#157709) 2025-12-02 12:41:54 +00:00
cdnninja
e31cce5d9b Bump pyvesync to 3.3.3 (#157697) 2025-12-02 12:41:53 +00:00
Paulus Schoutsen
21f6b9a53a Add integration_type to Nuki Bridge manifest (#157683)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:52 +00:00
Paulus Schoutsen
047e549112 Add integration_type to Motionblinds manifest (#157682)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:51 +00:00
Paulus Schoutsen
4c4aecd9a7 Add integration_type to Konnected.io manifest (#157681) 2025-12-02 12:41:50 +00:00
Paulus Schoutsen
733496ff3f Add integration_type to HomeWizard Energy manifest (#157680)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:49 +00:00
Paulus Schoutsen
f682e93243 Add integration_type to Tessie manifest (#157676)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:48 +00:00
Paulus Schoutsen
c8fa5b0290 Add integration_type to SwitchBot Bluetooth manifest (#157675)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:46 +00:00
Paulus Schoutsen
8ff2a22664 Add integration_type to Sonos manifest (#157674)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:45 +00:00
Paulus Schoutsen
c174ab2d96 Add integration_type to SmartThings manifest (#157673) 2025-12-02 12:41:44 +00:00
Paulus Schoutsen
10f0ff7bd7 Add integration_type to Reolink manifest (#157672)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:43 +00:00
Paulus Schoutsen
4a4eb33bf7 Add integration_type to HomeKit Device manifest (#157671)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:42 +00:00
Paulus Schoutsen
8199c4e5de Add integration_type to Home Connect manifest (#157668)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:40 +00:00
Paulus Schoutsen
0bfa8318a7 Add integration_type to Ecowitt manifest (#157666) 2025-12-02 12:41:39 +00:00
Paulus Schoutsen
ed66a4920c Add integration_type to Apple TV manifest (#157664)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 12:41:38 +00:00
Åke Strandberg
f51007c448 Add program id:s and phases to new Miele WQ1000 (#157660) 2025-12-02 12:41:37 +00:00
TheJulianJES
bd44402b04 Set Matter integration type to "hub" (#157657) 2025-12-02 12:41:36 +00:00
TheJulianJES
99fa92d966 Set ZHA integration type to "hub" (#157656) 2025-12-02 12:41:35 +00:00
Arjan
1cb8f19020 Meteo France: add new mapping "Brouillard dense givrant" (#157627) 2025-12-02 12:41:33 +00:00
Copilot
81cdbdd4df Add labs_updated event to subscription allowlist (#157552)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: balloob <1444314+balloob@users.noreply.github.com>
2025-12-02 12:41:32 +00:00
Franck Nijhof
c82706eaf5 Bump version to 2025.12.0b3 2025-12-01 19:26:30 +00:00
andreimoraru
07f9bec8b6 bump yt-dlp to 2025.11.12 (#157645) 2025-12-01 19:26:14 +00:00
Åke Strandberg
33d576234b Add code mappings for Miele WQ1000 (#157642) 2025-12-01 19:26:13 +00:00
Bram Kragten
9e2b4615f1 Update frontend to 20251201.0 (#157638) 2025-12-01 19:26:11 +00:00
Petro31
a46dc7e05f Reload config entry templates when labs flag automation.new_triggers_conditions is set (#157637)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2025-12-01 19:26:09 +00:00
Erik Montnemery
7dd9953345 Bump area registry to version 1.9 and sort areas (#157634) 2025-12-01 19:26:08 +00:00
Maciej Bieniek
1145026190 Bump aioshelly to version 13.22.0 (#157629) 2025-12-01 19:26:06 +00:00
Erik Montnemery
d8f9574bc3 Remove cover triggers (#157621) 2025-12-01 19:26:05 +00:00
Erik Montnemery
e91f8d3a81 Remove description_configured from condition and trigger translations (#157620) 2025-12-01 19:26:04 +00:00
Aidan Timson
8c0fd0565e Default area icons for new instances (#157619) 2025-12-01 19:26:02 +00:00
Paul Bottein
cc620fc0f8 Fix user store not loaded on restart (#157616) 2025-12-01 19:26:00 +00:00
Erik Montnemery
5a89332680 Bump floor registry to version 1.3 and sort floors (#157614)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-12-01 19:25:59 +00:00
LG-ThinQ-Integration
1831c5e249 Bump thinqconnect to 1.0.9 (#157607) 2025-12-01 19:25:57 +00:00
cdnninja
dddd2503ea Bump pyvesync to 3.3.2 (#157605) 2025-12-01 19:25:56 +00:00
Norbert Rittel
91ba510a1e Fix spelling of "to log in" in anglian_water (#157594) 2025-12-01 19:25:54 +00:00
Norbert Rittel
6e5e739496 Fix spelling of "to set up" in hue_ble (#157593) 2025-12-01 19:25:53 +00:00
Sanjay Govind
6b39eb069c Bump bosch-alarm-mode2 to v0.4.10 (#157564) 2025-12-01 19:25:51 +00:00
Allen Porter
847c332c70 Bump google-nest-sdm to 9.1.1 (#157562) 2025-12-01 19:25:50 +00:00
J. Nick Koston
1a19f3b527 Bump aioesphomeapi to 42.9.0 (#157558) 2025-12-01 19:25:49 +00:00
Thomas55555
8110935d2d Bump google air quality api to 1.1.3 (#157555) 2025-12-01 19:25:47 +00:00
Raphael Hehl
af69da94f5 Bump uiprotect to 7.31.0 (#157543) 2025-12-01 19:25:46 +00:00
Jan Bouwhuis
c1cf17d4db Fix MQTT entity cannot be renamed (#157540) 2025-12-01 19:25:44 +00:00
Allen Porter
6079637909 Bump python-roborock to 3.8.4 (#157538) 2025-12-01 19:25:43 +00:00
Jordan Harvey
9268e12b20 Disable cookie quotes for Anglian Water (#157518) 2025-12-01 19:25:41 +00:00
Raphael Hehl
d07993f4a4 Fix UniFi Protect RTSP repair warnings when globally disabled (#157516) 2025-12-01 19:25:40 +00:00
Allen Porter
441cb4197c Bump python-roborock to 3.8.3 (#157512) 2025-12-01 19:25:38 +00:00
J. Nick Koston
d2a095588d Bump ESPHome stable BLE version to 2025.11.0 (#157511) 2025-12-01 19:25:37 +00:00
Arie Catsman
f2578da7db Bump pyenphase to 2.4.2 (#157500) 2025-12-01 19:25:35 +00:00
Jan Bouwhuis
22200d6804 Fix subentry ID is not updated when renaming the entity ID (#157498) 2025-12-01 19:25:34 +00:00
Maciej Bieniek
8a4e5c3a28 Remove name from Shelly RGBCCT sensors (#157492) 2025-12-01 19:25:32 +00:00
Maciej Bieniek
30f31c7d8c Remove name for Shelly gas valve (gen1) entity (#157490) 2025-12-01 19:25:30 +00:00
Maciej Bieniek
232c4255a1 Add missing string for Shelly away mode switch (#157488) 2025-12-01 19:25:28 +00:00
Petro31
236f7cd22c Ensure platform template does not appear in repair (#157486) 2025-12-01 19:25:27 +00:00
Åke Strandberg
5948ff2e31 Add loggers to senz manifest (#157479) 2025-12-01 19:25:25 +00:00
epenet
380127bc70 Fix blocking call in Tuya initialisation (#157477) 2025-12-01 19:25:23 +00:00
epenet
b6a1e8251a Remove unnecessary instanciating in Tuya find_dpcode (#157473) 2025-12-01 19:25:22 +00:00
David Woodhouse
c20236717c Clarify percentage_command_topic and percentage_state_topic for MQTT fan (#157460)
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
2025-12-01 19:25:21 +00:00
Artur Pragacz
1fd9feaace Provide log info for discovered flows in logger (#157454) 2025-12-01 19:25:19 +00:00
ElectricSteve
7ce072b4dc bump: youtubeaio to 2.1.1 (#157452) 2025-12-01 19:25:17 +00:00
Artur Pragacz
45aa0399c7 Add tools in default agent also in fallback pipeline (#157441) 2025-12-01 19:25:16 +00:00
Hem Bhagat
d82b3871c1 Move translatable URLs out of strings.json for opentherm_gw integration (#157437) 2025-12-01 19:25:14 +00:00
Thomas55555
8f6d1162e5 Fix strings in Google Air Quality (#157297) 2025-12-01 19:21:28 +00:00
puddly
dafce97341 Disable owning integrations for the entire firmware interaction process (#157082) 2025-12-01 19:21:26 +00:00
Sebastian Schneider
ffd5d33bbc Support UniFi LED control for devices without RGB (#156812) 2025-12-01 19:21:24 +00:00
Franck Nijhof
bac32bc379 Bump version to 2025.12.0b2 2025-11-27 17:13:26 +00:00
Allen Porter
6344837009 Fix regression in roborock image entity naming (#157432) 2025-11-27 17:12:08 +00:00
Allen Porter
9079ff5ea8 Update roborock test typing (#157370) 2025-11-27 17:12:06 +00:00
Bram Kragten
cd646aea11 Update frontend to 20251127.0 (#157431) 2025-11-27 17:09:23 +00:00
Shay Levy
b3a93d9fab Fix Shelly support for button5 trigger (#157422) 2025-11-27 17:09:22 +00:00
Denis Shulyaka
db98fb138b Fix Anthropic init with incorrect model (#157421) 2025-11-27 17:09:21 +00:00
Petro31
348c8bca7c Avoid custom template platform deprecations (#157415) 2025-11-27 17:09:20 +00:00
Allen Porter
e30707ad5e Bump python-roborock to 3.8.1 (#157376) 2025-11-27 17:09:18 +00:00
Petro31
3fa4dcb980 Reload templates when labs flag automation.new_triggers_conditions is set (#157368) 2025-11-27 17:09:17 +00:00
Kamil Breguła
57835efc9d Fix MAC address mix-ups between WLED devices (#155491)
Co-authored-by: mik-laj <12058428+mik-laj@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-11-27 17:09:16 +00:00
Franck Nijhof
f8d5a8bc58 Bump version to 2025.12.0b1 2025-11-27 11:49:46 +00:00
epenet
3f1f8da6f5 Bump renault-api to 0.5.1 (#157411) 2025-11-27 11:48:09 +00:00
Jan Čermák
55613f56b6 Fix state classes of Ecowitt rain sensors (#157409) 2025-11-27 11:48:08 +00:00
victorigualada
3ee2a78663 Bump hass-nabucasa from 1.6.1 to 1.6.2 (#157405) 2025-11-27 11:48:06 +00:00
victorigualada
814a0c4cc9 Return early when setting cloud ai_task and conversation and not logged in to cloud (#157402) 2025-11-27 11:48:04 +00:00
starkillerOG
71b674d8f1 Bump reolink-aio to 0.16.6 (#157399) 2025-11-27 11:48:03 +00:00
Erik Montnemery
c952fc5e31 Minor polish of cover trigger tests (#157397) 2025-11-27 11:48:02 +00:00
Allen Porter
8c3d40a348 Remove old roborock map storage (#157379) 2025-11-27 11:48:01 +00:00
Paulus Schoutsen
2451dfb63d Default conversation agent to store tool calls in chat log (#157377) 2025-11-27 11:48:00 +00:00
Sarah Seidman
8e5921eab6 Normalize input for Droplet pairing code (#157361) 2025-11-27 11:47:59 +00:00
Jaap Pieroen
bc730da9b1 Bugfix: Essent remove average gas price today (#157317) 2025-11-27 11:47:57 +00:00
abelyliu
28b7ebea6e Fix parsing of Tuya electricity RAW values (#157039) 2025-11-27 11:47:56 +00:00
Erik Montnemery
cfa447c7a9 Add climate started_cooling and started_drying triggers (#156945) 2025-11-27 11:47:55 +00:00
Franck Nijhof
f64c870e42 Bump version to 2025.12.0b0 2025-11-26 17:13:42 +00:00
826 changed files with 30944 additions and 9517 deletions

View File

@@ -13,6 +13,7 @@ core: &core
# Our base platforms, that are used by other integrations
base_platforms: &base_platforms
- homeassistant/components/ai_task/**
- homeassistant/components/air_quality/**
- homeassistant/components/alarm_control_panel/**
- homeassistant/components/assist_satellite/**

View File

@@ -27,7 +27,6 @@
"charliermarsh.ruff",
"ms-python.pylint",
"ms-python.vscode-pylance",
"visualstudioexptteam.vscodeintellicode",
"redhat.vscode-yaml",
"esbenp.prettier-vscode",
"GitHub.vscode-pull-request-github",

View File

@@ -15,7 +15,7 @@ env:
UV_HTTP_TIMEOUT: 60
UV_SYSTEM_PYTHON: "true"
# Base image version from https://github.com/home-assistant/docker
BASE_IMAGE_VERSION: "2025.11.3"
BASE_IMAGE_VERSION: "2025.12.0"
ARCHITECTURES: '["amd64", "aarch64"]'
jobs:
@@ -70,7 +70,7 @@ jobs:
run: find ./homeassistant/components/*/translations -name "*.json" | tar zcvf translations.tar.gz -T -
- name: Upload translations
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: translations
path: translations.tar.gz
@@ -169,7 +169,7 @@ jobs:
fi
- name: Download translations
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: translations
@@ -416,9 +416,19 @@ jobs:
ARCHS=$(echo '${{ needs.init.outputs.architectures }}' | jq -r '.[]')
for arch in $ARCHS; do
echo "Copying ${arch} image to DockerHub..."
docker buildx imagetools create \
--tag "docker.io/homeassistant/${arch}-homeassistant:${{ needs.init.outputs.version }}" \
"ghcr.io/home-assistant/${arch}-homeassistant:${{ needs.init.outputs.version }}"
for attempt in 1 2 3; do
if docker buildx imagetools create \
--tag "docker.io/homeassistant/${arch}-homeassistant:${{ needs.init.outputs.version }}" \
"ghcr.io/home-assistant/${arch}-homeassistant:${{ needs.init.outputs.version }}"; then
break
fi
echo "Attempt ${attempt} failed, retrying in 10 seconds..."
sleep 10
if [ "${attempt}" -eq 3 ]; then
echo "Failed after 3 attempts"
exit 1
fi
done
cosign sign --yes "docker.io/homeassistant/${arch}-homeassistant:${{ needs.init.outputs.version }}"
done
@@ -472,7 +482,7 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Download translations
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: translations

View File

@@ -41,8 +41,8 @@ env:
UV_CACHE_VERSION: 1
MYPY_CACHE_VERSION: 1
HA_SHORT_VERSION: "2026.1"
DEFAULT_PYTHON: "3.13.9"
ALL_PYTHON_VERSIONS: "['3.13.9', '3.14.0']"
DEFAULT_PYTHON: "3.13.11"
ALL_PYTHON_VERSIONS: "['3.13.11', '3.14.2']"
# 10.3 is the oldest supported version
# - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022)
# 10.6 is the current long-term-support
@@ -263,7 +263,7 @@ jobs:
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: &actions-cache actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: &actions-cache actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: venv
key: &key-pre-commit-venv >-
@@ -304,7 +304,7 @@ jobs:
- &cache-restore-pre-commit-venv
name: Restore base Python virtual environment
id: cache-venv
uses: &actions-cache-restore actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: &actions-cache-restore actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: venv
fail-on-cache-miss: true
@@ -511,7 +511,7 @@ jobs:
fi
- name: Save apt cache
if: steps.cache-apt-check.outputs.cache-hit != 'true'
uses: &actions-cache-save actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: &actions-cache-save actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: *path-apt-cache
key: *key-apt-cache
@@ -534,7 +534,7 @@ jobs:
python --version
uv pip freeze >> pip_freeze.txt
- name: Upload pip_freeze artifact
uses: &actions-upload-artifact actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: &actions-upload-artifact actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: pip-freeze-${{ matrix.python-version }}
path: pip_freeze.txt
@@ -864,7 +864,7 @@ jobs:
run: |
echo "::add-matcher::.github/workflows/matchers/pytest-slow.json"
- name: Download pytest_buckets
uses: &actions-download-artifact actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
uses: &actions-download-artifact actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: pytest_buckets
- &compile-english-translations
@@ -1188,7 +1188,7 @@ jobs:
pattern: coverage-*
- name: Upload coverage to Codecov
if: needs.info.outputs.test_full_suite == 'true'
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
fail_ci_if_error: true
flags: full-suite
@@ -1313,7 +1313,7 @@ jobs:
pattern: coverage-*
- name: Upload coverage to Codecov
if: needs.info.outputs.test_full_suite == 'false'
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -24,11 +24,11 @@ jobs:
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Initialize CodeQL
uses: github/codeql-action/init@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6
uses: github/codeql-action/init@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
with:
languages: python
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6
uses: github/codeql-action/analyze@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
with:
category: "/language:python"

View File

@@ -10,7 +10,7 @@ jobs:
if: github.repository_owner == 'home-assistant'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
- uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7 # v6.0.0
with:
github-token: ${{ github.token }}
issue-inactive-days: "30"

View File

@@ -74,7 +74,7 @@ jobs:
) > .env_file
- name: Upload env_file
uses: &actions-upload-artifact actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: &actions-upload-artifact actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: env_file
path: ./.env_file
@@ -119,7 +119,7 @@ jobs:
- &download-env-file
name: Download env_file
uses: &actions-download-artifact actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
uses: &actions-download-artifact actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: env_file

22
CODEOWNERS generated
View File

@@ -73,6 +73,8 @@ build.json @home-assistant/supervisor
/tests/components/airobot/ @mettolen
/homeassistant/components/airos/ @CoMPaTech
/tests/components/airos/ @CoMPaTech
/homeassistant/components/airpatrol/ @antondalgren
/tests/components/airpatrol/ @antondalgren
/homeassistant/components/airq/ @Sibgatulin @dl2080
/tests/components/airq/ @Sibgatulin @dl2080
/homeassistant/components/airthings/ @danielhiversen @LaStrada
@@ -218,8 +220,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/bizkaibus/ @UgaitzEtxebarria
/homeassistant/components/blebox/ @bbx-a @swistakm
/tests/components/blebox/ @bbx-a @swistakm
/homeassistant/components/blink/ @fronzbot @mkmer
/tests/components/blink/ @fronzbot @mkmer
/homeassistant/components/blink/ @fronzbot
/tests/components/blink/ @fronzbot
/homeassistant/components/blue_current/ @gleeuwen @NickKoepr @jtodorova23
/tests/components/blue_current/ @gleeuwen @NickKoepr @jtodorova23
/homeassistant/components/bluemaestro/ @bdraco
@@ -306,8 +308,8 @@ build.json @home-assistant/supervisor
/tests/components/config/ @home-assistant/core
/homeassistant/components/configurator/ @home-assistant/core
/tests/components/configurator/ @home-assistant/core
/homeassistant/components/control4/ @lawtancool
/tests/components/control4/ @lawtancool
/homeassistant/components/control4/ @lawtancool @davidrecordon
/tests/components/control4/ @lawtancool @davidrecordon
/homeassistant/components/conversation/ @home-assistant/core @synesthesiam @arturpragacz
/tests/components/conversation/ @home-assistant/core @synesthesiam @arturpragacz
/homeassistant/components/cookidoo/ @miaucl
@@ -418,6 +420,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/efergy/ @tkdrob
/tests/components/efergy/ @tkdrob
/homeassistant/components/egardia/ @jeroenterheerdt
/homeassistant/components/egauge/ @neggert
/tests/components/egauge/ @neggert
/homeassistant/components/eheimdigital/ @autinerd
/tests/components/eheimdigital/ @autinerd
/homeassistant/components/ekeybionyx/ @richardpolzer
@@ -460,7 +464,7 @@ build.json @home-assistant/supervisor
/tests/components/enigma2/ @autinerd
/homeassistant/components/enphase_envoy/ @bdraco @cgarwood @catsmanac
/tests/components/enphase_envoy/ @bdraco @cgarwood @catsmanac
/homeassistant/components/entur_public_transport/ @hfurubotten
/homeassistant/components/entur_public_transport/ @hfurubotten @SanderBlom
/homeassistant/components/environment_canada/ @gwww @michaeldavie
/tests/components/environment_canada/ @gwww @michaeldavie
/homeassistant/components/ephember/ @ttroy50 @roberty99
@@ -571,6 +575,8 @@ build.json @home-assistant/supervisor
/tests/components/generic_hygrostat/ @Shulyaka
/homeassistant/components/geniushub/ @manzanotti
/tests/components/geniushub/ @manzanotti
/homeassistant/components/gentex_homelink/ @niaexa @ryanjones-gentex
/tests/components/gentex_homelink/ @niaexa @ryanjones-gentex
/homeassistant/components/geo_json_events/ @exxamalte
/tests/components/geo_json_events/ @exxamalte
/homeassistant/components/geo_location/ @home-assistant/core
@@ -1356,8 +1362,8 @@ build.json @home-assistant/supervisor
/tests/components/ring/ @sdb9696
/homeassistant/components/risco/ @OnFreund
/tests/components/risco/ @OnFreund
/homeassistant/components/rituals_perfume_genie/ @milanmeu @frenck
/tests/components/rituals_perfume_genie/ @milanmeu @frenck
/homeassistant/components/rituals_perfume_genie/ @milanmeu @frenck @quebulm
/tests/components/rituals_perfume_genie/ @milanmeu @frenck @quebulm
/homeassistant/components/rmvtransport/ @cgtobi
/tests/components/rmvtransport/ @cgtobi
/homeassistant/components/roborock/ @Lash-L @allenporter
@@ -1803,6 +1809,8 @@ build.json @home-assistant/supervisor
/tests/components/weatherflow_cloud/ @jeeftor
/homeassistant/components/weatherkit/ @tjhorner
/tests/components/weatherkit/ @tjhorner
/homeassistant/components/web_rtc/ @home-assistant/core
/tests/components/web_rtc/ @home-assistant/core
/homeassistant/components/webdav/ @jpbede
/tests/components/webdav/ @jpbede
/homeassistant/components/webhook/ @home-assistant/core

2
Dockerfile generated
View File

@@ -30,7 +30,7 @@ RUN \
# Verify go2rtc can be executed
go2rtc --version \
# Install uv
&& pip3 install uv==0.9.6
&& pip3 install uv==0.9.17
WORKDIR /usr/src

View File

@@ -10,6 +10,7 @@
}
],
"documentation": "https://www.home-assistant.io/integrations/actron_air",
"integration_type": "hub",
"iot_class": "cloud_polling",
"quality_scale": "bronze",
"requirements": ["actron-neo-api==0.1.87"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@Bre77"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/advantage_air",
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["advantage_air"],
"requirements": ["advantage-air==0.4.4"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@Noltari"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/aemet",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["aemet_opendata"],
"requirements": ["AEMET-OpenData==0.6.4"]

View File

@@ -4,6 +4,7 @@
"codeowners": [],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/aftership",
"integration_type": "service",
"iot_class": "cloud_polling",
"requirements": ["pyaftership==21.11.0"]
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@ispysoftware"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/agent_dvr",
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["agent"],
"requirements": ["agent-py==0.0.24"]

View File

@@ -101,8 +101,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
vol.Schema({str: STRUCTURE_FIELD_SCHEMA}),
_validate_structure_fields,
),
vol.Optional(ATTR_ATTACHMENTS): vol.All(
cv.ensure_list, [selector.MediaSelector({"accept": ["*/*"]})]
vol.Optional(ATTR_ATTACHMENTS): selector.MediaSelector(
{"accept": ["*/*"], "multiple": True}
),
}
),
@@ -118,8 +118,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
vol.Required(ATTR_TASK_NAME): cv.string,
vol.Optional(ATTR_ENTITY_ID): cv.entity_id,
vol.Required(ATTR_INSTRUCTIONS): cv.string,
vol.Optional(ATTR_ATTACHMENTS): vol.All(
cv.ensure_list, [selector.MediaSelector({"accept": ["*/*"]})]
vol.Optional(ATTR_ATTACHMENTS): selector.MediaSelector(
{"accept": ["*/*"], "multiple": True}
),
}
),

View File

@@ -4,6 +4,7 @@
"codeowners": ["@asymworks"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airnow",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["pyairnow"],
"requirements": ["pyairnow==1.3.1"]

View File

@@ -7,7 +7,7 @@ from homeassistant.core import HomeAssistant
from .coordinator import AirobotConfigEntry, AirobotDataUpdateCoordinator
PLATFORMS: list[Platform] = [Platform.CLIMATE]
PLATFORMS: list[Platform] = [Platform.CLIMATE, Platform.SENSOR]
async def async_setup_entry(hass: HomeAssistant, entry: AirobotConfigEntry) -> bool:

View File

@@ -0,0 +1,38 @@
"""Diagnostics support for Airobot."""
from __future__ import annotations
from dataclasses import asdict
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from .coordinator import AirobotConfigEntry
TO_REDACT_CONFIG = [CONF_HOST, CONF_MAC, CONF_PASSWORD, CONF_USERNAME]
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: AirobotConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
coordinator = entry.runtime_data
# Build device capabilities info
device_capabilities = None
if coordinator.data:
device_capabilities = {
"has_floor_sensor": coordinator.data.status.has_floor_sensor,
"has_co2_sensor": coordinator.data.status.has_co2_sensor,
"hw_version": coordinator.data.status.hw_version,
"fw_version": coordinator.data.status.fw_version,
}
return {
"entry_data": async_redact_data(entry.data, TO_REDACT_CONFIG),
"device_capabilities": device_capabilities,
"status": asdict(coordinator.data.status) if coordinator.data else None,
"settings": asdict(coordinator.data.settings) if coordinator.data else None,
}

View File

@@ -39,12 +39,12 @@ rules:
# Gold
devices: done
diagnostics: todo
diagnostics: done
discovery-update-info: done
discovery: done
docs-data-update: done
docs-examples: todo
docs-known-limitations: todo
docs-known-limitations: done
docs-supported-devices: done
docs-supported-functions: done
docs-troubleshooting: done
@@ -54,8 +54,8 @@ rules:
comment: Single device integration, no dynamic device discovery needed.
entity-category: done
entity-device-class: done
entity-disabled-by-default: todo
entity-translations: todo
entity-disabled-by-default: done
entity-translations: done
exception-translations: done
icon-translations: todo
reconfiguration-flow: todo

View File

@@ -0,0 +1,150 @@
"""Sensor platform for Airobot thermostat."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
from pyairobotrest.models import ThermostatStatus
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import (
CONCENTRATION_PARTS_PER_MILLION,
PERCENTAGE,
EntityCategory,
UnitOfTemperature,
UnitOfTime,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util.dt import utcnow
from homeassistant.util.variance import ignore_variance
from . import AirobotConfigEntry
from .entity import AirobotEntity
PARALLEL_UPDATES = 0
@dataclass(frozen=True, kw_only=True)
class AirobotSensorEntityDescription(SensorEntityDescription):
"""Describes Airobot sensor entity."""
value_fn: Callable[[ThermostatStatus], StateType | datetime]
supported_fn: Callable[[ThermostatStatus], bool] = lambda _: True
uptime_to_stable_datetime = ignore_variance(
lambda value: utcnow().replace(microsecond=0) - timedelta(seconds=value),
timedelta(minutes=2),
)
SENSOR_TYPES: tuple[AirobotSensorEntityDescription, ...] = (
AirobotSensorEntityDescription(
key="air_temperature",
translation_key="air_temperature",
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda status: status.temp_air,
),
AirobotSensorEntityDescription(
key="humidity",
device_class=SensorDeviceClass.HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda status: status.hum_air,
),
AirobotSensorEntityDescription(
key="floor_temperature",
translation_key="floor_temperature",
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda status: status.temp_floor,
supported_fn=lambda status: status.has_floor_sensor,
),
AirobotSensorEntityDescription(
key="co2",
device_class=SensorDeviceClass.CO2,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda status: status.co2,
supported_fn=lambda status: status.has_co2_sensor,
),
AirobotSensorEntityDescription(
key="air_quality_index",
device_class=SensorDeviceClass.AQI,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda status: status.aqi,
supported_fn=lambda status: status.has_co2_sensor,
),
AirobotSensorEntityDescription(
key="heating_uptime",
translation_key="heating_uptime",
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.HOURS,
state_class=SensorStateClass.TOTAL_INCREASING,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda status: status.heating_uptime,
entity_registry_enabled_default=False,
),
AirobotSensorEntityDescription(
key="errors",
translation_key="errors",
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda status: status.errors,
),
AirobotSensorEntityDescription(
key="device_uptime",
translation_key="device_uptime",
device_class=SensorDeviceClass.TIMESTAMP,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda status: uptime_to_stable_datetime(status.device_uptime),
entity_registry_enabled_default=False,
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: AirobotConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Airobot sensor platform."""
coordinator = entry.runtime_data
async_add_entities(
AirobotSensor(coordinator, description)
for description in SENSOR_TYPES
if description.supported_fn(coordinator.data.status)
)
class AirobotSensor(AirobotEntity, SensorEntity):
"""Representation of an Airobot sensor."""
entity_description: AirobotSensorEntityDescription
def __init__(
self,
coordinator,
description: AirobotSensorEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = f"{coordinator.data.status.device_id}_{description.key}"
@property
def native_value(self) -> StateType | datetime:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self.coordinator.data.status)

View File

@@ -43,6 +43,25 @@
}
}
},
"entity": {
"sensor": {
"air_temperature": {
"name": "Air temperature"
},
"device_uptime": {
"name": "Device uptime"
},
"errors": {
"name": "Error count"
},
"floor_temperature": {
"name": "Floor temperature"
},
"heating_uptime": {
"name": "Heating uptime"
}
}
},
"exceptions": {
"authentication_failed": {
"message": "Authentication failed, please reauthenticate."

View File

@@ -0,0 +1,24 @@
"""The AirPatrol integration."""
from __future__ import annotations
from homeassistant.core import HomeAssistant
from .const import PLATFORMS
from .coordinator import AirPatrolConfigEntry, AirPatrolDataUpdateCoordinator
async def async_setup_entry(hass: HomeAssistant, entry: AirPatrolConfigEntry) -> bool:
"""Set up AirPatrol from a config entry."""
coordinator = AirPatrolDataUpdateCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: AirPatrolConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

View File

@@ -0,0 +1,208 @@
"""Climate platform for AirPatrol integration."""
from __future__ import annotations
from typing import Any
from homeassistant.components.climate import (
FAN_AUTO,
FAN_HIGH,
FAN_LOW,
SWING_OFF,
SWING_ON,
ClimateEntity,
ClimateEntityFeature,
HVACMode,
)
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import AirPatrolConfigEntry
from .coordinator import AirPatrolDataUpdateCoordinator
from .entity import AirPatrolEntity
PARALLEL_UPDATES = 0
AP_TO_HA_HVAC_MODES = {
"heat": HVACMode.HEAT,
"cool": HVACMode.COOL,
"off": HVACMode.OFF,
}
HA_TO_AP_HVAC_MODES = {value: key for key, value in AP_TO_HA_HVAC_MODES.items()}
AP_TO_HA_FAN_MODES = {
"min": FAN_LOW,
"max": FAN_HIGH,
"auto": FAN_AUTO,
}
HA_TO_AP_FAN_MODES = {value: key for key, value in AP_TO_HA_FAN_MODES.items()}
AP_TO_HA_SWING_MODES = {
"on": SWING_ON,
"off": SWING_OFF,
}
HA_TO_AP_SWING_MODES = {value: key for key, value in AP_TO_HA_SWING_MODES.items()}
async def async_setup_entry(
hass: HomeAssistant,
config_entry: AirPatrolConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up AirPatrol climate entities."""
coordinator = config_entry.runtime_data
units = coordinator.data
async_add_entities(
AirPatrolClimate(coordinator, unit_id)
for unit_id, unit in units.items()
if "climate" in unit
)
class AirPatrolClimate(AirPatrolEntity, ClimateEntity):
"""AirPatrol climate entity."""
_attr_name = None
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.FAN_MODE
| ClimateEntityFeature.SWING_MODE
| ClimateEntityFeature.TURN_OFF
| ClimateEntityFeature.TURN_ON
)
_attr_hvac_modes = [HVACMode.HEAT, HVACMode.COOL, HVACMode.OFF]
_attr_fan_modes = [FAN_LOW, FAN_HIGH, FAN_AUTO]
_attr_swing_modes = [SWING_ON, SWING_OFF]
_attr_min_temp = 16.0
_attr_max_temp = 30.0
def __init__(
self,
coordinator: AirPatrolDataUpdateCoordinator,
unit_id: str,
) -> None:
"""Initialize the climate entity."""
super().__init__(coordinator, unit_id)
self._attr_unique_id = f"{coordinator.config_entry.unique_id}-{unit_id}"
@property
def climate_data(self) -> dict[str, Any]:
"""Return the climate data."""
return self.device_data.get("climate") or {}
@property
def params(self) -> dict[str, Any]:
"""Return the current parameters for the climate entity."""
return self.climate_data.get("ParametersData") or {}
@property
def available(self) -> bool:
"""Return if entity is available."""
return super().available and bool(self.climate_data)
@property
def current_humidity(self) -> float | None:
"""Return the current humidity."""
if humidity := self.climate_data.get("RoomHumidity"):
return float(humidity)
return None
@property
def current_temperature(self) -> float | None:
"""Return the current temperature."""
if temp := self.climate_data.get("RoomTemp"):
return float(temp)
return None
@property
def target_temperature(self) -> float | None:
"""Return the target temperature."""
if temp := self.params.get("PumpTemp"):
return float(temp)
return None
@property
def hvac_mode(self) -> HVACMode | None:
"""Return the current HVAC mode."""
pump_power = self.params.get("PumpPower")
pump_mode = self.params.get("PumpMode")
if pump_power and pump_power == "on" and pump_mode:
return AP_TO_HA_HVAC_MODES.get(pump_mode)
return HVACMode.OFF
@property
def fan_mode(self) -> str | None:
"""Return the current fan mode."""
fan_speed = self.params.get("FanSpeed")
if fan_speed:
return AP_TO_HA_FAN_MODES.get(fan_speed)
return None
@property
def swing_mode(self) -> str | None:
"""Return the current swing mode."""
swing = self.params.get("Swing")
if swing:
return AP_TO_HA_SWING_MODES.get(swing)
return None
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
params = self.params.copy()
if ATTR_TEMPERATURE in kwargs:
temp = kwargs[ATTR_TEMPERATURE]
params["PumpTemp"] = f"{temp:.3f}"
await self._async_set_params(params)
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
params = self.params.copy()
if hvac_mode == HVACMode.OFF:
params["PumpPower"] = "off"
else:
params["PumpPower"] = "on"
params["PumpMode"] = HA_TO_AP_HVAC_MODES.get(hvac_mode)
await self._async_set_params(params)
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set new target fan mode."""
params = self.params.copy()
params["FanSpeed"] = HA_TO_AP_FAN_MODES.get(fan_mode)
await self._async_set_params(params)
async def async_set_swing_mode(self, swing_mode: str) -> None:
"""Set new target swing mode."""
params = self.params.copy()
params["Swing"] = HA_TO_AP_SWING_MODES.get(swing_mode)
await self._async_set_params(params)
async def async_turn_on(self) -> None:
"""Turn the entity on."""
params = self.params.copy()
if mode := AP_TO_HA_HVAC_MODES.get(params["PumpMode"]):
await self.async_set_hvac_mode(mode)
async def async_turn_off(self) -> None:
"""Turn the entity off."""
await self.async_set_hvac_mode(HVACMode.OFF)
async def _async_set_params(self, params: dict[str, Any]) -> None:
"""Set the unit to dry mode."""
new_climate_data = self.climate_data.copy()
new_climate_data["ParametersData"] = params
await self.coordinator.api.set_unit_climate_data(
self._unit_id, new_climate_data
)
await self.coordinator.async_request_refresh()

View File

@@ -0,0 +1,111 @@
"""Config flow for the AirPatrol integration."""
from __future__ import annotations
from collections.abc import Mapping
from typing import Any
from airpatrol.api import AirPatrolAPI, AirPatrolAuthenticationError, AirPatrolError
import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.selector import (
TextSelector,
TextSelectorConfig,
TextSelectorType,
)
from .const import DOMAIN
DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_EMAIL): TextSelector(
TextSelectorConfig(
type=TextSelectorType.EMAIL,
autocomplete="email",
)
),
vol.Required(CONF_PASSWORD): TextSelector(
TextSelectorConfig(
type=TextSelectorType.PASSWORD,
autocomplete="current-password",
)
),
}
)
async def validate_api(
hass: HomeAssistant, user_input: dict[str, str]
) -> tuple[str | None, str | None, dict[str, str]]:
"""Validate the API connection."""
errors: dict[str, str] = {}
session = async_get_clientsession(hass)
access_token = None
unique_id = None
try:
api = await AirPatrolAPI.authenticate(
session, user_input[CONF_EMAIL], user_input[CONF_PASSWORD]
)
except AirPatrolAuthenticationError:
errors["base"] = "invalid_auth"
except AirPatrolError:
errors["base"] = "cannot_connect"
else:
access_token = api.get_access_token()
unique_id = api.get_unique_id()
return (access_token, unique_id, errors)
class AirPatrolConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for AirPatrol."""
VERSION = 1
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""
errors: dict[str, str] = {}
if user_input is not None:
access_token, unique_id, errors = await validate_api(self.hass, user_input)
if access_token and unique_id:
user_input[CONF_ACCESS_TOKEN] = access_token
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=user_input[CONF_EMAIL], data=user_input
)
return self.async_show_form(
step_id="user", data_schema=DATA_SCHEMA, errors=errors
)
async def async_step_reauth(
self, user_input: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle reauthentication with new credentials."""
return await self.async_step_reauth_confirm()
async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reauthentication confirmation."""
errors: dict[str, str] = {}
if user_input:
access_token, unique_id, errors = await validate_api(self.hass, user_input)
if access_token and unique_id:
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_mismatch()
user_input[CONF_ACCESS_TOKEN] = access_token
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)
return self.async_show_form(
step_id="reauth_confirm", data_schema=DATA_SCHEMA, errors=errors
)

View File

@@ -0,0 +1,16 @@
"""Constants for the AirPatrol integration."""
from datetime import timedelta
import logging
from airpatrol.api import AirPatrolAuthenticationError, AirPatrolError
from homeassistant.const import Platform
DOMAIN = "airpatrol"
LOGGER = logging.getLogger(__package__)
PLATFORMS = [Platform.CLIMATE]
SCAN_INTERVAL = timedelta(minutes=1)
AIRPATROL_ERRORS = (AirPatrolAuthenticationError, AirPatrolError)

View File

@@ -0,0 +1,100 @@
"""Data update coordinator for AirPatrol."""
from __future__ import annotations
from typing import Any
from airpatrol.api import AirPatrolAPI, AirPatrolAuthenticationError, AirPatrolError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN, LOGGER, SCAN_INTERVAL
type AirPatrolConfigEntry = ConfigEntry[AirPatrolDataUpdateCoordinator]
class AirPatrolDataUpdateCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]):
"""Class to manage fetching AirPatrol data."""
config_entry: AirPatrolConfigEntry
api: AirPatrolAPI
def __init__(self, hass: HomeAssistant, config_entry: AirPatrolConfigEntry) -> None:
"""Initialize."""
super().__init__(
hass,
LOGGER,
name=f"{DOMAIN.capitalize()} {config_entry.title}",
update_interval=SCAN_INTERVAL,
config_entry=config_entry,
)
async def _async_setup(self) -> None:
try:
await self._setup_client()
except AirPatrolError as api_err:
raise UpdateFailed(
f"Error communicating with AirPatrol API: {api_err}"
) from api_err
async def _async_update_data(self) -> dict[str, dict[str, Any]]:
"""Update unit data from AirPatrol API."""
return {unit_data["unit_id"]: unit_data for unit_data in await self._get_data()}
async def _get_data(self, retry: bool = False) -> list[dict[str, Any]]:
"""Fetch data from API."""
try:
return await self.api.get_data()
except AirPatrolAuthenticationError as auth_err:
if retry:
raise ConfigEntryAuthFailed(
"Authentication with AirPatrol failed"
) from auth_err
await self._update_token()
return await self._get_data(retry=True)
except AirPatrolError as err:
raise UpdateFailed(
f"Error communicating with AirPatrol API: {err}"
) from err
async def _update_token(self) -> None:
"""Refresh the AirPatrol API client and update the access token."""
session = async_get_clientsession(self.hass)
try:
self.api = await AirPatrolAPI.authenticate(
session,
self.config_entry.data[CONF_EMAIL],
self.config_entry.data[CONF_PASSWORD],
)
except AirPatrolAuthenticationError as auth_err:
raise ConfigEntryAuthFailed(
"Authentication with AirPatrol failed"
) from auth_err
self.hass.config_entries.async_update_entry(
self.config_entry,
data={
**self.config_entry.data,
CONF_ACCESS_TOKEN: self.api.get_access_token(),
},
)
async def _setup_client(self) -> None:
"""Set up the AirPatrol API client from stored access_token."""
session = async_get_clientsession(self.hass)
api = AirPatrolAPI(
session,
self.config_entry.data[CONF_ACCESS_TOKEN],
self.config_entry.unique_id,
)
try:
await api.get_data()
except AirPatrolAuthenticationError:
await self._update_token()
self.api = api

View File

@@ -0,0 +1,44 @@
"""Base entity for AirPatrol integration."""
from __future__ import annotations
from typing import Any
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import AirPatrolDataUpdateCoordinator
class AirPatrolEntity(CoordinatorEntity[AirPatrolDataUpdateCoordinator]):
"""Base entity for AirPatrol devices."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: AirPatrolDataUpdateCoordinator,
unit_id: str,
) -> None:
"""Initialize the AirPatrol entity."""
super().__init__(coordinator)
self._unit_id = unit_id
device = coordinator.data[unit_id]
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, unit_id)},
name=device["name"],
manufacturer=device["manufacturer"],
model=device["model"],
serial_number=device["hwid"],
)
@property
def device_data(self) -> dict[str, Any]:
"""Return the device data."""
return self.coordinator.data[self._unit_id]
@property
def available(self) -> bool:
"""Return if entity is available."""
return super().available and self._unit_id in self.coordinator.data

View File

@@ -0,0 +1,11 @@
{
"domain": "airpatrol",
"name": "AirPatrol",
"codeowners": ["@antondalgren"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airpatrol",
"integration_type": "device",
"iot_class": "cloud_polling",
"quality_scale": "bronze",
"requirements": ["airpatrol==0.1.0"]
}

View File

@@ -0,0 +1,65 @@
rules:
# Bronze
action-setup: done
appropriate-polling: done
brands: done
common-modules: done
config-flow-test-coverage: done
config-flow: done
dependency-transparency: done
docs-actions:
status: exempt
comment: Integration does not provide custom actions
docs-high-level-description: done
docs-installation-instructions: done
docs-removal-instructions: done
entity-event-setup:
status: exempt
comment: |
Entities doesn't subscribe to events.
entity-unique-id: done
has-entity-name: done
runtime-data: done
test-before-configure: done
test-before-setup: done
unique-config-entry: done
# Silver
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters: done
docs-installation-parameters: done
entity-unavailable: done
integration-owner: done
log-when-unavailable: todo
parallel-updates: done
reauthentication-flow: done
test-coverage: done
# Gold
devices: done
diagnostics: todo
discovery-update-info: todo
discovery: todo
docs-data-update: todo
docs-examples: todo
docs-known-limitations: todo
docs-supported-devices: todo
docs-supported-functions: todo
docs-troubleshooting: todo
docs-use-cases: todo
dynamic-devices: todo
entity-category: done
entity-device-class: done
entity-disabled-by-default: todo
entity-translations: done
exception-translations: todo
icon-translations: todo
reconfiguration-flow: todo
repair-issues: todo
stale-devices: todo
# Platinum
async-dependency: todo
inject-websession: todo
strict-typing: todo

View File

@@ -0,0 +1,38 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
"unique_id_mismatch": "Login credentials do not match the configured account"
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"step": {
"reauth_confirm": {
"data": {
"email": "[%key:common::config_flow::data::email%]",
"password": "[%key:common::config_flow::data::password%]"
},
"data_description": {
"email": "[%key:component::airpatrol::config::step::user::data_description::email%]",
"password": "[%key:component::airpatrol::config::step::user::data_description::password%]"
},
"description": "Reauthenticate with AirPatrol"
},
"user": {
"data": {
"email": "[%key:common::config_flow::data::email%]",
"password": "[%key:common::config_flow::data::password%]"
},
"data_description": {
"email": "Your AirPatrol email address",
"password": "Your AirPatrol password"
},
"description": "Connect to AirPatrol"
}
}
}
}

View File

@@ -17,6 +17,7 @@
}
],
"documentation": "https://www.home-assistant.io/integrations/airthings",
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["airthings"],
"requirements": ["airthings-cloud==0.2.0"]

View File

@@ -27,6 +27,7 @@
"config_flow": true,
"dependencies": ["bluetooth_adapters"],
"documentation": "https://www.home-assistant.io/integrations/airthings_ble",
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["airthings-ble==1.2.0"]
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@samsinnamon"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airtouch4",
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["airtouch4pyapi"],
"requirements": ["airtouch4pyapi==1.0.5"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@danzel"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airtouch5",
"integration_type": "hub",
"iot_class": "local_push",
"loggers": ["airtouch5py"],
"requirements": ["airtouch5py==0.3.0"]

View File

@@ -9,7 +9,8 @@
}
],
"documentation": "https://www.home-assistant.io/integrations/airzone",
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["aioairzone"],
"requirements": ["aioairzone==1.0.2"]
"requirements": ["aioairzone==1.0.4"]
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@Noltari"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airzone_cloud",
"integration_type": "hub",
"iot_class": "cloud_push",
"loggers": ["aioairzone_cloud"],
"requirements": ["aioairzone-cloud==0.7.2"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@madpilot"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/amberelectric",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["amberelectric"],
"requirements": ["amberelectric==2.0.12"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@engrbm87"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/android_ip_webcam",
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["pydroid-ipcam==3.0.0"]
}

View File

@@ -39,7 +39,6 @@ async def async_setup_entry(
cookie_jar=CookieJar(quote_cookie=False),
),
refresh_token=entry.data[CONF_ACCESS_TOKEN],
account_number=entry.data[CONF_ACCOUNT_NUMBER],
)
try:
await auth.send_refresh_request()
@@ -49,7 +48,7 @@ async def async_setup_entry(
_aw = AnglianWater(authenticator=auth)
try:
await _aw.validate_smart_meter()
await _aw.validate_smart_meter(entry.data[CONF_ACCOUNT_NUMBER])
except SmartMeterUnavailableError as err:
raise ConfigEntryError(
translation_domain=DOMAIN, translation_key="smart_meter_unavailable"

View File

@@ -7,7 +7,7 @@ from typing import Any
from aiohttp import CookieJar
from pyanglianwater import AnglianWater
from pyanglianwater.auth import BaseAuth, MSOB2CAuth
from pyanglianwater.auth import MSOB2CAuth
from pyanglianwater.exceptions import (
InvalidAccountIdError,
SelfAssertedError,
@@ -30,11 +30,14 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
vol.Required(CONF_PASSWORD): selector.TextSelector(
selector.TextSelectorConfig(type=selector.TextSelectorType.PASSWORD)
),
vol.Required(CONF_ACCOUNT_NUMBER): selector.TextSelector(),
}
)
async def validate_credentials(auth: MSOB2CAuth) -> str | MSOB2CAuth:
async def validate_credentials(
auth: MSOB2CAuth, account_number: str
) -> str | MSOB2CAuth:
"""Validate the provided credentials."""
try:
await auth.send_login_request()
@@ -45,7 +48,7 @@ async def validate_credentials(auth: MSOB2CAuth) -> str | MSOB2CAuth:
return "unknown"
_aw = AnglianWater(authenticator=auth)
try:
await _aw.validate_smart_meter()
await _aw.validate_smart_meter(account_number)
except (InvalidAccountIdError, SmartMeterUnavailableError):
return "smart_meter_unavailable"
return auth
@@ -68,35 +71,21 @@ class AnglianWaterConfigFlow(ConfigFlow, domain=DOMAIN):
self.hass,
cookie_jar=CookieJar(quote_cookie=False),
),
account_number=user_input.get(CONF_ACCOUNT_NUMBER),
)
),
user_input[CONF_ACCOUNT_NUMBER],
)
if isinstance(validation_response, BaseAuth):
account_number = (
user_input.get(CONF_ACCOUNT_NUMBER)
or validation_response.account_number
)
await self.async_set_unique_id(account_number)
if isinstance(validation_response, str):
errors["base"] = validation_response
else:
await self.async_set_unique_id(user_input[CONF_ACCOUNT_NUMBER])
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=account_number,
title=user_input[CONF_ACCOUNT_NUMBER],
data={
**user_input,
CONF_ACCESS_TOKEN: validation_response.refresh_token,
CONF_ACCOUNT_NUMBER: account_number,
},
)
if validation_response == "smart_meter_unavailable":
return self.async_show_form(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA.extend(
{
vol.Required(CONF_ACCOUNT_NUMBER): selector.TextSelector(),
}
),
errors={"base": validation_response},
)
errors["base"] = validation_response
return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors

View File

@@ -12,7 +12,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN
from .const import CONF_ACCOUNT_NUMBER, DOMAIN
type AnglianWaterConfigEntry = ConfigEntry[AnglianWaterUpdateCoordinator]
@@ -44,6 +44,6 @@ class AnglianWaterUpdateCoordinator(DataUpdateCoordinator[None]):
async def _async_update_data(self) -> None:
"""Update data from Anglian Water's API."""
try:
return await self.api.update()
return await self.api.update(self.config_entry.data[CONF_ACCOUNT_NUMBER])
except (ExpiredAccessTokenError, UnknownEndpointError) as err:
raise UpdateFailed from err

View File

@@ -4,7 +4,9 @@
"codeowners": ["@pantherale0"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/anglian_water",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["pyanglianwater"],
"quality_scale": "bronze",
"requirements": ["pyanglianwater==2.1.0"]
"requirements": ["pyanglianwater==3.1.0"]
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@Lash-L"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/anova",
"integration_type": "hub",
"iot_class": "cloud_push",
"loggers": ["anova_wifi"],
"requirements": ["anova-wifi==0.17.0"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@hyralex"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/anthemav",
"integration_type": "device",
"iot_class": "local_push",
"loggers": ["anthemav"],
"requirements": ["anthemav==1.4.1"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@bdr99"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/aosmith",
"integration_type": "hub",
"iot_class": "cloud_polling",
"requirements": ["py-aosmith==1.0.15"]
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@yuxincs"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/apcupsd",
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["apcaccess"],
"quality_scale": "platinum",

View File

@@ -4,6 +4,7 @@
"codeowners": ["@elupus"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/arcam_fmj",
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["arcam"],
"requirements": ["arcam-fmj==1.8.2"],

View File

@@ -4,6 +4,7 @@
"codeowners": ["@ikalnyi"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/arve",
"integration_type": "hub",
"iot_class": "cloud_polling",
"requirements": ["asyncarve==0.1.1"]
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@milanmeu"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/aseko_pool_live",
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["aioaseko"],
"requirements": ["aioaseko==1.0.0"]

View File

@@ -3,8 +3,9 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
import logging
import math
from pymicro_vad import MicroVad
from pysilero_vad import SileroVoiceActivityDetector
from pyspeex_noise import AudioProcessor
from .const import BYTES_PER_CHUNK
@@ -42,8 +43,8 @@ class AudioEnhancer(ABC):
"""Enhance chunk of PCM audio @ 16Khz with 16-bit mono samples."""
class MicroVadSpeexEnhancer(AudioEnhancer):
"""Audio enhancer that runs microVAD and speex."""
class SileroVadSpeexEnhancer(AudioEnhancer):
"""Audio enhancer that runs Silero VAD and speex."""
def __init__(
self, auto_gain: int, noise_suppression: int, is_vad_enabled: bool
@@ -69,21 +70,49 @@ class MicroVadSpeexEnhancer(AudioEnhancer):
self.noise_suppression,
)
self.vad: MicroVad | None = None
self.vad: SileroVoiceActivityDetector | None = None
# We get 10ms chunks but Silero works on 32ms chunks, so we have to
# buffer audio. The previous speech probability is used until enough
# audio has been buffered.
self._vad_buffer: bytearray | None = None
self._vad_buffer_chunks = 0
self._vad_buffer_chunk_idx = 0
self._last_speech_probability: float | None = None
if self.is_vad_enabled:
self.vad = MicroVad()
_LOGGER.debug("Initialized microVAD")
self.vad = SileroVoiceActivityDetector()
# VAD buffer is a multiple of 10ms, but Silero VAD needs 32ms.
self._vad_buffer_chunks = int(
math.ceil(self.vad.chunk_bytes() / BYTES_PER_CHUNK)
)
self._vad_leftover_bytes = self.vad.chunk_bytes() - BYTES_PER_CHUNK
self._vad_buffer = bytearray(self.vad.chunk_bytes())
_LOGGER.debug("Initialized Silero VAD")
def enhance_chunk(self, audio: bytes, timestamp_ms: int) -> EnhancedAudioChunk:
"""Enhance 10ms chunk of PCM audio @ 16Khz with 16-bit mono samples."""
speech_probability: float | None = None
assert len(audio) == BYTES_PER_CHUNK
if self.vad is not None:
# Run VAD
speech_probability = self.vad.Process10ms(audio)
assert self._vad_buffer is not None
start_idx = self._vad_buffer_chunk_idx * BYTES_PER_CHUNK
self._vad_buffer[start_idx : start_idx + BYTES_PER_CHUNK] = audio
self._vad_buffer_chunk_idx += 1
if self._vad_buffer_chunk_idx >= self._vad_buffer_chunks:
# We have enough data to run Silero VAD (32 ms)
self._last_speech_probability = self.vad.process_chunk(
self._vad_buffer[: self.vad.chunk_bytes()]
)
# Copy leftover audio that wasn't processed to start
self._vad_buffer[: self._vad_leftover_bytes] = self._vad_buffer[
-self._vad_leftover_bytes :
]
self._vad_buffer_chunk_idx = 0
if self.audio_processor is not None:
# Run noise suppression and auto gain
@@ -92,5 +121,5 @@ class MicroVadSpeexEnhancer(AudioEnhancer):
return EnhancedAudioChunk(
audio=audio,
timestamp_ms=timestamp_ms,
speech_probability=speech_probability,
speech_probability=self._last_speech_probability,
)

View File

@@ -8,5 +8,5 @@
"integration_type": "system",
"iot_class": "local_push",
"quality_scale": "internal",
"requirements": ["pymicro-vad==1.0.1", "pyspeex-noise==1.0.2"]
"requirements": ["pysilero-vad==3.0.1", "pyspeex-noise==1.0.2"]
}

View File

@@ -55,7 +55,7 @@ from homeassistant.util import (
from homeassistant.util.hass_dict import HassKey
from homeassistant.util.limited_size_dict import LimitedSizeDict
from .audio_enhancer import AudioEnhancer, EnhancedAudioChunk, MicroVadSpeexEnhancer
from .audio_enhancer import AudioEnhancer, EnhancedAudioChunk, SileroVadSpeexEnhancer
from .const import (
ACKNOWLEDGE_PATH,
BYTES_PER_CHUNK,
@@ -633,7 +633,7 @@ class PipelineRun:
# Initialize with audio settings
if self.audio_settings.needs_processor and (self.audio_enhancer is None):
# Default audio enhancer
self.audio_enhancer = MicroVadSpeexEnhancer(
self.audio_enhancer = SileroVadSpeexEnhancer(
self.audio_settings.auto_gain_dbfs,
self.audio_settings.noise_suppression_level,
self.audio_settings.is_vad_enabled,

View File

@@ -7,5 +7,5 @@
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["aioasuswrt", "asusrouter", "asyncssh"],
"requirements": ["aioasuswrt==1.5.1", "asusrouter==1.21.0"]
"requirements": ["aioasuswrt==1.5.4", "asusrouter==1.21.3"]
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@MatsNL"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/atag",
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["pyatag"],
"requirements": ["pyatag==0.3.5.3"]

View File

@@ -27,7 +27,8 @@
}
],
"documentation": "https://www.home-assistant.io/integrations/august",
"integration_type": "hub",
"iot_class": "cloud_push",
"loggers": ["pubnub", "yalexs"],
"requirements": ["yalexs==9.2.0", "yalexs-ble==3.2.1"]
"requirements": ["yalexs==9.2.0", "yalexs-ble==3.2.2"]
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@djtimca"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/aurora",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["auroranoaa"],
"requirements": ["auroranoaa==0.0.5"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@nickw444", "@Bre77"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/aussie_broadband",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["aussiebb"],
"requirements": ["pyaussiebb==0.1.5"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@klaasnicolaas"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/autarco",
"integration_type": "hub",
"iot_class": "cloud_polling",
"requirements": ["autarco==3.2.0"]
}

View File

@@ -6,10 +6,7 @@ rules:
This integration does not provide additional actions.
appropriate-polling: done
brands: done
common-modules:
status: todo
comment: |
The entity.py file is not used in this integration.
common-modules: done
config-flow-test-coverage: done
config-flow: done
dependency-transparency: done

View File

@@ -204,13 +204,25 @@ async def async_setup_entry(
async_add_entities(entities)
class AutarcoBatterySensorEntity(
CoordinatorEntity[AutarcoDataUpdateCoordinator], SensorEntity
):
class AutarcoSensorBase(CoordinatorEntity[AutarcoDataUpdateCoordinator], SensorEntity):
"""Base class for Autarco sensors."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: AutarcoDataUpdateCoordinator,
description: SensorEntityDescription,
) -> None:
"""Initialize Autarco sensor base."""
super().__init__(coordinator)
self.entity_description = description
class AutarcoBatterySensorEntity(AutarcoSensorBase):
"""Defines an Autarco battery sensor."""
entity_description: AutarcoBatterySensorEntityDescription
_attr_has_entity_name = True
def __init__(
self,
@@ -218,10 +230,8 @@ class AutarcoBatterySensorEntity(
coordinator: AutarcoDataUpdateCoordinator,
description: AutarcoBatterySensorEntityDescription,
) -> None:
"""Initialize Autarco sensor."""
super().__init__(coordinator)
self.entity_description = description
"""Initialize Autarco battery sensor."""
super().__init__(coordinator, description)
self._attr_unique_id = (
f"{coordinator.account_site.site_id}_battery_{description.key}"
)
@@ -239,13 +249,10 @@ class AutarcoBatterySensorEntity(
return self.entity_description.value_fn(self.coordinator.data.battery)
class AutarcoSolarSensorEntity(
CoordinatorEntity[AutarcoDataUpdateCoordinator], SensorEntity
):
class AutarcoSolarSensorEntity(AutarcoSensorBase):
"""Defines an Autarco solar sensor."""
entity_description: AutarcoSolarSensorEntityDescription
_attr_has_entity_name = True
def __init__(
self,
@@ -253,10 +260,8 @@ class AutarcoSolarSensorEntity(
coordinator: AutarcoDataUpdateCoordinator,
description: AutarcoSolarSensorEntityDescription,
) -> None:
"""Initialize Autarco sensor."""
super().__init__(coordinator)
self.entity_description = description
"""Initialize Autarco solar sensor."""
super().__init__(coordinator, description)
self._attr_unique_id = (
f"{coordinator.account_site.site_id}_solar_{description.key}"
)
@@ -273,13 +278,10 @@ class AutarcoSolarSensorEntity(
return self.entity_description.value_fn(self.coordinator.data.solar)
class AutarcoInverterSensorEntity(
CoordinatorEntity[AutarcoDataUpdateCoordinator], SensorEntity
):
class AutarcoInverterSensorEntity(AutarcoSensorBase):
"""Defines an Autarco inverter sensor."""
entity_description: AutarcoInverterSensorEntityDescription
_attr_has_entity_name = True
def __init__(
self,
@@ -288,10 +290,8 @@ class AutarcoInverterSensorEntity(
description: AutarcoInverterSensorEntityDescription,
serial_number: str,
) -> None:
"""Initialize Autarco sensor."""
super().__init__(coordinator)
self.entity_description = description
"""Initialize Autarco inverter sensor."""
super().__init__(coordinator, description)
self._serial_number = serial_number
self._attr_unique_id = f"{serial_number}_{description.key}"
self._attr_device_info = DeviceInfo(

View File

@@ -125,13 +125,16 @@ _EXPERIMENTAL_TRIGGER_PLATFORMS = {
"alarm_control_panel",
"assist_satellite",
"binary_sensor",
"button",
"climate",
"cover",
"fan",
"lawn_mower",
"light",
"media_player",
"switch",
"text",
"update",
"vacuum",
}

View File

@@ -4,6 +4,7 @@
"codeowners": ["@kaareseras"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/azure_data_explorer",
"integration_type": "service",
"iot_class": "cloud_push",
"loggers": ["azure"],
"requirements": ["azure-kusto-ingest==4.5.1", "azure-kusto-data[aio]==4.5.1"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@timmo001"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/azure_devops",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["aioazuredevops"],
"requirements": ["aioazuredevops==2.2.2"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@eavanvalkenburg"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/azure_event_hub",
"integration_type": "service",
"iot_class": "cloud_push",
"loggers": ["azure"],
"requirements": ["azure-eventhub==5.11.1"],

View File

@@ -4,6 +4,7 @@
"codeowners": ["@bdraco", "@jfroy"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/baf",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["aiobafi6==0.9.0"],
"zeroconf": [

View File

@@ -12,6 +12,7 @@
}
],
"documentation": "https://www.home-assistant.io/integrations/balboa",
"integration_type": "device",
"iot_class": "local_push",
"loggers": ["pybalboa"],
"requirements": ["pybalboa==1.1.3"]

View File

@@ -21,29 +21,29 @@ from homeassistant.helpers import device_registry as dr
from homeassistant.util.ssl import get_default_context
from .const import DOMAIN
from .websocket import BangOlufsenWebsocket
from .websocket import BeoWebsocket
@dataclass
class BangOlufsenData:
class BeoData:
"""Dataclass for API client and WebSocket client."""
websocket: BangOlufsenWebsocket
websocket: BeoWebsocket
client: MozartClient
type BangOlufsenConfigEntry = ConfigEntry[BangOlufsenData]
type BeoConfigEntry = ConfigEntry[BeoData]
PLATFORMS = [Platform.EVENT, Platform.MEDIA_PLAYER]
async def async_setup_entry(hass: HomeAssistant, entry: BangOlufsenConfigEntry) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: BeoConfigEntry) -> bool:
"""Set up from a config entry."""
# Remove casts to str
assert entry.unique_id
# Create device now as BangOlufsenWebsocket needs a device for debug logging, firing events etc.
# Create device now as BeoWebsocket needs a device for debug logging, firing events etc.
device_registry = dr.async_get(hass)
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
@@ -68,10 +68,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: BangOlufsenConfigEntry)
await client.close_api_client()
raise ConfigEntryNotReady(f"Unable to connect to {entry.title}") from error
websocket = BangOlufsenWebsocket(hass, entry, client)
websocket = BeoWebsocket(hass, entry, client)
# Add the websocket and API client
entry.runtime_data = BangOlufsenData(websocket, client)
entry.runtime_data = BeoData(websocket, client)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
@@ -82,9 +82,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: BangOlufsenConfigEntry)
return True
async def async_unload_entry(
hass: HomeAssistant, entry: BangOlufsenConfigEntry
) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: BeoConfigEntry) -> bool:
"""Unload a config entry."""
# Close the API client and WebSocket notification listener
entry.runtime_data.client.disconnect_notifications()

View File

@@ -47,7 +47,7 @@ _exception_map = {
}
class BangOlufsenConfigFlowHandler(ConfigFlow, domain=DOMAIN):
class BeoConfigFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle a config flow."""
_beolink_jid = ""

View File

@@ -14,7 +14,7 @@ from homeassistant.components.media_player import (
)
class BangOlufsenSource:
class BeoSource:
"""Class used for associating device source ids with friendly names. May not include all sources."""
DEEZER: Final[Source] = Source(name="Deezer", id="deezer")
@@ -22,17 +22,18 @@ class BangOlufsenSource:
NET_RADIO: Final[Source] = Source(name="B&O Radio", id="netRadio")
SPDIF: Final[Source] = Source(name="Optical", id="spdif")
TIDAL: Final[Source] = Source(name="Tidal", id="tidal")
TV: Final[Source] = Source(name="TV", id="tv")
UNKNOWN: Final[Source] = Source(name="Unknown Source", id="unknown")
URI_STREAMER: Final[Source] = Source(name="Audio Streamer", id="uriStreamer")
BANG_OLUFSEN_STATES: dict[str, MediaPlayerState] = {
BEO_STATES: dict[str, MediaPlayerState] = {
# Dict used for translating device states to Home Assistant states.
"started": MediaPlayerState.PLAYING,
"buffering": MediaPlayerState.PLAYING,
"idle": MediaPlayerState.IDLE,
"paused": MediaPlayerState.PAUSED,
"stopped": MediaPlayerState.PAUSED,
"stopped": MediaPlayerState.IDLE,
"ended": MediaPlayerState.PAUSED,
"error": MediaPlayerState.IDLE,
# A device's initial state is "unknown" and should be treated as "idle"
@@ -40,30 +41,31 @@ BANG_OLUFSEN_STATES: dict[str, MediaPlayerState] = {
}
# Dict used for translating Home Assistant settings to device repeat settings.
BANG_OLUFSEN_REPEAT_FROM_HA: dict[RepeatMode, str] = {
BEO_REPEAT_FROM_HA: dict[RepeatMode, str] = {
RepeatMode.ALL: "all",
RepeatMode.ONE: "track",
RepeatMode.OFF: "none",
}
# Dict used for translating device repeat settings to Home Assistant settings.
BANG_OLUFSEN_REPEAT_TO_HA: dict[str, RepeatMode] = {
value: key for key, value in BANG_OLUFSEN_REPEAT_FROM_HA.items()
BEO_REPEAT_TO_HA: dict[str, RepeatMode] = {
value: key for key, value in BEO_REPEAT_FROM_HA.items()
}
# Media types for play_media
class BangOlufsenMediaType(StrEnum):
class BeoMediaType(StrEnum):
"""Bang & Olufsen specific media types."""
FAVOURITE = "favourite"
DEEZER = "deezer"
FAVOURITE = "favourite"
OVERLAY_TTS = "overlay_tts"
RADIO = "radio"
TIDAL = "tidal"
TTS = "provider"
OVERLAY_TTS = "overlay_tts"
TV = "tv"
class BangOlufsenModel(StrEnum):
class BeoModel(StrEnum):
"""Enum for compatible model names."""
# Mozart devices
@@ -82,7 +84,7 @@ class BangOlufsenModel(StrEnum):
BEOREMOTE_ONE = "Beoremote One"
class BangOlufsenAttribute(StrEnum):
class BeoAttribute(StrEnum):
"""Enum for extra_state_attribute keys."""
BEOLINK = "beolink"
@@ -93,7 +95,7 @@ class BangOlufsenAttribute(StrEnum):
# Physical "buttons" on devices
class BangOlufsenButtons(StrEnum):
class BeoButtons(StrEnum):
"""Enum for device buttons."""
BLUETOOTH = "Bluetooth"
@@ -140,7 +142,7 @@ class WebsocketNotification(StrEnum):
DOMAIN: Final[str] = "bang_olufsen"
# Default values for configuration.
DEFAULT_MODEL: Final[str] = BangOlufsenModel.BEOSOUND_BALANCE
DEFAULT_MODEL: Final[str] = BeoModel.BEOSOUND_BALANCE
# Configuration.
CONF_SERIAL_NUMBER: Final = "serial_number"
@@ -148,7 +150,7 @@ CONF_BEOLINK_JID: Final = "jid"
# Models to choose from in manual configuration.
SELECTABLE_MODELS: list[str] = [
model.value for model in BangOlufsenModel if model != BangOlufsenModel.BEOREMOTE_ONE
model.value for model in BeoModel if model != BeoModel.BEOREMOTE_ONE
]
MANUFACTURER: Final[str] = "Bang & Olufsen"
@@ -160,15 +162,15 @@ ATTR_ITEM_NUMBER: Final[str] = "in"
ATTR_FRIENDLY_NAME: Final[str] = "fn"
# Power states.
BANG_OLUFSEN_ON: Final[str] = "on"
BEO_ON: Final[str] = "on"
VALID_MEDIA_TYPES: Final[tuple] = (
BangOlufsenMediaType.FAVOURITE,
BangOlufsenMediaType.DEEZER,
BangOlufsenMediaType.RADIO,
BangOlufsenMediaType.TTS,
BangOlufsenMediaType.TIDAL,
BangOlufsenMediaType.OVERLAY_TTS,
BeoMediaType.FAVOURITE,
BeoMediaType.DEEZER,
BeoMediaType.RADIO,
BeoMediaType.TTS,
BeoMediaType.TIDAL,
BeoMediaType.OVERLAY_TTS,
MediaType.MUSIC,
MediaType.URL,
MediaType.CHANNEL,
@@ -246,7 +248,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray(
)
# Device events
BANG_OLUFSEN_WEBSOCKET_EVENT: Final[str] = f"{DOMAIN}_websocket_event"
BEO_WEBSOCKET_EVENT: Final[str] = f"{DOMAIN}_websocket_event"
# Dict used to translate native Bang & Olufsen event names to string.json compatible ones
EVENT_TRANSLATION_MAP: dict[str, str] = {
@@ -263,7 +265,7 @@ EVENT_TRANSLATION_MAP: dict[str, str] = {
CONNECTION_STATUS: Final[str] = "CONNECTION_STATUS"
DEVICE_BUTTONS: Final[list[str]] = [x.value for x in BangOlufsenButtons]
DEVICE_BUTTONS: Final[list[str]] = [x.value for x in BeoButtons]
DEVICE_BUTTON_EVENTS: Final[list[str]] = [

View File

@@ -10,13 +10,13 @@ from homeassistant.const import CONF_MODEL
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import BangOlufsenConfigEntry
from . import BeoConfigEntry
from .const import DOMAIN
from .util import get_device_buttons
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: BangOlufsenConfigEntry
hass: HomeAssistant, config_entry: BeoConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""

View File

@@ -24,8 +24,8 @@ from homeassistant.helpers.entity import Entity
from .const import DOMAIN
class BangOlufsenBase:
"""Base class for BangOlufsen Home Assistant objects."""
class BeoBase:
"""Base class for Bang & Olufsen Home Assistant objects."""
def __init__(self, entry: ConfigEntry, client: MozartClient) -> None:
"""Initialize the object."""
@@ -51,8 +51,8 @@ class BangOlufsenBase:
)
class BangOlufsenEntity(Entity, BangOlufsenBase):
"""Base Entity for BangOlufsen entities."""
class BeoEntity(Entity, BeoBase):
"""Base Entity for Bang & Olufsen entities."""
_attr_has_entity_name = True
_attr_should_poll = False

View File

@@ -14,7 +14,7 @@ from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import BangOlufsenConfigEntry
from . import BeoConfigEntry
from .const import (
BEO_REMOTE_CONTROL_KEYS,
BEO_REMOTE_KEY_EVENTS,
@@ -25,10 +25,10 @@ from .const import (
DEVICE_BUTTON_EVENTS,
DOMAIN,
MANUFACTURER,
BangOlufsenModel,
BeoModel,
WebsocketNotification,
)
from .entity import BangOlufsenEntity
from .entity import BeoEntity
from .util import get_device_buttons, get_remotes
PARALLEL_UPDATES = 0
@@ -36,14 +36,14 @@ PARALLEL_UPDATES = 0
async def async_setup_entry(
hass: HomeAssistant,
config_entry: BangOlufsenConfigEntry,
config_entry: BeoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Event entities from config entry."""
entities: list[BangOlufsenEvent] = []
entities: list[BeoEvent] = []
async_add_entities(
BangOlufsenButtonEvent(config_entry, button_type)
BeoButtonEvent(config_entry, button_type)
for button_type in get_device_buttons(config_entry.data[CONF_MODEL])
)
@@ -54,7 +54,7 @@ async def async_setup_entry(
# Add Light keys
entities.extend(
[
BangOlufsenRemoteKeyEvent(
BeoRemoteKeyEvent(
config_entry,
remote,
f"{BEO_REMOTE_SUBMENU_LIGHT}/{key_type}",
@@ -66,7 +66,7 @@ async def async_setup_entry(
# Add Control keys
entities.extend(
[
BangOlufsenRemoteKeyEvent(
BeoRemoteKeyEvent(
config_entry,
remote,
f"{BEO_REMOTE_SUBMENU_CONTROL}/{key_type}",
@@ -84,10 +84,9 @@ async def async_setup_entry(
config_entry.entry_id
)
for device in devices:
if (
device.model == BangOlufsenModel.BEOREMOTE_ONE
and device.serial_number not in {remote.serial_number for remote in remotes}
):
if device.model == BeoModel.BEOREMOTE_ONE and device.serial_number not in {
remote.serial_number for remote in remotes
}:
device_registry.async_update_device(
device.id, remove_config_entry_id=config_entry.entry_id
)
@@ -95,13 +94,13 @@ async def async_setup_entry(
async_add_entities(new_entities=entities)
class BangOlufsenEvent(BangOlufsenEntity, EventEntity):
class BeoEvent(BeoEntity, EventEntity):
"""Base Event class."""
_attr_device_class = EventDeviceClass.BUTTON
_attr_entity_registry_enabled_default = False
def __init__(self, config_entry: BangOlufsenConfigEntry) -> None:
def __init__(self, config_entry: BeoConfigEntry) -> None:
"""Initialize Event."""
super().__init__(config_entry, config_entry.runtime_data.client)
@@ -112,12 +111,12 @@ class BangOlufsenEvent(BangOlufsenEntity, EventEntity):
self.async_write_ha_state()
class BangOlufsenButtonEvent(BangOlufsenEvent):
class BeoButtonEvent(BeoEvent):
"""Event class for Button events."""
_attr_event_types = DEVICE_BUTTON_EVENTS
def __init__(self, config_entry: BangOlufsenConfigEntry, button_type: str) -> None:
def __init__(self, config_entry: BeoConfigEntry, button_type: str) -> None:
"""Initialize Button."""
super().__init__(config_entry)
@@ -146,14 +145,14 @@ class BangOlufsenButtonEvent(BangOlufsenEvent):
)
class BangOlufsenRemoteKeyEvent(BangOlufsenEvent):
class BeoRemoteKeyEvent(BeoEvent):
"""Event class for Beoremote One key events."""
_attr_event_types = BEO_REMOTE_KEY_EVENTS
def __init__(
self,
config_entry: BangOlufsenConfigEntry,
config_entry: BeoConfigEntry,
remote: PairedRemote,
key_type: str,
) -> None:
@@ -166,8 +165,8 @@ class BangOlufsenRemoteKeyEvent(BangOlufsenEvent):
self._attr_unique_id = f"{remote.serial_number}_{self._unique_id}_{key_type}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{remote.serial_number}_{self._unique_id}")},
name=f"{BangOlufsenModel.BEOREMOTE_ONE}-{remote.serial_number}-{self._unique_id}",
model=BangOlufsenModel.BEOREMOTE_ONE,
name=f"{BeoModel.BEOREMOTE_ONE}-{remote.serial_number}-{self._unique_id}",
model=BeoModel.BEOREMOTE_ONE,
serial_number=remote.serial_number,
sw_version=remote.app_version,
manufacturer=MANUFACTURER,

View File

@@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/bang_olufsen",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["mozart-api==5.1.0.247.1"],
"requirements": ["mozart-api==5.3.1.108.0"],
"zeroconf": ["_bangolufsen._tcp.local."]
}

View File

@@ -69,11 +69,11 @@ from homeassistant.helpers.entity_platform import (
)
from homeassistant.util.dt import utcnow
from . import BangOlufsenConfigEntry
from . import BeoConfigEntry
from .const import (
BANG_OLUFSEN_REPEAT_FROM_HA,
BANG_OLUFSEN_REPEAT_TO_HA,
BANG_OLUFSEN_STATES,
BEO_REPEAT_FROM_HA,
BEO_REPEAT_TO_HA,
BEO_STATES,
BEOLINK_JOIN_SOURCES,
BEOLINK_JOIN_SOURCES_TO_UPPER,
CONF_BEOLINK_JID,
@@ -82,12 +82,12 @@ from .const import (
FALLBACK_SOURCES,
MANUFACTURER,
VALID_MEDIA_TYPES,
BangOlufsenAttribute,
BangOlufsenMediaType,
BangOlufsenSource,
BeoAttribute,
BeoMediaType,
BeoSource,
WebsocketNotification,
)
from .entity import BangOlufsenEntity
from .entity import BeoEntity
from .util import get_serial_number_from_jid
PARALLEL_UPDATES = 0
@@ -96,7 +96,7 @@ SCAN_INTERVAL = timedelta(seconds=30)
_LOGGER = logging.getLogger(__name__)
BANG_OLUFSEN_FEATURES = (
BEO_FEATURES = (
MediaPlayerEntityFeature.BROWSE_MEDIA
| MediaPlayerEntityFeature.CLEAR_PLAYLIST
| MediaPlayerEntityFeature.GROUPING
@@ -119,15 +119,13 @@ BANG_OLUFSEN_FEATURES = (
async def async_setup_entry(
hass: HomeAssistant,
config_entry: BangOlufsenConfigEntry,
config_entry: BeoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up a Media Player entity from config entry."""
# Add MediaPlayer entity
async_add_entities(
new_entities=[
BangOlufsenMediaPlayer(config_entry, config_entry.runtime_data.client)
],
new_entities=[BeoMediaPlayer(config_entry, config_entry.runtime_data.client)],
update_before_add=True,
)
@@ -187,7 +185,7 @@ async def async_setup_entry(
)
class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
class BeoMediaPlayer(BeoEntity, MediaPlayerEntity):
"""Representation of a media player."""
_attr_name = None
@@ -220,6 +218,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
self._sources: dict[str, str] = {}
self._state: str = MediaPlayerState.IDLE
self._video_sources: dict[str, str] = {}
self._video_source_id_map: dict[str, str] = {}
self._sound_modes: dict[str, int] = {}
# Beolink compatible sources
@@ -288,7 +287,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
queue_settings = await self._client.get_settings_queue(_request_timeout=5)
if queue_settings.repeat is not None:
self._attr_repeat = BANG_OLUFSEN_REPEAT_TO_HA[queue_settings.repeat]
self._attr_repeat = BEO_REPEAT_TO_HA[queue_settings.repeat]
if queue_settings.shuffle is not None:
self._attr_shuffle = queue_settings.shuffle
@@ -357,6 +356,9 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
and menu_item.label != "TV"
):
self._video_sources[key] = menu_item.label
self._video_source_id_map[
menu_item.content.content_uri.removeprefix("tv://")
] = menu_item.label
# Combine the source dicts
self._sources = self._audio_sources | self._video_sources
@@ -408,8 +410,8 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
# Check if source is line-in or optical and progress should be updated
if self._source_change.id in (
BangOlufsenSource.LINE_IN.id,
BangOlufsenSource.SPDIF.id,
BeoSource.LINE_IN.id,
BeoSource.SPDIF.id,
):
self._playback_progress = PlaybackProgress(progress=0)
@@ -450,10 +452,8 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
# Add Beolink self
self._beolink_attributes = {
BangOlufsenAttribute.BEOLINK: {
BangOlufsenAttribute.BEOLINK_SELF: {
self.device_entry.name: self._beolink_jid
}
BeoAttribute.BEOLINK: {
BeoAttribute.BEOLINK_SELF: {self.device_entry.name: self._beolink_jid}
}
}
@@ -461,12 +461,12 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
peers = await self._client.get_beolink_peers()
if len(peers) > 0:
self._beolink_attributes[BangOlufsenAttribute.BEOLINK][
BangOlufsenAttribute.BEOLINK_PEERS
self._beolink_attributes[BeoAttribute.BEOLINK][
BeoAttribute.BEOLINK_PEERS
] = {}
for peer in peers:
self._beolink_attributes[BangOlufsenAttribute.BEOLINK][
BangOlufsenAttribute.BEOLINK_PEERS
self._beolink_attributes[BeoAttribute.BEOLINK][
BeoAttribute.BEOLINK_PEERS
][peer.friendly_name] = peer.jid
# Add Beolink listeners / leader
@@ -488,8 +488,8 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
# Add self
group_members.append(self.entity_id)
self._beolink_attributes[BangOlufsenAttribute.BEOLINK][
BangOlufsenAttribute.BEOLINK_LEADER
self._beolink_attributes[BeoAttribute.BEOLINK][
BeoAttribute.BEOLINK_LEADER
] = {
self._remote_leader.friendly_name: self._remote_leader.jid,
}
@@ -527,8 +527,8 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
beolink_listener.jid
)
break
self._beolink_attributes[BangOlufsenAttribute.BEOLINK][
BangOlufsenAttribute.BEOLINK_LISTENERS
self._beolink_attributes[BeoAttribute.BEOLINK][
BeoAttribute.BEOLINK_LISTENERS
] = beolink_listeners_attribute
self._attr_group_members = group_members
@@ -587,7 +587,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
for sound_mode in sound_modes:
label = f"{sound_mode.name} ({sound_mode.id})"
self._sound_modes[label] = sound_mode.id
self._sound_modes[label] = cast(int, sound_mode.id)
if sound_mode.id == active_sound_mode.id:
self._attr_sound_mode = label
@@ -600,7 +600,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
@property
def supported_features(self) -> MediaPlayerEntityFeature:
"""Flag media player features that are supported."""
features = BANG_OLUFSEN_FEATURES
features = BEO_FEATURES
# Add seeking if supported by the current source
if self._source_change.is_seekable is True:
@@ -611,7 +611,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
@property
def state(self) -> MediaPlayerState:
"""Return the current state of the media player."""
return BANG_OLUFSEN_STATES[self._state]
return BEO_STATES[self._state]
@property
def volume_level(self) -> float | None:
@@ -631,10 +631,11 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
def media_content_type(self) -> MediaType | str | None:
"""Return the current media type."""
content_type = {
BangOlufsenSource.URI_STREAMER.id: MediaType.URL,
BangOlufsenSource.DEEZER.id: BangOlufsenMediaType.DEEZER,
BangOlufsenSource.TIDAL.id: BangOlufsenMediaType.TIDAL,
BangOlufsenSource.NET_RADIO.id: BangOlufsenMediaType.RADIO,
BeoSource.DEEZER.id: BeoMediaType.DEEZER,
BeoSource.NET_RADIO.id: BeoMediaType.RADIO,
BeoSource.TIDAL.id: BeoMediaType.TIDAL,
BeoSource.TV.id: BeoMediaType.TV,
BeoSource.URI_STREAMER.id: MediaType.URL,
}
# Hard to determine content type.
if self._source_change.id in content_type:
@@ -694,7 +695,11 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
@property
def source(self) -> str | None:
"""Return the current audio source."""
"""Return the current audio/video source."""
# Associate TV content ID with a video source
if self.media_content_id in self._video_source_id_map:
return self._video_source_id_map[self.media_content_id]
return self._source_change.name
@property
@@ -765,9 +770,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
async def async_set_repeat(self, repeat: RepeatMode) -> None:
"""Set playback queues to repeat."""
await self._client.set_settings_queue(
play_queue_settings=PlayQueueSettings(
repeat=BANG_OLUFSEN_REPEAT_FROM_HA[repeat]
)
play_queue_settings=PlayQueueSettings(repeat=BEO_REPEAT_FROM_HA[repeat])
)
async def async_set_shuffle(self, shuffle: bool) -> None:
@@ -871,7 +874,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
self._volume.level.level + offset_volume, 100
)
if media_type == BangOlufsenMediaType.OVERLAY_TTS:
if media_type == BeoMediaType.OVERLAY_TTS:
# Bang & Olufsen cloud TTS
overlay_play_request.text_to_speech = (
OverlayPlayRequestTextToSpeechTextToSpeech(
@@ -888,14 +891,14 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
# The "provider" media_type may not be suitable for overlay all the time.
# Use it for now.
elif media_type == BangOlufsenMediaType.TTS:
elif media_type == BeoMediaType.TTS:
await self._client.post_overlay_play(
overlay_play_request=OverlayPlayRequest(
uri=Uri(location=media_id),
)
)
elif media_type == BangOlufsenMediaType.RADIO:
elif media_type == BeoMediaType.RADIO:
await self._client.run_provided_scene(
scene_properties=SceneProperties(
action_list=[
@@ -907,13 +910,13 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
)
)
elif media_type == BangOlufsenMediaType.FAVOURITE:
elif media_type == BeoMediaType.FAVOURITE:
await self._client.activate_preset(id=int(media_id))
elif media_type in (BangOlufsenMediaType.DEEZER, BangOlufsenMediaType.TIDAL):
elif media_type in (BeoMediaType.DEEZER, BeoMediaType.TIDAL):
try:
# Play Deezer flow.
if media_id == "flow" and media_type == BangOlufsenMediaType.DEEZER:
if media_id == "flow" and media_type == BeoMediaType.DEEZER:
deezer_id = None
if "id" in kwargs[ATTR_MEDIA_EXTRA]:

View File

@@ -11,7 +11,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceEntry
from .const import DEVICE_BUTTONS, DOMAIN, BangOlufsenButtons, BangOlufsenModel
from .const import DEVICE_BUTTONS, DOMAIN, BeoButtons, BeoModel
def get_device(hass: HomeAssistant, unique_id: str) -> DeviceEntry:
@@ -40,16 +40,27 @@ async def get_remotes(client: MozartClient) -> list[PairedRemote]:
]
def get_device_buttons(model: BangOlufsenModel) -> list[str]:
def get_device_buttons(model: BeoModel) -> list[str]:
"""Get supported buttons for a given model."""
# Beoconnect Core does not have any buttons
if model == BeoModel.BEOCONNECT_CORE:
return []
buttons = DEVICE_BUTTONS.copy()
# Beosound Premiere does not have a bluetooth button
if model == BangOlufsenModel.BEOSOUND_PREMIERE:
buttons.remove(BangOlufsenButtons.BLUETOOTH)
# Models that don't have a microphone button
if model in (
BeoModel.BEOSOUND_A5,
BeoModel.BEOSOUND_A9,
BeoModel.BEOSOUND_PREMIERE,
):
buttons.remove(BeoButtons.MICROPHONE)
# Beoconnect Core does not have any buttons
elif model == BangOlufsenModel.BEOCONNECT_CORE:
buttons = []
# Models that don't have a Bluetooth button
if model in (
BeoModel.BEOSOUND_A9,
BeoModel.BEOSOUND_PREMIERE,
):
buttons.remove(BeoButtons.BLUETOOTH)
return buttons

View File

@@ -27,20 +27,20 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.util.enum import try_parse_enum
from .const import (
BANG_OLUFSEN_WEBSOCKET_EVENT,
BEO_WEBSOCKET_EVENT,
CONNECTION_STATUS,
DOMAIN,
EVENT_TRANSLATION_MAP,
BangOlufsenModel,
BeoModel,
WebsocketNotification,
)
from .entity import BangOlufsenBase
from .entity import BeoBase
from .util import get_device, get_remotes
_LOGGER = logging.getLogger(__name__)
class BangOlufsenWebsocket(BangOlufsenBase):
class BeoWebsocket(BeoBase):
"""The WebSocket listeners."""
def __init__(
@@ -48,7 +48,7 @@ class BangOlufsenWebsocket(BangOlufsenBase):
) -> None:
"""Initialize the WebSocket listeners."""
BangOlufsenBase.__init__(self, entry, client)
BeoBase.__init__(self, entry, client)
self.hass = hass
self._device = get_device(hass, self._unique_id)
@@ -178,7 +178,7 @@ class BangOlufsenWebsocket(BangOlufsenBase):
self.entry.entry_id
)
if device.serial_number is not None
and device.model == BangOlufsenModel.BEOREMOTE_ONE
and device.model == BeoModel.BEOREMOTE_ONE
]
# Get paired remotes from device
remote_serial_numbers = [
@@ -274,4 +274,4 @@ class BangOlufsenWebsocket(BangOlufsenBase):
}
_LOGGER.debug("%s", debug_notification)
self.hass.bus.async_fire(BANG_OLUFSEN_WEBSOCKET_EVENT, debug_notification)
self.hass.bus.async_fire(BEO_WEBSOCKET_EVENT, debug_notification)

View File

@@ -4,6 +4,7 @@
"codeowners": ["@bbx-a", "@swistakm"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/blebox",
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["blebox_uniapi"],
"requirements": ["blebox-uniapi==2.5.0"],

View File

@@ -64,6 +64,12 @@ async def async_migrate_entry(hass: HomeAssistant, entry: BlinkConfigEntry) -> b
if entry.version == 2:
await _reauth_flow_wrapper(hass, entry, data)
return False
if entry.version == 3:
# Migrate device_id to hardware_id for blinkpy 0.25.x OAuth2 compatibility
if "device_id" in data:
data["hardware_id"] = data.pop("device_id")
hass.config_entries.async_update_entry(entry, data=data, version=4)
return True
return True

View File

@@ -21,7 +21,7 @@ from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DEVICE_ID, DOMAIN
from .const import DOMAIN, HARDWARE_ID
_LOGGER = logging.getLogger(__name__)
@@ -43,7 +43,7 @@ async def _send_blink_2fa_pin(blink: Blink, pin: str | None) -> bool:
class BlinkConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a Blink config flow."""
VERSION = 3
VERSION = 4
def __init__(self) -> None:
"""Initialize the blink flow."""
@@ -53,7 +53,7 @@ class BlinkConfigFlow(ConfigFlow, domain=DOMAIN):
async def _handle_user_input(self, user_input: dict[str, Any]):
"""Handle user input."""
self.auth = Auth(
{**user_input, "device_id": DEVICE_ID},
{**user_input, "hardware_id": HARDWARE_ID},
no_prompt=True,
session=async_get_clientsession(self.hass),
)

View File

@@ -3,7 +3,7 @@
from homeassistant.const import Platform
DOMAIN = "blink"
DEVICE_ID = "Home Assistant"
HARDWARE_ID = "Home Assistant"
CONF_MIGRATE = "migrate"
CONF_CAMERA = "camera"

View File

@@ -1,7 +1,7 @@
{
"domain": "blink",
"name": "Blink",
"codeowners": ["@fronzbot", "@mkmer"],
"codeowners": ["@fronzbot"],
"config_flow": true,
"dhcp": [
{
@@ -18,7 +18,8 @@
}
],
"documentation": "https://www.home-assistant.io/integrations/blink",
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["blinkpy"],
"requirements": ["blinkpy==0.24.1"]
"requirements": ["blinkpy==0.25.2"]
}

View File

@@ -13,32 +13,25 @@ from bluecurrent_api.exceptions import (
RequestLimitReached,
WebsocketError,
)
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import CONF_API_TOKEN, CONF_DEVICE_ID, Platform
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.exceptions import (
ConfigEntryAuthFailed,
ConfigEntryNotReady,
ServiceValidationError,
)
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_TOKEN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.typing import ConfigType
from .const import (
BCU_APP,
CHARGEPOINT_SETTINGS,
CHARGEPOINT_STATUS,
CHARGING_CARD_ID,
DOMAIN,
EVSE_ID,
LOGGER,
PLUG_AND_CHARGE,
SERVICE_START_CHARGE_SESSION,
VALUE,
)
from .services import async_setup_services
type BlueCurrentConfigEntry = ConfigEntry[Connector]
@@ -54,13 +47,12 @@ VALUE_TYPES = [CHARGEPOINT_STATUS, CHARGEPOINT_SETTINGS]
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
SERVICE_START_CHARGE_SESSION_SCHEMA = vol.Schema(
{
vol.Required(CONF_DEVICE_ID): cv.string,
# When no charging card is provided, use no charging card (BCU_APP = no charging card).
vol.Optional(CHARGING_CARD_ID, default=BCU_APP): cv.string,
}
)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Blue Current."""
async_setup_services(hass)
return True
async def async_setup_entry(
@@ -88,66 +80,6 @@ async def async_setup_entry(
return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Blue Current."""
async def start_charge_session(service_call: ServiceCall) -> None:
"""Start a charge session with the provided device and charge card ID."""
# When no charge card is provided, use the default charge card set in the config flow.
charging_card_id = service_call.data[CHARGING_CARD_ID]
device_id = service_call.data[CONF_DEVICE_ID]
# Get the device based on the given device ID.
device = dr.async_get(hass).devices.get(device_id)
if device is None:
raise ServiceValidationError(
translation_domain=DOMAIN, translation_key="invalid_device_id"
)
blue_current_config_entry: ConfigEntry | None = None
for config_entry_id in device.config_entries:
config_entry = hass.config_entries.async_get_entry(config_entry_id)
if not config_entry or config_entry.domain != DOMAIN:
# Not the blue_current config entry.
continue
if config_entry.state is not ConfigEntryState.LOADED:
raise ServiceValidationError(
translation_domain=DOMAIN, translation_key="config_entry_not_loaded"
)
blue_current_config_entry = config_entry
break
if not blue_current_config_entry:
# The device is not connected to a valid blue_current config entry.
raise ServiceValidationError(
translation_domain=DOMAIN, translation_key="no_config_entry"
)
connector = blue_current_config_entry.runtime_data
# Get the evse_id from the identifier of the device.
evse_id = next(
identifier[1]
for identifier in device.identifiers
if identifier[0] == DOMAIN
)
await connector.client.start_session(evse_id, charging_card_id)
hass.services.async_register(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
start_charge_session,
SERVICE_START_CHARGE_SESSION_SCHEMA,
)
return True
async def async_unload_entry(
hass: HomeAssistant, config_entry: BlueCurrentConfigEntry
) -> bool:

View File

@@ -4,6 +4,7 @@
"codeowners": ["@gleeuwen", "@NickKoepr", "@jtodorova23"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/blue_current",
"integration_type": "hub",
"iot_class": "cloud_push",
"loggers": ["bluecurrent_api"],
"requirements": ["bluecurrent-api==1.3.2"]

View File

@@ -0,0 +1,79 @@
"""The Blue Current integration."""
from __future__ import annotations
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import CONF_DEVICE_ID
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 BCU_APP, CHARGING_CARD_ID, DOMAIN, SERVICE_START_CHARGE_SESSION
SERVICE_START_CHARGE_SESSION_SCHEMA = vol.Schema(
{
vol.Required(CONF_DEVICE_ID): cv.string,
# When no charging card is provided, use no charging card (BCU_APP = no charging card).
vol.Optional(CHARGING_CARD_ID, default=BCU_APP): cv.string,
}
)
async def start_charge_session(service_call: ServiceCall) -> None:
"""Start a charge session with the provided device and charge card ID."""
# When no charge card is provided, use the default charge card set in the config flow.
charging_card_id = service_call.data[CHARGING_CARD_ID]
device_id = service_call.data[CONF_DEVICE_ID]
# Get the device based on the given device ID.
device = dr.async_get(service_call.hass).devices.get(device_id)
if device is None:
raise ServiceValidationError(
translation_domain=DOMAIN, translation_key="invalid_device_id"
)
blue_current_config_entry: ConfigEntry | None = None
for config_entry_id in device.config_entries:
config_entry = service_call.hass.config_entries.async_get_entry(config_entry_id)
if not config_entry or config_entry.domain != DOMAIN:
# Not the blue_current config entry.
continue
if config_entry.state is not ConfigEntryState.LOADED:
raise ServiceValidationError(
translation_domain=DOMAIN, translation_key="config_entry_not_loaded"
)
blue_current_config_entry = config_entry
break
if not blue_current_config_entry:
# The device is not connected to a valid blue_current config entry.
raise ServiceValidationError(
translation_domain=DOMAIN, translation_key="no_config_entry"
)
connector = blue_current_config_entry.runtime_data
# Get the evse_id from the identifier of the device.
evse_id = next(
identifier[1] for identifier in device.identifiers if identifier[0] == DOMAIN
)
await connector.client.start_session(evse_id, charging_card_id)
@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Register the services."""
hass.services.async_register(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
start_charge_session,
SERVICE_START_CHARGE_SESSION_SCHEMA,
)

View File

@@ -11,6 +11,7 @@
"config_flow": true,
"dependencies": ["bluetooth_adapters"],
"documentation": "https://www.home-assistant.io/integrations/bluemaestro",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["bluemaestro-ble==0.4.1"]
}

View File

@@ -5,6 +5,7 @@
"codeowners": ["@thrawnarn", "@LouisChrist"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/bluesound",
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["pyblu==2.0.5"],
"zeroconf": [

View File

@@ -15,7 +15,7 @@
],
"quality_scale": "internal",
"requirements": [
"bleak==1.0.1",
"bleak==2.0.0",
"bleak-retry-connector==4.4.3",
"bluetooth-adapters==2.1.0",
"bluetooth-auto-recovery==1.5.3",

View File

@@ -4,6 +4,7 @@
"codeowners": ["@gerard33", "@rikroe"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive",
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["bimmer_connected"],
"requirements": ["bimmer-connected[china]==0.17.3"]

View File

@@ -14,6 +14,7 @@
}
],
"documentation": "https://www.home-assistant.io/integrations/bond",
"integration_type": "hub",
"iot_class": "local_push",
"loggers": ["bond_async"],
"requirements": ["bond-async==0.2.1"],

View File

@@ -5,6 +5,7 @@
"codeowners": ["@tschamm"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/bosch_shc",
"integration_type": "hub",
"iot_class": "local_push",
"loggers": ["boschshcpy"],
"requirements": ["boschshcpy==0.2.107"],

View File

@@ -4,6 +4,7 @@
"codeowners": ["@gjohansson-ST"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/brottsplatskartan",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["brottsplatskartan"],
"requirements": ["brottsplatskartan==1.0.5"]

View File

@@ -4,6 +4,7 @@
"codeowners": ["@eavanvalkenburg"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/brunt",
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["brunt"],
"requirements": ["brunt==1.2.0"]

View File

@@ -2,7 +2,7 @@
from __future__ import annotations
from typing import Any
from typing import Any, Final
from bsblan import BSBLANError
@@ -17,7 +17,7 @@ from homeassistant.components.climate import (
)
from homeassistant.const import ATTR_TEMPERATURE
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import format_mac
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util.enum import try_parse_enum
@@ -39,6 +39,22 @@ PRESET_MODES = [
PRESET_NONE,
]
# Mapping from Home Assistant HVACMode to BSB-Lan integer values
# BSB-Lan uses: 0=off, 1=auto, 2=eco/reduced, 3=heat/comfort
HA_TO_BSBLAN_HVAC_MODE: Final[dict[HVACMode, int]] = {
HVACMode.OFF: 0,
HVACMode.AUTO: 1,
HVACMode.HEAT: 3,
}
# Mapping from BSB-Lan integer values to Home Assistant HVACMode
BSBLAN_TO_HA_HVAC_MODE: Final[dict[int, HVACMode]] = {
0: HVACMode.OFF,
1: HVACMode.AUTO,
2: HVACMode.AUTO, # eco/reduced maps to AUTO with preset
3: HVACMode.HEAT,
}
async def async_setup_entry(
hass: HomeAssistant,
@@ -98,17 +114,20 @@ class BSBLANClimate(BSBLanEntity, ClimateEntity):
@property
def hvac_mode(self) -> HVACMode | None:
"""Return hvac operation ie. heat, cool mode."""
if self.coordinator.data.state.hvac_mode.value == PRESET_ECO:
return HVACMode.AUTO
return try_parse_enum(HVACMode, self.coordinator.data.state.hvac_mode.value)
hvac_mode_value = self.coordinator.data.state.hvac_mode.value
if hvac_mode_value is None:
return None
# BSB-Lan returns integer values: 0=off, 1=auto, 2=eco, 3=heat
if isinstance(hvac_mode_value, int):
return BSBLAN_TO_HA_HVAC_MODE.get(hvac_mode_value)
return try_parse_enum(HVACMode, hvac_mode_value)
@property
def preset_mode(self) -> str | None:
"""Return the current preset mode."""
if (
self.hvac_mode == HVACMode.AUTO
and self.coordinator.data.state.hvac_mode.value == PRESET_ECO
):
hvac_mode_value = self.coordinator.data.state.hvac_mode.value
# BSB-Lan mode 2 is eco/reduced mode
if hvac_mode_value == 2:
return PRESET_ECO
return PRESET_NONE
@@ -118,13 +137,6 @@ class BSBLANClimate(BSBLanEntity, ClimateEntity):
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set preset mode."""
if self.hvac_mode != HVACMode.AUTO and preset_mode != PRESET_NONE:
raise ServiceValidationError(
"Preset mode can only be set when HVAC mode is set to 'auto'",
translation_domain=DOMAIN,
translation_key="set_preset_mode_error",
translation_placeholders={"preset_mode": preset_mode},
)
await self.async_set_data(preset_mode=preset_mode)
async def async_set_temperature(self, **kwargs: Any) -> None:
@@ -133,16 +145,17 @@ class BSBLANClimate(BSBLanEntity, ClimateEntity):
async def async_set_data(self, **kwargs: Any) -> None:
"""Set device settings using BSBLAN."""
data = {}
data: dict[str, Any] = {}
if ATTR_TEMPERATURE in kwargs:
data[ATTR_TARGET_TEMPERATURE] = kwargs[ATTR_TEMPERATURE]
if ATTR_HVAC_MODE in kwargs:
data[ATTR_HVAC_MODE] = kwargs[ATTR_HVAC_MODE]
data[ATTR_HVAC_MODE] = HA_TO_BSBLAN_HVAC_MODE[kwargs[ATTR_HVAC_MODE]]
if ATTR_PRESET_MODE in kwargs:
# eco preset uses BSB-Lan mode 2, none preset uses mode 1 (auto)
if kwargs[ATTR_PRESET_MODE] == PRESET_ECO:
data[ATTR_HVAC_MODE] = PRESET_ECO
data[ATTR_HVAC_MODE] = 2
elif kwargs[ATTR_PRESET_MODE] == PRESET_NONE:
data[ATTR_HVAC_MODE] = PRESET_NONE
data[ATTR_HVAC_MODE] = 1
try:
await self.coordinator.client.thermostat(**data)

View File

@@ -7,7 +7,7 @@
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["bsblan"],
"requirements": ["python-bsblan==3.1.1"],
"requirements": ["python-bsblan==3.1.4"],
"zeroconf": [
{
"name": "bsb-lan*",

View File

@@ -4,7 +4,7 @@ from __future__ import annotations
from typing import Any
from bsblan import BSBLANError
from bsblan import BSBLANError, SetHotWaterParam
from homeassistant.components.water_heater import (
STATE_ECO,
@@ -131,7 +131,9 @@ class BSBLANWaterHeater(BSBLanDualCoordinatorEntity, WaterHeaterEntity):
"""Set new target temperature."""
temperature = kwargs.get(ATTR_TEMPERATURE)
try:
await self.coordinator.client.set_hot_water(nominal_setpoint=temperature)
await self.coordinator.client.set_hot_water(
SetHotWaterParam(nominal_setpoint=temperature)
)
except BSBLANError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
@@ -144,7 +146,9 @@ class BSBLANWaterHeater(BSBLanDualCoordinatorEntity, WaterHeaterEntity):
"""Set new operation mode."""
bsblan_mode = OPERATION_MODES_REVERSE.get(operation_mode)
try:
await self.coordinator.client.set_hot_water(operating_mode=bsblan_mode)
await self.coordinator.client.set_hot_water(
SetHotWaterParam(operating_mode=bsblan_mode)
)
except BSBLANError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,

View File

@@ -4,6 +4,7 @@
"codeowners": ["@mjj4791", "@ties", "@Robbie1221"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/buienradar",
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["buienradar", "vincenty"],
"requirements": ["buienradar==1.0.6"]

View File

@@ -17,5 +17,10 @@
"press": {
"service": "mdi:gesture-tap-button"
}
},
"triggers": {
"pressed": {
"trigger": "mdi:gesture-tap-button"
}
}
}

View File

@@ -27,5 +27,11 @@
"name": "Press"
}
},
"title": "Button"
"title": "Button",
"triggers": {
"pressed": {
"description": "Triggers when a button was pressed",
"name": "Button pressed"
}
}
}

View File

@@ -0,0 +1,42 @@
"""Provides triggers for buttons."""
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant, State
from homeassistant.helpers.trigger import (
ENTITY_STATE_TRIGGER_SCHEMA,
EntityTriggerBase,
Trigger,
)
from . import DOMAIN
class ButtonPressedTrigger(EntityTriggerBase):
"""Trigger for button entity presses."""
_domain = DOMAIN
_schema = ENTITY_STATE_TRIGGER_SCHEMA
def is_valid_transition(self, from_state: State, to_state: State) -> bool:
"""Check if the origin state is valid and different from the current state."""
# UNKNOWN is a valid from_state, otherwise the first time the button is pressed
# would not trigger
if from_state.state == STATE_UNAVAILABLE:
return False
return from_state.state != to_state.state
def is_valid_state(self, state: State) -> bool:
"""Check if the new state is not invalid."""
return state.state not in (STATE_UNAVAILABLE, STATE_UNKNOWN)
TRIGGERS: dict[str, type[Trigger]] = {
"pressed": ButtonPressedTrigger,
}
async def async_get_triggers(hass: HomeAssistant) -> dict[str, type[Trigger]]:
"""Return the triggers for buttons."""
return TRIGGERS

View File

@@ -0,0 +1,4 @@
pressed:
target:
entity:
domain: button

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