Compare commits

...

16 Commits

Author SHA1 Message Date
Franck Nijhof
97cc3984c5 2025.3.0 (#139859)
* Add vesync debug mode in library (#134571)

* Debug mode pass through

* Correct code, shouldn't have been lambda

* listener for change

* ruff

* Update manifest.json

* Reflect correct logger title

* Ruff fix from merge

* Fix return value for DataUpdateCoordinator._async setup (#139181)

Fix return value for coodinator async setup

* Fix race in WS command recorder/info (#139177)

* Fix race in WS command recorder/info

* Add comment

* Remove unnecessary local import

* Bump aiohttp to 3.11.13 (#139197)

changelog: https://github.com/aio-libs/aiohttp/compare/v3.11.12...v3.11.13

* Update Linkplay constants for Arylic S10+ and Arylic Up2Stream Amp 2.1 (#138198)

* Add support for Apps and Radios to Squeezebox Media Browser (#135009)

* Add azure_storage as backup agent (#134085)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Bump onedrive quality scale to platinum (#137451)

* Bump pyloadapi to v1.4.2 (#139140)

* Add missing translations to switchbot (#139212)

* Fix bug in check_translations fixture (#139206)

* Fix bug in check_translations fixture

* Fix check for ignored translation errors

* Fix websocket_api test

* Add missing exception translation to Home Connect (#139218)

Add missing exception translation

* Configure trusted publishing for PyPI file upload (#137607)

* Bump aiostreammagic to 2.11.0 (#139213)

* Add missing exception translation to Home Connect (#139223)

* Bump ohmepy to 1.3.2 (#139013)

* Fix kitchen_sink statistic issues (#139228)

* Bump aiowebdav2 to 0.3.0 (#139202)

* Bump pylamarzocco to 1.4.7 (#139231)

* Add backup helper (#139199)

* Add backup helper

* Add hassio to stage 1

* Apply same changes to newly merged `webdav` and `azure_storage` to fix inflight conflict

* Address comments, add tests

---------

Co-authored-by: J. Nick Koston <nick@koston.org>

* Reduce requests made by webdav (#139238)

* Reduce requests made by webdav

* Update homeassistant/components/webdav/backup.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Add Homee valve platform (#139188)

* Fix units for LCN sensor (#138940)

* Add Ohme voltage and slot list sensor (#139203)

* Bump ohmepy to 1.3.1

* Bump ohmepy to 1.3.2

* Add voltage and slot list sensor

* CI fixes

* Change slot list sensor name

* Fix snapshot tests

* Initiate source list as instance variable in Volumio (#139243)

* `logbook.log` action: Make description of  `name` field UI-friendly (#139200)

* Treat "Twist Assist" & "Block to Block" as feature names and add descriptions in Z-Wave (#139239)

Treat "Twist Assist" & "Block to Block" as feature names and add descriptions

- name-case both "Twist Assist" and "Block to Block" so those feature names don't get translated
- for proper translation of both features add useful descriptions of what they actually do
- fix sentence-casing on "Operation type"

* Add climate's swing mode to LG ThinQ (#137619)

Co-authored-by: yunseon.park <yunseon.park@lge.com>

* Bump aiowithings to 3.1.6 (#139242)

* Add update reward action to Habitica integration (#139157)

* Add Re-Auth Flow to vesync (#137398)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Rework the velbus configflow to make it more user-friendly (#135609)

* Add missing ATTR_HVAC_MODE of async_set_temperature to LG ThinQ (#137621)

Co-authored-by: yunseon.park <yunseon.park@lge.com>

* Make Radarr units translatable (#139250)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Improve Minecraft Server config flow tests (#139251)

* Revert "Bump Stookwijzer to 1.5.7" (#139253)

* Add parallel updates to Home Connect (#139255)

* Bump fnv-hash-fast to 1.2.6 (#139246)

* Make default dim level configurable in Lutron (#137127)

* Set PARALLEL_UPDATES in all Minecraft Server platforms (#139259)

* Bump aiowebostv to 0.7.1 (#139244)

* Consistently capitalize "Velbus" brand name, camel-case "VelServ" (#139257)

* Bump cached-ipaddress to 0.9.2 (#139245)

* Make Sonarr component's units translatable (#139254)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Bump stookwijzer to 1.5.8 (#139258)

* Bump Velbus to bronze quality scale (#139256)

* Add Homee number platform (#138962)

Co-authored-by: Joostlek <joostlek@outlook.com>

* Fix yolink lock v2 state update (#138710)

* Set Minecraft Server quality scale to silver (#139265)

* Add OpenWeatherMap Minute forecast action (#128799)

* Fix Ezviz entity state for cameras that are offline (#136003)

* Use proper camel-case for "VeSync", fix sentence-casing in title (#139252)

Just a quick follow-up PR to fix these two spelling mistakes.

* Add request made by `rest_command` to debug log (#139266)

* Create repair for configured unavailable backup agents (#137382)

* Create repair for configured not loaded agents

* Rework to repair issue

* Extract logic to config function

* Update test

* Handle empty agend ids config update

* Address review comment

* Update tests

* Address comment

* Improve description of `openweathermap.get_minute_forecast` action (#139267)

* Use right import in ezviz (#139272)

* Change touchline dependency to pytouchline_extended (#136362)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Rename description field to notes in Habitica action (#139271)

* Add support for effects in Govee lights (#137846)

* Add Burbank Water and Power (BWP) virtual integration (#139027)

* Update adext to 0.4.4 (#139151)

* Add sound mode support to Onkyo (#133531)

* Use new python library for picnic component (#139111)

* Bump securetar to 2025.2.1 (#139273)

* Fix race in async_get_integrations with multiple calls when an integration is not found (#139270)

* Fix race in async_get_integrations with multiple calls when an integration is not found

* Fix race in async_get_integrations with multiple calls when an integration is not found

* Fix race in async_get_integrations with multiple calls when an integration is not found

* tweaks

* tweaks

* tweaks

* restore lost comment

* tweak test

* comment cache

* improve test

* improve comment

* Bump python-overseerr to 0.7.1 (#139263)

Co-authored-by: Shay Levy <levyshay1@gmail.com>

* Add coordinator to SMHI (#139052)

* Add coordinator to SMHI

* Remove not needed logging

* docstrings

* Make Radarr unit translation lowercase (#139261)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Add common state translation string for charging and discharging (#139074)

add common state translation string for charging and discharging

* Add test fixture ignore_translations_for_mock_domains (#139235)

* Add test fixture ignore_translations_for_mock_domains

* Fix fixture

* Avoid unnecessary attempt to get integration

* Really fix fixture

* Add forgotten parameter

* Address review comment

* Fix grammar in loader comments (#139276)

https://github.com/home-assistant/core/pull/139270#discussion_r1970315129

* Bump aiohomeconnect to 0.15.0 (#139277)

* Add current cavity temperature sensor to Home Connect (#139282)

* Bump anthropic to 0.47.2 (#139283)

* Adjust recorder validate_statistics handler (#139229)

* Fix re-connect logic in Apple TV integration (#139289)

* Revert "Bump stookwijzer==1.5.8" (#139287)

* Add option to ESPHome to subscribe to logs (#139073)

* Remove not used constants in smhi (#139298)

* Bump `aioshelly` to version `13.0.0` (#139294)

* Bump aioshelly to version 13.0.0

* MODEL_BLU_GATEWAY_GEN3 -> MODEL_BLU_GATEWAY_G3

* Remove timeout from vscode test launch configuration (#139288)

* Add missing Home Connect context at event listener registration for appliance options (#139292)

* Add missing context at event listener registration for appliance options

* Add tests

* Sort common translation strings (#139300)

sort common strings

* Add album artist media browser category to Squeezebox (#139210)

* Bump aioesphomeapi to 29.2.0 (#139309)

* Bump actions/download-artifact from 4.1.8 to 4.1.9 (#139317)

Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.1.8 to 4.1.9.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4.1.8...v4.1.9)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump home-assistant/builder from 2024.08.2 to 2025.02.0 (#139316)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Adjust remote ESPHome log subscription level on logging change (#139308)

* Fix homeassistant/expose_entity/list (#138872)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Bump `accuweather` to version `4.1.0` (#139320)

* Bump ZHA to 0.0.50 (#139318)

* Bump pytechnove to 2.0.0 (#139314)

* Update python-smarttub dependency to 0.0.39 (#139313)

* Fix anthropic blocking call (#139299)

* Bump pybotvac to 0.0.26 (#139330)

* Bump stookwijzer==1.6.0 (#139332)

* Improve error message when failing to create backups (#139262)

* Improve error message when failing to create backups

* Check for expected error message in tests

* Add translations and icon for Twinkly select entity (#139336)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Bump recommended ESPHome Bluetooth proxy version to 2025.2.1 (#139196)

* Add default_db_url flag to WS command recorder/info (#139333)

* Improve action descriptions of LIFX integration (#139329)

Improve action description of lifx integration

- fix sentence-casing on two action names
- change "Kelvin" unit name to proper uppercase
- reference 'Theme' and 'Palette' fields by their friendly names for matching translations
- change paint_theme action description to match HA style

* Bump Music Assistant client to 1.1.1 (#139331)

* Refactor SmartThings (#137940)

* Add keys initiate_flow and entry_type to data entry translations (#138882)

* Add support for swing horizontal mode for mqtt climate (#139303)

* Add support for swing horizontal mode for mqtt climate

* Fix import

* Add entity translations to SmartThings (#139342)

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* fix

* fix

* Add AC tests

* Add thermostat tests

* Add cover tests

* Add device tests

* Add light tests

* Add rest of the tests

* Add oauth

* Add oauth tests

* Add oauth tests

* Add oauth tests

* Add oauth tests

* Bump version

* Add rest of the tests

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Iterate over entities instead

* use set

* use const

* uncomment

* fix handler

* Fix device info

* Fix device info

* Fix lib

* Fix lib

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Add fake fan

* Fix

* Add entity translations to SmartThings

* Fix

* Improve logging for selected options in Onkyo (#139279)

Different error for not selected option

* Change no fixtures comment in SmartThings (#139344)

* Set options for carbon monoxide detector sensor in SmartThings (#139346)

* Improve calculating supported features in template light (#139339)

* Update frontend to 20250226.0 (#139340)

Co-authored-by: Robert Resch <robert@resch.dev>

* Use particulate matter device class in SmartThings (#139351)

Use particule matter device class in SmartThings

* Set options for dishwasher job state sensor in SmartThings (#139349)

* Set options for dishwasher machine state sensor in SmartThings (#139347)

* Set options for dishwasher machine state sensor in SmartThings

* Fix

* Set options for alarm sensor in SmartThings (#139345)

* Set options for alarm sensor in SmartThings

* Set options for alarm sensor in SmartThings

* Fix

* Fix variable scopes in scripts (#138883)

Co-authored-by: Erik <erik@montnemery.com>

* Add translatable states to SmartThings media source input (#139353)

Add translatable states to media source input

* Add translatable states to SmartThings media playback (#139354)

Add translatable states to media playback

* Add translatable states to oven mode in SmartThings (#139356)

* Add translatable states to oven job state in SmartThings (#139361)

* Add translatable states to oven machine state (#139358)

* Add translatable states to robot cleaner movement in SmartThings (#139363)

* Add translatable states to robot cleaner cleaning mode in SmartThings (#139362)

* Add translatable states to robot cleaner cleaning mode in SmartThings

* Update homeassistant/components/smartthings/strings.json

* Update homeassistant/components/smartthings/strings.json

---------

Co-authored-by: Josef Zweck <josef@zweck.dev>

* Add translatable states to washer machine state in SmartThings (#139366)

* Add translatable states to smoke detector in SmartThings (#139365)

* Add translatable states to robot cleaner turbo mode in SmartThings (#139364)

* Add translatable states to washer job state in SmartThings (#139368)

* Add translatable states to washer job state in SmartThings

* fix

* Update homeassistant/components/smartthings/sensor.py

* Improve Home Connect oven cavity temperature sensor (#139355)

* Improve oven cavity temperature translation

* Fetch cavity temperature unit

* Handle generic Home Connect error

* Improve test clarity

* Add translatable states to dryer machine state in Smartthings (#139369)

* Add translatable states to dryer job state in SmartThings (#139370)

* Add translatable states to washer job state in SmartThings

* Add translatable states to dryer job state in Smartthings

* fix

* fix

* Don't create entities for disabled capabilities in SmartThings (#139343)

* Don't create entities for disabled capabilities in SmartThings

* Fix

* fix

* fix

* Fix typo in SmartThing string (#139373)

* Bump version to 2025.3.0b0

* Bump stookwijzer==1.6.1 (#139380)

* Bump ZHA to 0.0.51 (#139383)

* Bump ZHA to 0.0.51

* Fix unit tests not accounting for primary entities

* Bump intents to 2025.2.26 (#139387)

* Fix fetch options error for Home connect (#139392)

* Handle errors when obtaining options definitions

* Don't fetch program options if the program key is unknown

* Test to ensure that available program endpoint is not called on unknown program

* Bump onedrive to 0.0.12 (#139410)

* Bump onedrive to 0.0.12

* Add alternative name

* Bump pysmartthings to 2.0.0 (#139418)

* Bump pysmartthings to 2.0.0

* Fix

* Fix

* Fix

* Fix

* Bump habluetooth to 3.24.1 (#139420)

* Fix conversation agent fallback (#139421)

* Add diagnostics to SmartThings (#139423)

* Bump bleak-esphome to 2.8.0 (#139426)

* Bump reolink-aio to 0.12.1 (#139427)

* Fix Music Assistant media player entity features (#139428)

* Fix Music Assistant supported media player features

* Update supported features when player config changes

* Add tests

* Update frontend to 20250227.0 (#139437)

* Bump version to 2025.3.0b1

* Bump weatherflow4py to 1.3.1 (#135529)

* version bump of dep

* update requirements

* Add new mediatypes to Music Assistant integration (#139338)

* Bump Music Assistant client to 1.1.0

* Add some casts to help mypy

* Add handling of the new media types in Music Assistant

* mypy cleanup

* lint

* update snapshot

* Adjust tests

---------

Co-authored-by: Franck Nijhof <git@frenck.dev>

* Move climate intent to homeassistant integration (#139371)

* Move climate intent to homeassistant integration

* Move get temperature intent to intent integration

* Clean up old test

* Bump aiohomeconnect to 0.15.1 (#139445)

* Fix SmartThings diagnostics (#139447)

* Bump pysmartthings to 2.0.1 (#139454)

* Change webdav namespace to absolut URI (#139456)

* Change webdav namespace to absolut URI

* Add const file

* Improve onedrive migration (#139458)

* Bump pysmartthings to 2.1.0 (#139460)

* Only lowercase SmartThings media input source if we have it (#139468)

* Set SmartThings suggested display precision (#139470)

* Fix Gemini Schema validation for #139416 (#139478)

Fixed Schema validation for issue #139477

* Fail recorder.backup.async_pre_backup if Home Assistant is not running (#139491)

Fail recorder.backup.async_pre_backup if hass is not running

* Fix shift state in Teslemetry (#139505)

* Fix shift state

* Different fix

* Improve error handling in CoreBackupReaderWriter (#139508)

* Add diagnostics to onedrive (#139516)

* Add diagnostics to onedrive

* redact PII

* add raw data

* Make the Tuya backend library compatible with the newer paho mqtt client. (#139518)

* Make the Tuya backend library compatible with the newer paho mqtt client.

* Improve classnames and docstrings

* Suppress unsupported event 'EVT_USP_RpsPowerDeniedByPsuOverload' by bumping aiounifi to v83 (#139519)

Bump aiounifi to v83

* Don't split wheels builder anymore (#139522)

* Bump yt-dlp to 2025.02.19 (#139526)

* Update frontend to 20250228.0 (#139531)

* Bump version to 2025.3.0b2

* Add missing 'state_class' attribute for Growatt plant sensors (#132145)

* Add missing 'state_class' attribute for Growatt plant sensors

* Update total.py

* Update total.py 'TOTAL_INCREASING'

* Update total.py "maximum_output" -> 'TOTAL_INCREASING'

* Update homeassistant/components/growatt_server/sensor/total.py

---------

Co-authored-by: Franck Nijhof <frenck@frenck.nl>

* Bump env_canada to 0.8.0 (#138237)

* Bump env_canada to 0.8.0

* Fix requirements*.txt

* Grepped more

---------

Co-authored-by: Franck Nijhof <git@frenck.dev>

* Fix Nederlandse Spoorwegen to ignore trains in the past (#138331)

* Update NS integration to show first next train instead of just the first.

* Handle no first or next trip.

* Remove debug statement.

* Remove seconds and revert back to minutes.

* Make use of dt_util.now().

* Fix issue with next train if no first train.

* Use multiple indexed group-by queries to get start time states for MySQL (#138786)

* tweaks

* mysql

* mysql

* Update homeassistant/components/recorder/history/modern.py

* Update homeassistant/components/recorder/history/modern.py

* Update homeassistant/components/recorder/const.py

* Update homeassistant/components/recorder/statistics.py

* Apply suggestions from code review

* mysql

* mysql

* cover

* make sure db is fully init on old schema

* fixes

* fixes

* coverage

* coverage

* coverage

* s/slow_dependant_subquery/slow_dependent_subquery/g

* reword

* comment that callers are responsible for staying under the limit

* comment that callers are responsible for staying under the limit

* switch to kwargs

* reduce branching complexity

* split stats query

* preen

* split tests

* split tests

* Specify recorder as after dependency in sql integration (#139037)

* Specify recorder as after dependency in sql integration

* Remove hassfest exception

---------

Co-authored-by: J. Nick Koston <nick@koston.org>

* Handle IPv6 URLs in devolo Home Network (#139191)

* Handle IPv6 URLs in devolo Home Network

* Use yarl

* Fix bug in derivative sensor when source sensor's state is constant (#139230)

Previously, when the source sensor's state remains constant, the derivative
sensor repeats its latest value indefinitely.

This patch fixes this bug by consuming the state_reported event and updating
the sensor's output even when the source sensor doesn't change its state.

* Ensure Hue bridge is added first to the device registry (#139438)

* Fix update data for multiple Gree devices (#139469)

fix sync date for multiple devices

do not use handler for explicit update devices as internal communication lib do not provide which device is updated
use ha update loop

copy data object to prevent rewrite data from internal lib

allow more time to process response before log warning about long wait for response and make log message more clear

* Use last event as color mode in SmartThings (#139473)

* Use last event as color mode in SmartThings

* Use last event as color mode in SmartThings

* Fix

* Set SmartThings delta energy to Total (#139474)

* Fix alert not respecting can_acknowledge setting (#139483)

* fix(alert): check can_ack prior to acking

* fix(alert): add test for when can_acknowledge=False

* fix(alert): warn on can_ack blocking an ack

* Raise error when trying to acknowledge alert with can_acknowledge set to False

* Rewrite can_ack check as guard

Co-authored-by: Franck Nijhof <frenck@frenck.nl>

* Make can_ack service error msg human readable because it will show up in the UI

* format with ruff

* Make pytest aware of service error when acking an unackable alert

---------

Co-authored-by: Franck Nijhof <frenck@frenck.nl>

* Bump pysmartthings to 2.2.0 (#139539)

* Remove orphan devices on startup in SmartThings (#139541)

* Bump PySwitchBot to 0.56.1 (#139544)

changelog: https://github.com/sblibs/pySwitchbot/compare/0.56.0...0.56.1

* Bump pysmartthings to 2.3.0 (#139546)

* Improve SmartThings OCF device info (#139547)

* Add SmartThings Viper device info (#139548)

* Revert polling changes to HomeKit Controller (#139550)

This reverts #116200

We changed the polling logic to avoid polling if all chars are marked as watchable
to avoid crashing the firmware on a very limited set of devices as it was
more in line with what iOS does. In the end, the user ended up replacing
the device in #116143 because it turned out to be unreliable in other
ways. The vendor has since issued a firmware update that may resolve
the problem with all of these devices.

In practice it turns out many more devices
report that chars are evented and never send events. After a few months
of data and reports the trade-off does not seem worth it since
users are having to set up manual polling on a wide range of
devices. The amount of devices with evented chars that do not
actually send state vastly exceeds the number of devices that
might crash if they are polled too often so restore the previous
behavior

fixes #138561
fixes #100331
fixes #124529
fixes #123456
fixes #130763
fixes #124099
fixes #124916
fixes #135434
fixes #125273
fixes #124099
fixes #119617

* Bump pysmartthings to 2.4.0 (#139564)

* Bump Tesla Fleet API to v0.9.12 (#139565)

* bump

* Update manifest.json

* Fix versions

* remove tesla_bluetooth

* Remove mistake

* Bump aiowebdav2 to 0.3.1 (#139567)

* Validate scopes in SmartThings config flow (#139569)

* Only determine SmartThings swing modes if we support it (#139571)

Only determine swing modes if we support it

* Don't require not needed scopes in SmartThings (#139576)

* Don't require not needed scopes

* Don't require not needed scopes

* Homee: fix watchdog icon (#139577)

fix watchdog icon

* Bump aiohomekit to 3.2.8 (#139579)

changelog: https://github.com/Jc2k/aiohomekit/compare/3.2.7...3.2.8

* Fix duplicate unique id issue in Sensibo (#139582)

* Fix duplicate unique id issue in Sensibo

* Fixes

* Mods

* Improve field descriptions of `zha.permit` action (#139584)

Make the field descriptions of `source_ieee` and `install_code` UI-friendly by cross-referencing them using their friendly names to allow matching translations.

Better explain the alternative of using the `qr_code` field by adding that this contains both the IEEE address and the Install code of the joining device.

* Fix - Allow brightness only light MQTT json light to be set up using the `brightness` flag or via  `supported_color_modes` (#139585)

* Fix - Allow brightness only light MQTT json light to be set up using the `brightness` flag or via  `supported_color_modes`

* Improve comment

* Fix Manufacturer naming for Squeezelite model name for Squeezebox (#139586)

Squeezelite Manufacturer Fix

* Bump deebot-client to 12.3.1 (#139598)

* Fix handling of NaN float values for current humidity in ESPHome (#139600)

fixes #131837

* Bump aioshelly to 13.1.0 (#139601)

Co-authored-by: Franck Nijhof <git@frenck.dev>

* Bump inkbird-ble to 0.7.1 (#139603)

changelog: https://github.com/Bluetooth-Devices/inkbird-ble/compare/v0.7.0...v0.7.1

* Fix body text of imap message not available in custom event data template (#139609)

* Fix arm vacation mode showing as armed away in elkm1 (#139613)

Add native arm vacation mode support to elkm1

Vacation mode is currently implemented as a custom
service which will be deprecated in a future PR.

Note that the custom service was added long before
HA had a native vacation mode which was added
in #45980

* Still request scopes in SmartThings (#139626)

Still request scopes

* Bump pysmartthings to 2.4.1 (#139627)

* Bump version to 2025.3.0b3

* Fix unique identifiers where multiple IKEA Tradfri gateways are in use (#136060)

* Create unique identifiers where multiple gateways are in use

Resolving issue https://github.com/home-assistant/core/issues/134497

* Added migration function to __init__.py

Added migration function to execute upon initialisation, to:
a) remove the erroneously-added config)_entry added to the device (gateway B gets added as a config_entry to a device associated to gateway A), and
b) swap out the non-unique identifiers for genuinely unique identifiers.

* Added tests to simulate migration from bad data scenario (i.e. explicitly executing migrate_entity_unique_ids() from __init__.py)

* Ammendments suggested in first review

* Changes after second review

* Rewrite of test_migrate_config_entry_and_identifiers after feedback

* Converted migrate function into major version, updated tests

* Finalised variable naming convention per feedback, added test to validate config entry migrated to v2

* Hopefully final changes for cosmetic / comment stucture

* Further code-coverage in test_migrate_config_entry_and_identifiers()

* Minor test corrections

* Added test for non-tradfri identifiers

* Fix vicare exception for specific ventilation device type (#138343)

* fix for exception for specific ventilation device type + tests

* fix for exception for specific ventilation device type + tests

* New Testset just for fan

* update test_sensor.ambr

* Prevent zero interval in Calendar get_events service (#139378)

* Prevent zero interval in Calendar get_events service

* Fix holiday calendar tests

* Remove redundant entity_id

* Use translation for exception

* Replace check with voluptuous validator

* Revert strings.xml

* Fix Homee brightness sensors reporting in percent (#139409)

* fix brigtness sensor having percent as unit.

* add test for percent-brightness-sensor

* remove valve position and update tests

* Removed test, because covered by Snapshots

* fix review comments

* move device calss to init.

* fix test

* fix review comments

* add battery sensor back to test fixture

* fix

* Fix ability to remove orphan device in Music Assistant integration (#139431)

* Fix ability to remove orphan device in Music Assistant integration

* Add test

* Remove orphaned device entries at startup as well

* adjust mocked client

* Fix broken link in ESPHome BLE repair (#139639)

ESPHome always uses .0 in the URL for the changelog,
and we never had a patch version in the stable
BLE version field so we need to switch it to
.0 for the URL.

* Fix scope comparison in SmartThings (#139652)

* Avoid duplicate chat log content (#139679)

* Add additional roborock debug logging (#139680)

* Improve failure handling and logging for invalid map responses (#139681)

* Abort SmartThings flow if default_config is not enabled (#139700)

* Abort SmartThings flow if default_config is not enabled

* Abort SmartThings flow if default_config is not enabled

* Abort SmartThings flow if default_config is not enabled

* Bump ESPHome stable BLE version to 2025.2.2 (#139704)

ensure proxies have https://github.com/esphome/esphome/pull/8328
so they do not reboot themselves if disconnecting takes
too long

* Bump holidays to 0.68 (#139711)

* Bump aiowebostv to 0.7.2 (#139712)

* Bump sense-energy to 0.13.6 (#139714)

changes: https://github.com/scottbonline/sense/releases/tag/0.13.6

* Add nest translation string for `already_in_progress` (#139727)

* Bump google-nest-sdm to 7.1.4 (#139728)

* Delete refresh after a non-breaking error at event stream at Home Connect (#139740)

* Delete refresh after non-breaking error

And improve how many time does it take to retry to open stream

* Update tests

* Bump version to 2025.3.0b4

* Bump aiohomeconnect to 0.16.2 (#139750)

* Add Apollo Automation virtual integration (#139751)

Co-authored-by: Robert Resch <robert@resch.dev>

* Fix incorrect weather state returned by HKO (#139757)

* Fix incorrect weather state

* Clean up unused import

---------

Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: Franck Nijhof <git@frenck.dev>

* Bump pysmartthings to 2.5.0 (#139758)

* Bump pysmartthings to 2.5.0

* Bump pysmartthings to 2.5.0

* Fix home connect available (#139760)

* Fix home connect available

* Extend and clarify test

* Do not change connected state on stream interrupted

* Bump nexia to 2.1.1 (#139772)

changelog: https://github.com/bdraco/nexia/compare/2.0.9...2.1.1

fixes #133368

* Bump version to 2025.3.0b5

* Bump aiowebostv to 0.7.3 (#139788)

* Drop BETA postfix from Matter integration's title (#139816)

Drop BETA postfix from Matter title

Now that the whole Matter stack of Home Assistant is officially certified, we can drop the beta flag.

* Split the energy and data retrieval in WeHeat (#139211)

* Split the energy and data logs

* Make sure that pump_info name is set to device name, bump weheat

* Adding config entry

* Fixed circular import

* parallelisation of awaits

* Update homeassistant/components/weheat/binary_sensor.py

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Fix undefined weheatdata

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Bump version to 2025.3.0b6

* Update frontend to 20250305.0 (#139829)

* Bump version to 2025.3.0b7

* Get temperature data appropriate for hass.config.unit in LG ThinQ (#137626)

* Get temperature data appropriate for hass.config.unit

* Modify temperature_unit for init

* Modify unit's map

* Fix ruff error

---------

Co-authored-by: yunseon.park <yunseon.park@lge.com>

* Bump nexia to 2.2.1 (#139786)

* Bump nexia to 2.2.0

changelog: https://github.com/bdraco/nexia/compare/2.1.1...2.2.0

* Apply suggestions from code review

* Revert "Add scene support to roborock (#137203)" (#139840)

This reverts commit 379bf10675.

* Bump aioecowitt to 2025.3.1 (#139841)

* Bump aioecowitt to 2025.3.1

* Bump aioecowitt to 2025.3.1

* Bump onedrive-personal-sdk to 0.0.13 (#139846)

* Bump intents to 2025.3.5 (#139851)

Co-authored-by: Franck Nijhof <git@frenck.dev>

* Bump version to 2025.3.0b8

* Bump version to 2025.3.0

* Fix no disabled capabilities in SmartThings (#139860)

Fix no disabled capabilities

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: cdnninja <jaydenaphillips@gmail.com>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Tristan <tristan.steele@gmail.com>
Co-authored-by: peteS-UK <64092177+peteS-UK@users.noreply.github.com>
Co-authored-by: Josef Zweck <josef@zweck.dev>
Co-authored-by: Manu <4445816+tr4nt0r@users.noreply.github.com>
Co-authored-by: J. Diego Rodríguez Royo <jdrr1998@hotmail.com>
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
Co-authored-by: Noah Husby <32528627+noahhusby@users.noreply.github.com>
Co-authored-by: Dan Raper <me@danr.uk>
Co-authored-by: Jan-Philipp Benecke <jan-philipp@bnck.me>
Co-authored-by: Markus Adrario <Mozilla@adrario.de>
Co-authored-by: Andre Lengwenus <alengwenus@gmail.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Norbert Rittel <norbert@rittel.de>
Co-authored-by: LG-ThinQ-Integration <LG-ThinQ-Integration@lge.com>
Co-authored-by: yunseon.park <yunseon.park@lge.com>
Co-authored-by: Maikel Punie <maikel.punie@gmail.com>
Co-authored-by: Dan Bishop <d@nbishop.uk>
Co-authored-by: elmurato <1382097+elmurato@users.noreply.github.com>
Co-authored-by: Robert Resch <robert@resch.dev>
Co-authored-by: Cameron Ring <cameron@cs.stanford.edu>
Co-authored-by: Shay Levy <levyshay1@gmail.com>
Co-authored-by: fwestenberg <47930023+fwestenberg@users.noreply.github.com>
Co-authored-by: Matrix <justin@yosmart.com>
Co-authored-by: Andrew <34544450+10100011@users.noreply.github.com>
Co-authored-by: Renier Moorcroft <66512715+RenierM26@users.noreply.github.com>
Co-authored-by: Peter Brøndum <34370407+brondum@users.noreply.github.com>
Co-authored-by: Galorhallen <12990764+Galorhallen@users.noreply.github.com>
Co-authored-by: tronikos <tronikos@users.noreply.github.com>
Co-authored-by: Paul Traina <pleasantone@users.noreply.github.com>
Co-authored-by: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com>
Co-authored-by: Noah Groß <me@codesalat.dev>
Co-authored-by: G Johansson <goran.johansson@shiftit.se>
Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>
Co-authored-by: Denis Shulyaka <Shulyaka@gmail.com>
Co-authored-by: Pierre Ståhl <pierre.staahl@gmail.com>
Co-authored-by: Maciej Bieniek <bieniu@users.noreply.github.com>
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: TheJulianJES <TheJulianJES@users.noreply.github.com>
Co-authored-by: Christophe Gagnier <Moustachauve@users.noreply.github.com>
Co-authored-by: Matt Zimmerman <mdz@users.noreply.github.com>
Co-authored-by: Ben Bridts <ben.bridts@gmail.com>
Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: puddly <32534428+puddly@users.noreply.github.com>
Co-authored-by: Michael Hansen <mike@rhasspy.org>
Co-authored-by: starkillerOG <starkiller.og@gmail.com>
Co-authored-by: Jeef <jeeftor@users.noreply.github.com>
Co-authored-by: Ivan Lopez Hernandez <ivan.lh.94@outlook.com>
Co-authored-by: Brett Adams <Bre77@users.noreply.github.com>
Co-authored-by: Robert Svensson <Kane610@users.noreply.github.com>
Co-authored-by: LaithBudairi <69572447+LaithBudairi@users.noreply.github.com>
Co-authored-by: M-A <maruel@gmail.com>
Co-authored-by: Martreides <8385298+Martreides@users.noreply.github.com>
Co-authored-by: Guido Schmitz <Shutgun@users.noreply.github.com>
Co-authored-by: Juan Grande <juan.grande@gmail.com>
Co-authored-by: Filip Agh <filip11agh@gmail.com>
Co-authored-by: StaleLoafOfBread <45444205+StaleLoafOfBread@users.noreply.github.com>
Co-authored-by: cs12ag <70966712+cs12ag@users.noreply.github.com>
Co-authored-by: Niklas Neesen <n.neesen@me.com>
Co-authored-by: Allen Porter <allen@thebends.org>
Co-authored-by: Anthony Hou <anthony.tr.hou@gmail.com>
Co-authored-by: SteveDiks <126147459+SteveDiks@users.noreply.github.com>
2025-03-05 20:00:41 +01:00
Joost Lekkerkerker
98e317dd55 Fix no disabled capabilities in SmartThings (#139860)
Fix no disabled capabilities
2025-03-05 17:42:31 +00:00
Franck Nijhof
ed088aa72f Bump version to 2025.3.0 2025-03-05 17:39:36 +00:00
Franck Nijhof
51162320cb Bump version to 2025.3.0b8 2025-03-05 17:25:33 +00:00
Michael Hansen
b88eab8ba3 Bump intents to 2025.3.5 (#139851)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2025-03-05 17:23:04 +00:00
Josef Zweck
6c080ee650 Bump onedrive-personal-sdk to 0.0.13 (#139846) 2025-03-05 17:22:17 +00:00
Joost Lekkerkerker
8056b0df2b Bump aioecowitt to 2025.3.1 (#139841)
* Bump aioecowitt to 2025.3.1

* Bump aioecowitt to 2025.3.1
2025-03-05 17:22:14 +00:00
Allen Porter
3f94b7a61c Revert "Add scene support to roborock (#137203)" (#139840)
This reverts commit 379bf10675.
2025-03-05 17:22:11 +00:00
J. Nick Koston
1484e46317 Bump nexia to 2.2.1 (#139786)
* Bump nexia to 2.2.0

changelog: https://github.com/bdraco/nexia/compare/2.1.1...2.2.0

* Apply suggestions from code review
2025-03-05 17:22:08 +00:00
LG-ThinQ-Integration
2812c8a993 Get temperature data appropriate for hass.config.unit in LG ThinQ (#137626)
* Get temperature data appropriate for hass.config.unit

* Modify temperature_unit for init

* Modify unit's map

* Fix ruff error

---------

Co-authored-by: yunseon.park <yunseon.park@lge.com>
2025-03-05 17:22:04 +00:00
Franck Nijhof
5043e2ad10 Bump version to 2025.3.0b7 2025-03-05 11:01:06 +00:00
Bram Kragten
2c2fd76270 Update frontend to 20250305.0 (#139829) 2025-03-05 11:00:56 +00:00
Franck Nijhof
7001f8daaf Bump version to 2025.3.0b6 2025-03-05 09:39:26 +00:00
SteveDiks
b41fc932c5 Split the energy and data retrieval in WeHeat (#139211)
* Split the energy and data logs

* Make sure that pump_info name is set to device name, bump weheat

* Adding config entry

* Fixed circular import

* parallelisation of awaits

* Update homeassistant/components/weheat/binary_sensor.py

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Fix undefined weheatdata

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2025-03-05 09:39:13 +00:00
Marcel van der Veldt
0872243297 Drop BETA postfix from Matter integration's title (#139816)
Drop BETA postfix from Matter title

Now that the whole Matter stack of Home Assistant is officially certified, we can drop the beta flag.
2025-03-05 08:44:44 +00:00
Shay Levy
bba889975a Bump aiowebostv to 0.7.3 (#139788) 2025-03-05 08:44:39 +00:00
36 changed files with 335 additions and 410 deletions

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/conversation",
"integration_type": "system",
"quality_scale": "internal",
"requirements": ["hassil==2.2.3", "home-assistant-intents==2025.2.26"]
"requirements": ["hassil==2.2.3", "home-assistant-intents==2025.3.5"]
}

View File

@@ -6,5 +6,5 @@
"dependencies": ["webhook"],
"documentation": "https://www.home-assistant.io/integrations/ecowitt",
"iot_class": "local_push",
"requirements": ["aioecowitt==2024.2.1"]
"requirements": ["aioecowitt==2025.3.1"]
}

View File

@@ -20,5 +20,5 @@
"documentation": "https://www.home-assistant.io/integrations/frontend",
"integration_type": "system",
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20250228.0"]
"requirements": ["home-assistant-frontend==20250305.0"]
}

View File

@@ -110,7 +110,9 @@ class ThinQClimateEntity(ThinQEntity, ClimateEntity):
self._attr_hvac_modes = [HVACMode.OFF]
self._attr_hvac_mode = HVACMode.OFF
self._attr_preset_modes = []
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_temperature_unit = (
self._get_unit_of_measurement(self.data.unit) or UnitOfTemperature.CELSIUS
)
self._requested_hvac_mode: str | None = None
# Set up HVAC modes.
@@ -182,6 +184,11 @@ class ThinQClimateEntity(ThinQEntity, ClimateEntity):
self._attr_target_temperature_high = self.data.target_temp_high
self._attr_target_temperature_low = self.data.target_temp_low
# Update unit.
self._attr_temperature_unit = (
self._get_unit_of_measurement(self.data.unit) or UnitOfTemperature.CELSIUS
)
_LOGGER.debug(
"[%s:%s] update status: c:%s, t:%s, l:%s, h:%s, hvac:%s, unit:%s, step:%s",
self.coordinator.device_name,

View File

@@ -3,6 +3,8 @@
from datetime import timedelta
from typing import Final
from homeassistant.const import UnitOfTemperature
# Config flow
DOMAIN = "lg_thinq"
COMPANY = "LGE"
@@ -18,3 +20,10 @@ MQTT_SUBSCRIPTION_INTERVAL: Final = timedelta(days=1)
# MQTT: Message types
DEVICE_PUSH_MESSAGE: Final = "DEVICE_PUSH"
DEVICE_STATUS_MESSAGE: Final = "DEVICE_STATUS"
# Unit conversion map
DEVICE_UNIT_TO_HA: dict[str, str] = {
"F": UnitOfTemperature.FAHRENHEIT,
"C": UnitOfTemperature.CELSIUS,
}
REVERSE_DEVICE_UNIT_TO_HA = {v: k for k, v in DEVICE_UNIT_TO_HA.items()}

View File

@@ -2,19 +2,21 @@
from __future__ import annotations
from collections.abc import Mapping
import logging
from typing import TYPE_CHECKING, Any
from thinqconnect import ThinQAPIException
from thinqconnect.integration import HABridge
from homeassistant.core import HomeAssistant
from homeassistant.const import EVENT_CORE_CONFIG_UPDATE
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
if TYPE_CHECKING:
from . import ThinqConfigEntry
from .const import DOMAIN
from .const import DOMAIN, REVERSE_DEVICE_UNIT_TO_HA
_LOGGER = logging.getLogger(__name__)
@@ -54,6 +56,40 @@ class DeviceDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
f"{self.device_id}_{self.sub_id}" if self.sub_id else self.device_id
)
# Set your preferred temperature unit. This will allow us to retrieve
# temperature values from the API in a converted value corresponding to
# preferred unit.
self._update_preferred_temperature_unit()
# Add a callback to handle core config update.
self.unit_system: str | None = None
self.hass.bus.async_listen(
event_type=EVENT_CORE_CONFIG_UPDATE,
listener=self._handle_update_config,
event_filter=self.async_config_update_filter,
)
async def _handle_update_config(self, _: Event) -> None:
"""Handle update core config."""
self._update_preferred_temperature_unit()
await self.async_refresh()
@callback
def async_config_update_filter(self, event_data: Mapping[str, Any]) -> bool:
"""Filter out unwanted events."""
if (unit_system := event_data.get("unit_system")) != self.unit_system:
self.unit_system = unit_system
return True
return False
def _update_preferred_temperature_unit(self) -> None:
"""Update preferred temperature unit."""
self.api.set_preferred_temperature_unit(
REVERSE_DEVICE_UNIT_TO_HA.get(self.hass.config.units.temperature_unit)
)
async def _async_update_data(self) -> dict[str, Any]:
"""Request to the server to update the status from full response data."""
try:

View File

@@ -10,25 +10,19 @@ from thinqconnect import ThinQAPIException
from thinqconnect.devices.const import Location
from thinqconnect.integration import PropertyState
from homeassistant.const import UnitOfTemperature
from homeassistant.core import callback
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import COMPANY, DOMAIN
from .const import COMPANY, DEVICE_UNIT_TO_HA, DOMAIN
from .coordinator import DeviceDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
EMPTY_STATE = PropertyState()
UNIT_CONVERSION_MAP: dict[str, str] = {
"F": UnitOfTemperature.FAHRENHEIT,
"C": UnitOfTemperature.CELSIUS,
}
class ThinQEntity(CoordinatorEntity[DeviceDataUpdateCoordinator]):
"""The base implementation of all lg thinq entities."""
@@ -75,7 +69,7 @@ class ThinQEntity(CoordinatorEntity[DeviceDataUpdateCoordinator]):
if unit is None:
return None
return UNIT_CONVERSION_MAP.get(unit)
return DEVICE_UNIT_TO_HA.get(unit)
def _update_status(self) -> None:
"""Update status itself.

View File

@@ -1,6 +1,6 @@
{
"domain": "matter",
"name": "Matter (BETA)",
"name": "Matter",
"after_dependencies": ["hassio"],
"codeowners": ["@home-assistant/matter"],
"config_flow": true,

View File

@@ -12,5 +12,5 @@
"documentation": "https://www.home-assistant.io/integrations/nexia",
"iot_class": "cloud_polling",
"loggers": ["nexia"],
"requirements": ["nexia==2.1.1"]
"requirements": ["nexia==2.2.1"]
}

View File

@@ -9,5 +9,5 @@
"iot_class": "cloud_polling",
"loggers": ["onedrive_personal_sdk"],
"quality_scale": "platinum",
"requirements": ["onedrive-personal-sdk==0.0.12"]
"requirements": ["onedrive-personal-sdk==0.0.13"]
}

View File

@@ -83,13 +83,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: RoborockConfigEntry) ->
# Get a Coordinator if the device is available or if we have connected to the device before
coordinators = await asyncio.gather(
*build_setup_functions(
hass,
entry,
device_map,
user_data,
product_info,
home_data.rooms,
api_client,
hass, entry, device_map, user_data, product_info, home_data.rooms
),
return_exceptions=True,
)
@@ -141,7 +135,6 @@ def build_setup_functions(
user_data: UserData,
product_info: dict[str, HomeDataProduct],
home_data_rooms: list[HomeDataRoom],
api_client: RoborockApiClient,
) -> list[
Coroutine[
Any,
@@ -158,7 +151,6 @@ def build_setup_functions(
device,
product_info[device.product_id],
home_data_rooms,
api_client,
)
for device in device_map.values()
]
@@ -171,12 +163,11 @@ async def setup_device(
device: HomeDataDevice,
product_info: HomeDataProduct,
home_data_rooms: list[HomeDataRoom],
api_client: RoborockApiClient,
) -> RoborockDataUpdateCoordinator | RoborockDataUpdateCoordinatorA01 | None:
"""Set up a coordinator for a given device."""
if device.pv == "1.0":
return await setup_device_v1(
hass, entry, user_data, device, product_info, home_data_rooms, api_client
hass, entry, user_data, device, product_info, home_data_rooms
)
if device.pv == "A01":
return await setup_device_a01(hass, entry, user_data, device, product_info)
@@ -196,7 +187,6 @@ async def setup_device_v1(
device: HomeDataDevice,
product_info: HomeDataProduct,
home_data_rooms: list[HomeDataRoom],
api_client: RoborockApiClient,
) -> RoborockDataUpdateCoordinator | None:
"""Set up a device Coordinator."""
mqtt_client = await hass.async_add_executor_job(
@@ -218,15 +208,7 @@ async def setup_device_v1(
await mqtt_client.async_release()
raise
coordinator = RoborockDataUpdateCoordinator(
hass,
entry,
device,
networking,
product_info,
mqtt_client,
home_data_rooms,
api_client,
user_data,
hass, entry, device, networking, product_info, mqtt_client, home_data_rooms
)
try:
await coordinator.async_config_entry_first_refresh()

View File

@@ -36,7 +36,6 @@ PLATFORMS = [
Platform.BUTTON,
Platform.IMAGE,
Platform.NUMBER,
Platform.SCENE,
Platform.SELECT,
Platform.SENSOR,
Platform.SWITCH,

View File

@@ -10,26 +10,17 @@ import logging
from propcache.api import cached_property
from roborock import HomeDataRoom
from roborock.code_mappings import RoborockCategory
from roborock.containers import (
DeviceData,
HomeDataDevice,
HomeDataProduct,
HomeDataScene,
NetworkInfo,
UserData,
)
from roborock.containers import DeviceData, HomeDataDevice, HomeDataProduct, NetworkInfo
from roborock.exceptions import RoborockException
from roborock.roborock_message import RoborockDyadDataProtocol, RoborockZeoProtocol
from roborock.roborock_typing import DeviceProp
from roborock.version_1_apis.roborock_local_client_v1 import RoborockLocalClientV1
from roborock.version_1_apis.roborock_mqtt_client_v1 import RoborockMqttClientV1
from roborock.version_a01_apis import RoborockClientA01
from roborock.web_api import RoborockApiClient
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_CONNECTIONS
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.typing import StateType
@@ -76,8 +67,6 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
product_info: HomeDataProduct,
cloud_api: RoborockMqttClientV1,
home_data_rooms: list[HomeDataRoom],
api_client: RoborockApiClient,
user_data: UserData,
) -> None:
"""Initialize."""
super().__init__(
@@ -100,7 +89,7 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
self.cloud_api = cloud_api
self.device_info = DeviceInfo(
name=self.roborock_device_info.device.name,
identifiers={(DOMAIN, self.duid)},
identifiers={(DOMAIN, self.roborock_device_info.device.duid)},
manufacturer="Roborock",
model=self.roborock_device_info.product.model,
model_id=self.roborock_device_info.product.model,
@@ -114,10 +103,8 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
self.maps: dict[int, RoborockMapInfo] = {}
self._home_data_rooms = {str(room.id): room.name for room in home_data_rooms}
self.map_storage = RoborockMapStorage(
hass, self.config_entry.entry_id, self.duid_slug
hass, self.config_entry.entry_id, slugify(self.duid)
)
self._user_data = user_data
self._api_client = api_client
async def _async_setup(self) -> None:
"""Set up the coordinator."""
@@ -147,7 +134,7 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
except RoborockException:
_LOGGER.warning(
"Using the cloud API for device %s. This is not recommended as it can lead to rate limiting. We recommend making your vacuum accessible by your Home Assistant instance",
self.duid,
self.roborock_device_info.device.duid,
)
await self.api.async_disconnect()
# We use the cloud api if the local api fails to connect.
@@ -207,34 +194,6 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
for room in room_mapping or ()
}
async def get_scenes(self) -> list[HomeDataScene]:
"""Get scenes."""
try:
return await self._api_client.get_scenes(self._user_data, self.duid)
except RoborockException as err:
_LOGGER.error("Failed to get scenes %s", err)
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="command_failed",
translation_placeholders={
"command": "get_scenes",
},
) from err
async def execute_scene(self, scene_id: int) -> None:
"""Execute scene."""
try:
await self._api_client.execute_scene(self._user_data, scene_id)
except RoborockException as err:
_LOGGER.error("Failed to execute scene %s %s", scene_id, err)
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="command_failed",
translation_placeholders={
"command": "execute_scene",
},
) from err
@cached_property
def duid(self) -> str:
"""Get the unique id of the device as specified by Roborock."""

View File

@@ -1,64 +0,0 @@
"""Support for Roborock scene."""
from __future__ import annotations
import asyncio
from typing import Any
from homeassistant.components.scene import Scene as SceneEntity
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import RoborockConfigEntry
from .coordinator import RoborockDataUpdateCoordinator
from .entity import RoborockEntity
async def async_setup_entry(
hass: HomeAssistant,
config_entry: RoborockConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up scene platform."""
scene_lists = await asyncio.gather(
*[coordinator.get_scenes() for coordinator in config_entry.runtime_data.v1],
)
async_add_entities(
RoborockSceneEntity(
coordinator,
EntityDescription(
key=str(scene.id),
name=scene.name,
),
)
for coordinator, scenes in zip(
config_entry.runtime_data.v1, scene_lists, strict=True
)
for scene in scenes
)
class RoborockSceneEntity(RoborockEntity, SceneEntity):
"""A class to define Roborock scene entities."""
entity_description: EntityDescription
def __init__(
self,
coordinator: RoborockDataUpdateCoordinator,
entity_description: EntityDescription,
) -> None:
"""Create a scene entity."""
super().__init__(
f"{entity_description.key}_{coordinator.duid_slug}",
coordinator.device_info,
coordinator.api,
)
self._scene_id = int(entity_description.key)
self._coordinator = coordinator
self.entity_description = entity_description
async def async_activate(self, **kwargs: Any) -> None:
"""Activate the scene."""
await self._coordinator.execute_scene(self._scene_id)

View File

@@ -174,11 +174,12 @@ def process_status(
list[Capability | str],
disabled_capabilities_capability[Attribute.DISABLED_CAPABILITIES].value,
)
for capability in disabled_capabilities:
# We still need to make sure the climate entity can work without this capability
if (
capability in main_component
and capability != Capability.DEMAND_RESPONSE_LOAD_CONTROL
):
del main_component[capability]
if disabled_capabilities is not None:
for capability in disabled_capabilities:
# We still need to make sure the climate entity can work without this capability
if (
capability in main_component
and capability != Capability.DEMAND_RESPONSE_LOAD_CONTROL
):
del main_component[capability]
return status

View File

@@ -6,7 +6,7 @@
"documentation": "https://www.home-assistant.io/integrations/webostv",
"iot_class": "local_push",
"loggers": ["aiowebostv"],
"requirements": ["aiowebostv==0.7.2"],
"requirements": ["aiowebostv==0.7.3"],
"ssdp": [
{
"st": "urn:lge-com:service:webos-second-screen:1"

View File

@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
from http import HTTPStatus
import aiohttp
@@ -18,7 +19,13 @@ from homeassistant.helpers.config_entry_oauth2_flow import (
)
from .const import API_URL, LOGGER
from .coordinator import WeheatConfigEntry, WeheatDataUpdateCoordinator
from .coordinator import (
HeatPumpInfo,
WeheatConfigEntry,
WeheatData,
WeheatDataUpdateCoordinator,
WeheatEnergyUpdateCoordinator,
)
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
@@ -52,14 +59,38 @@ async def async_setup_entry(hass: HomeAssistant, entry: WeheatConfigEntry) -> bo
except UnauthorizedException as error:
raise ConfigEntryAuthFailed from error
nr_of_pumps = len(discovered_heat_pumps)
for pump_info in discovered_heat_pumps:
LOGGER.debug("Adding %s", pump_info)
# for each pump, add a coordinator
new_coordinator = WeheatDataUpdateCoordinator(hass, entry, session, pump_info)
# for each pump, add the coordinators
await new_coordinator.async_config_entry_first_refresh()
new_heat_pump = HeatPumpInfo(pump_info)
new_data_coordinator = WeheatDataUpdateCoordinator(
hass, entry, session, pump_info, nr_of_pumps
)
new_energy_coordinator = WeheatEnergyUpdateCoordinator(
hass, entry, session, pump_info
)
entry.runtime_data.append(new_coordinator)
entry.runtime_data.append(
WeheatData(
heat_pump_info=new_heat_pump,
data_coordinator=new_data_coordinator,
energy_coordinator=new_energy_coordinator,
)
)
await asyncio.gather(
*[
data.data_coordinator.async_config_entry_first_refresh()
for data in entry.runtime_data
],
*[
data.energy_coordinator.async_config_entry_first_refresh()
for data in entry.runtime_data
],
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

View File

@@ -14,7 +14,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from .coordinator import WeheatConfigEntry, WeheatDataUpdateCoordinator
from .coordinator import HeatPumpInfo, WeheatConfigEntry, WeheatDataUpdateCoordinator
from .entity import WeheatEntity
# Coordinator is used to centralize the data updates
@@ -68,10 +68,14 @@ async def async_setup_entry(
) -> None:
"""Set up the sensors for weheat heat pump."""
entities = [
WeheatHeatPumpBinarySensor(coordinator, entity_description)
WeheatHeatPumpBinarySensor(
weheatdata.heat_pump_info,
weheatdata.data_coordinator,
entity_description,
)
for weheatdata in entry.runtime_data
for entity_description in BINARY_SENSORS
for coordinator in entry.runtime_data
if entity_description.value_fn(coordinator.data) is not None
if entity_description.value_fn(weheatdata.data_coordinator.data) is not None
]
async_add_entities(entities)
@@ -80,20 +84,21 @@ async def async_setup_entry(
class WeheatHeatPumpBinarySensor(WeheatEntity, BinarySensorEntity):
"""Defines a Weheat heat pump binary sensor."""
heat_pump_info: HeatPumpInfo
coordinator: WeheatDataUpdateCoordinator
entity_description: WeHeatBinarySensorEntityDescription
def __init__(
self,
heat_pump_info: HeatPumpInfo,
coordinator: WeheatDataUpdateCoordinator,
entity_description: WeHeatBinarySensorEntityDescription,
) -> None:
"""Pass coordinator to CoordinatorEntity."""
super().__init__(coordinator)
super().__init__(heat_pump_info, coordinator)
self.entity_description = entity_description
self._attr_unique_id = f"{coordinator.heatpump_id}_{entity_description.key}"
self._attr_unique_id = f"{heat_pump_info.heatpump_id}_{entity_description.key}"
@property
def is_on(self) -> bool | None:

View File

@@ -17,7 +17,8 @@ API_URL = "https://api.weheat.nl"
OAUTH2_SCOPES = ["openid", "offline_access"]
UPDATE_INTERVAL = 30
LOG_UPDATE_INTERVAL = 120
ENERGY_UPDATE_INTERVAL = 1800
LOGGER: Logger = getLogger(__package__)

View File

@@ -1,5 +1,6 @@
"""Define a custom coordinator for the Weheat heatpump integration."""
from dataclasses import dataclass
from datetime import timedelta
from weheat.abstractions.discovery import HeatPumpDiscovery
@@ -10,6 +11,7 @@ from weheat.exceptions import (
ForbiddenException,
NotFoundException,
ServiceException,
TooManyRequestsException,
UnauthorizedException,
)
@@ -21,7 +23,9 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import API_URL, DOMAIN, LOGGER, UPDATE_INTERVAL
from .const import API_URL, DOMAIN, ENERGY_UPDATE_INTERVAL, LOG_UPDATE_INTERVAL, LOGGER
type WeheatConfigEntry = ConfigEntry[list[WeheatData]]
EXCEPTIONS = (
ServiceException,
@@ -29,9 +33,43 @@ EXCEPTIONS = (
ForbiddenException,
BadRequestException,
ApiException,
TooManyRequestsException,
)
type WeheatConfigEntry = ConfigEntry[list[WeheatDataUpdateCoordinator]]
class HeatPumpInfo(HeatPumpDiscovery.HeatPumpInfo):
"""Heat pump info with additional properties."""
def __init__(self, pump_info: HeatPumpDiscovery.HeatPumpInfo) -> None:
"""Initialize the HeatPump object with the provided pump information.
Args:
pump_info (HeatPumpDiscovery.HeatPumpInfo): An object containing the heat pump's discovery information, including:
- uuid (str): Unique identifier for the heat pump.
- uuid (str): Unique identifier for the heat pump.
- device_name (str): Name of the heat pump device.
- model (str): Model of the heat pump.
- sn (str): Serial number of the heat pump.
- has_dhw (bool): Indicates if the heat pump has domestic hot water functionality.
"""
super().__init__(
pump_info.uuid,
pump_info.device_name,
pump_info.model,
pump_info.sn,
pump_info.has_dhw,
)
@property
def readable_name(self) -> str | None:
"""Return the readable name of the heat pump."""
return self.device_name if self.device_name else self.model
@property
def heatpump_id(self) -> str:
"""Return the heat pump id."""
return self.uuid
class WeheatDataUpdateCoordinator(DataUpdateCoordinator[HeatPump]):
@@ -45,45 +83,28 @@ class WeheatDataUpdateCoordinator(DataUpdateCoordinator[HeatPump]):
config_entry: WeheatConfigEntry,
session: OAuth2Session,
heat_pump: HeatPumpDiscovery.HeatPumpInfo,
nr_of_heat_pumps: int,
) -> None:
"""Initialize the data coordinator."""
super().__init__(
hass,
logger=LOGGER,
config_entry=config_entry,
logger=LOGGER,
name=DOMAIN,
update_interval=timedelta(seconds=UPDATE_INTERVAL),
update_interval=timedelta(seconds=LOG_UPDATE_INTERVAL * nr_of_heat_pumps),
)
self.heat_pump_info = heat_pump
self._heat_pump_data = HeatPump(
API_URL, heat_pump.uuid, async_get_clientsession(hass)
)
self.session = session
@property
def heatpump_id(self) -> str:
"""Return the heat pump id."""
return self.heat_pump_info.uuid
@property
def readable_name(self) -> str | None:
"""Return the readable name of the heat pump."""
if self.heat_pump_info.name:
return self.heat_pump_info.name
return self.heat_pump_info.model
@property
def model(self) -> str:
"""Return the model of the heat pump."""
return self.heat_pump_info.model
async def _async_update_data(self) -> HeatPump:
"""Fetch data from the API."""
await self.session.async_ensure_token_valid()
try:
await self._heat_pump_data.async_get_status(
await self._heat_pump_data.async_get_logs(
self.session.token[CONF_ACCESS_TOKEN]
)
except UnauthorizedException as error:
@@ -92,3 +113,54 @@ class WeheatDataUpdateCoordinator(DataUpdateCoordinator[HeatPump]):
raise UpdateFailed(error) from error
return self._heat_pump_data
class WeheatEnergyUpdateCoordinator(DataUpdateCoordinator[HeatPump]):
"""A custom Energy coordinator for the Weheat heatpump integration."""
config_entry: WeheatConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: WeheatConfigEntry,
session: OAuth2Session,
heat_pump: HeatPumpDiscovery.HeatPumpInfo,
) -> None:
"""Initialize the data coordinator."""
super().__init__(
hass,
config_entry=config_entry,
logger=LOGGER,
name=DOMAIN,
update_interval=timedelta(seconds=ENERGY_UPDATE_INTERVAL),
)
self._heat_pump_data = HeatPump(
API_URL, heat_pump.uuid, async_get_clientsession(hass)
)
self.session = session
async def _async_update_data(self) -> HeatPump:
"""Fetch data from the API."""
await self.session.async_ensure_token_valid()
try:
await self._heat_pump_data.async_get_energy(
self.session.token[CONF_ACCESS_TOKEN]
)
except UnauthorizedException as error:
raise ConfigEntryAuthFailed from error
except EXCEPTIONS as error:
raise UpdateFailed(error) from error
return self._heat_pump_data
@dataclass
class WeheatData:
"""Data for the Weheat integration."""
heat_pump_info: HeatPumpInfo
data_coordinator: WeheatDataUpdateCoordinator
energy_coordinator: WeheatEnergyUpdateCoordinator

View File

@@ -3,25 +3,30 @@
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import HeatPumpInfo
from .const import DOMAIN, MANUFACTURER
from .coordinator import WeheatDataUpdateCoordinator
from .coordinator import WeheatDataUpdateCoordinator, WeheatEnergyUpdateCoordinator
class WeheatEntity(CoordinatorEntity[WeheatDataUpdateCoordinator]):
class WeheatEntity[
_WeheatEntityT: WeheatDataUpdateCoordinator | WeheatEnergyUpdateCoordinator
](CoordinatorEntity[_WeheatEntityT]):
"""Defines a base Weheat entity."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: WeheatDataUpdateCoordinator,
heat_pump_info: HeatPumpInfo,
coordinator: _WeheatEntityT,
) -> None:
"""Initialize the Weheat entity."""
super().__init__(coordinator)
self.heat_pump_info = heat_pump_info
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, coordinator.heatpump_id)},
name=coordinator.readable_name,
identifiers={(DOMAIN, heat_pump_info.heatpump_id)},
name=heat_pump_info.readable_name,
manufacturer=MANUFACTURER,
model=coordinator.model,
model=heat_pump_info.model,
)

View File

@@ -6,5 +6,5 @@
"dependencies": ["application_credentials"],
"documentation": "https://www.home-assistant.io/integrations/weheat",
"iot_class": "cloud_polling",
"requirements": ["weheat==2025.2.22"]
"requirements": ["weheat==2025.2.26"]
}

View File

@@ -27,7 +27,12 @@ from .const import (
DISPLAY_PRECISION_WATER_TEMP,
DISPLAY_PRECISION_WATTS,
)
from .coordinator import WeheatConfigEntry, WeheatDataUpdateCoordinator
from .coordinator import (
HeatPumpInfo,
WeheatConfigEntry,
WeheatDataUpdateCoordinator,
WeheatEnergyUpdateCoordinator,
)
from .entity import WeheatEntity
# Coordinator is used to centralize the data updates
@@ -142,22 +147,6 @@ SENSORS = [
else None
),
),
WeHeatSensorEntityDescription(
translation_key="electricity_used",
key="electricity_used",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda status: status.energy_total,
),
WeHeatSensorEntityDescription(
translation_key="energy_output",
key="energy_output",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda status: status.energy_output,
),
WeHeatSensorEntityDescription(
translation_key="compressor_rpm",
key="compressor_rpm",
@@ -174,7 +163,6 @@ SENSORS = [
),
]
DHW_SENSORS = [
WeHeatSensorEntityDescription(
translation_key="dhw_top_temperature",
@@ -196,6 +184,25 @@ DHW_SENSORS = [
),
]
ENERGY_SENSORS = [
WeHeatSensorEntityDescription(
translation_key="electricity_used",
key="electricity_used",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda status: status.energy_total,
),
WeHeatSensorEntityDescription(
translation_key="energy_output",
key="energy_output",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda status: status.energy_output,
),
]
async def async_setup_entry(
hass: HomeAssistant,
@@ -203,17 +210,39 @@ async def async_setup_entry(
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the sensors for weheat heat pump."""
entities = [
WeheatHeatPumpSensor(coordinator, entity_description)
for entity_description in SENSORS
for coordinator in entry.runtime_data
]
entities.extend(
WeheatHeatPumpSensor(coordinator, entity_description)
for entity_description in DHW_SENSORS
for coordinator in entry.runtime_data
if coordinator.heat_pump_info.has_dhw
)
entities: list[WeheatHeatPumpSensor] = []
for weheatdata in entry.runtime_data:
entities.extend(
WeheatHeatPumpSensor(
weheatdata.heat_pump_info,
weheatdata.data_coordinator,
entity_description,
)
for entity_description in SENSORS
if entity_description.value_fn(weheatdata.data_coordinator.data) is not None
)
if weheatdata.heat_pump_info.has_dhw:
entities.extend(
WeheatHeatPumpSensor(
weheatdata.heat_pump_info,
weheatdata.data_coordinator,
entity_description,
)
for entity_description in DHW_SENSORS
if entity_description.value_fn(weheatdata.data_coordinator.data)
is not None
)
entities.extend(
WeheatHeatPumpSensor(
weheatdata.heat_pump_info,
weheatdata.energy_coordinator,
entity_description,
)
for entity_description in ENERGY_SENSORS
if entity_description.value_fn(weheatdata.energy_coordinator.data)
is not None
)
async_add_entities(entities)
@@ -221,20 +250,21 @@ async def async_setup_entry(
class WeheatHeatPumpSensor(WeheatEntity, SensorEntity):
"""Defines a Weheat heat pump sensor."""
coordinator: WeheatDataUpdateCoordinator
heat_pump_info: HeatPumpInfo
coordinator: WeheatDataUpdateCoordinator | WeheatEnergyUpdateCoordinator
entity_description: WeHeatSensorEntityDescription
def __init__(
self,
coordinator: WeheatDataUpdateCoordinator,
heat_pump_info: HeatPumpInfo,
coordinator: WeheatDataUpdateCoordinator | WeheatEnergyUpdateCoordinator,
entity_description: WeHeatSensorEntityDescription,
) -> None:
"""Pass coordinator to CoordinatorEntity."""
super().__init__(coordinator)
super().__init__(heat_pump_info, coordinator)
self.entity_description = entity_description
self._attr_unique_id = f"{coordinator.heatpump_id}_{entity_description.key}"
self._attr_unique_id = f"{heat_pump_info.heatpump_id}_{entity_description.key}"
@property
def native_value(self) -> StateType:

View File

@@ -25,7 +25,7 @@ if TYPE_CHECKING:
APPLICATION_NAME: Final = "HomeAssistant"
MAJOR_VERSION: Final = 2025
MINOR_VERSION: Final = 3
PATCH_VERSION: Final = "0b5"
PATCH_VERSION: Final = "0"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 0)

View File

@@ -3640,7 +3640,7 @@
"iot_class": "cloud_push"
},
"matter": {
"name": "Matter (BETA)",
"name": "Matter",
"integration_type": "hub",
"config_flow": true,
"iot_class": "local_push"

View File

@@ -37,8 +37,8 @@ habluetooth==3.24.1
hass-nabucasa==0.92.0
hassil==2.2.3
home-assistant-bluetooth==1.13.1
home-assistant-frontend==20250228.0
home-assistant-intents==2025.2.26
home-assistant-frontend==20250305.0
home-assistant-intents==2025.3.5
httpx==0.28.1
ifaddr==0.2.0
Jinja2==3.1.5

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "homeassistant"
version = "2025.3.0b5"
version = "2025.3.0"
license = {text = "Apache-2.0"}
description = "Open-source home automation platform running on Python 3."
readme = "README.rst"

14
requirements_all.txt generated
View File

@@ -234,7 +234,7 @@ aioeafm==0.1.2
aioeagle==1.1.0
# homeassistant.components.ecowitt
aioecowitt==2024.2.1
aioecowitt==2025.3.1
# homeassistant.components.co2signal
aioelectricitymaps==0.4.0
@@ -425,7 +425,7 @@ aiowatttime==0.1.1
aiowebdav2==0.3.1
# homeassistant.components.webostv
aiowebostv==0.7.2
aiowebostv==0.7.3
# homeassistant.components.withings
aiowithings==3.1.6
@@ -1152,10 +1152,10 @@ hole==0.8.0
holidays==0.68
# homeassistant.components.frontend
home-assistant-frontend==20250228.0
home-assistant-frontend==20250305.0
# homeassistant.components.conversation
home-assistant-intents==2025.2.26
home-assistant-intents==2025.3.5
# homeassistant.components.homematicip_cloud
homematicip==1.1.7
@@ -1483,7 +1483,7 @@ nettigo-air-monitor==4.0.0
neurio==0.3.1
# homeassistant.components.nexia
nexia==2.1.1
nexia==2.2.1
# homeassistant.components.nextcloud
nextcloudmonitor==1.5.1
@@ -1565,7 +1565,7 @@ omnilogic==0.4.5
ondilo==0.5.0
# homeassistant.components.onedrive
onedrive-personal-sdk==0.0.12
onedrive-personal-sdk==0.0.13
# homeassistant.components.onvif
onvif-zeep-async==3.2.5
@@ -3058,7 +3058,7 @@ webio-api==0.1.11
webmin-xmlrpc==0.0.2
# homeassistant.components.weheat
weheat==2025.2.22
weheat==2025.2.26
# homeassistant.components.whirlpool
whirlpool-sixth-sense==0.18.12

View File

@@ -222,7 +222,7 @@ aioeafm==0.1.2
aioeagle==1.1.0
# homeassistant.components.ecowitt
aioecowitt==2024.2.1
aioecowitt==2025.3.1
# homeassistant.components.co2signal
aioelectricitymaps==0.4.0
@@ -407,7 +407,7 @@ aiowatttime==0.1.1
aiowebdav2==0.3.1
# homeassistant.components.webostv
aiowebostv==0.7.2
aiowebostv==0.7.3
# homeassistant.components.withings
aiowithings==3.1.6
@@ -981,10 +981,10 @@ hole==0.8.0
holidays==0.68
# homeassistant.components.frontend
home-assistant-frontend==20250228.0
home-assistant-frontend==20250305.0
# homeassistant.components.conversation
home-assistant-intents==2025.2.26
home-assistant-intents==2025.3.5
# homeassistant.components.homematicip_cloud
homematicip==1.1.7
@@ -1246,7 +1246,7 @@ netmap==0.7.0.2
nettigo-air-monitor==4.0.0
# homeassistant.components.nexia
nexia==2.1.1
nexia==2.2.1
# homeassistant.components.nextcloud
nextcloudmonitor==1.5.1
@@ -1313,7 +1313,7 @@ omnilogic==0.4.5
ondilo==0.5.0
# homeassistant.components.onedrive
onedrive-personal-sdk==0.0.12
onedrive-personal-sdk==0.0.13
# homeassistant.components.onvif
onvif-zeep-async==3.2.5
@@ -2462,7 +2462,7 @@ webio-api==0.1.11
webmin-xmlrpc==0.0.2
# homeassistant.components.weheat
weheat==2025.2.22
weheat==2025.2.26
# homeassistant.components.whirlpool
whirlpool-sixth-sense==0.18.12

View File

@@ -25,7 +25,7 @@ RUN --mount=from=ghcr.io/astral-sh/uv:0.6.1,source=/uv,target=/bin/uv \
-c /usr/src/homeassistant/homeassistant/package_constraints.txt \
-r /usr/src/homeassistant/requirements.txt \
stdlib-list==0.10.0 pipdeptree==2.25.0 tqdm==4.67.1 ruff==0.9.7 \
PyTurboJPEG==1.7.5 go2rtc-client==0.1.2 ha-ffmpeg==3.2.2 hassil==2.2.3 home-assistant-intents==2025.2.26 mutagen==1.47.0 pymicro-vad==1.0.1 pyspeex-noise==1.0.2
PyTurboJPEG==1.7.5 go2rtc-client==0.1.2 ha-ffmpeg==3.2.2 hassil==2.2.3 home-assistant-intents==2025.3.5 mutagen==1.47.0 pymicro-vad==1.0.1 pyspeex-noise==1.0.2
LABEL "name"="hassfest"
LABEL "maintainer"="Home Assistant <hello@home-assistant.io>"

View File

@@ -180,7 +180,6 @@ EXCEPTIONS = {
"PyMicroBot", # https://github.com/spycle/pyMicroBot/pull/3
"PySwitchmate", # https://github.com/Danielhiversen/pySwitchmate/pull/16
"PyXiaomiGateway", # https://github.com/Danielhiversen/PyXiaomiGateway/pull/201
"aioecowitt", # https://github.com/home-assistant-libs/aioecowitt/pull/180
"chacha20poly1305", # LGPL
"commentjson", # https://github.com/vaidik/commentjson/pull/55
"crownstone-cloud", # https://github.com/crownstone/crownstone-lib-python-cloud/pull/5

View File

@@ -15,8 +15,8 @@
<HVACMode.COOL: 'cool'>,
<HVACMode.DRY: 'dry'>,
]),
'max_temp': 30,
'min_temp': 18,
'max_temp': 86,
'min_temp': 64,
'preset_modes': list([
'air_clean',
]),
@@ -28,7 +28,7 @@
'on',
'off',
]),
'target_temp_step': 1,
'target_temp_step': 2,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -62,7 +62,7 @@
StateSnapshot({
'attributes': ReadOnlyDict({
'current_humidity': 40,
'current_temperature': 25,
'current_temperature': 77,
'fan_mode': 'mid',
'fan_modes': list([
'low',
@@ -75,8 +75,8 @@
<HVACMode.COOL: 'cool'>,
<HVACMode.DRY: 'dry'>,
]),
'max_temp': 30,
'min_temp': 18,
'max_temp': 86,
'min_temp': 64,
'preset_mode': None,
'preset_modes': list([
'air_clean',
@@ -94,8 +94,8 @@
]),
'target_temp_high': None,
'target_temp_low': None,
'target_temp_step': 1,
'temperature': 19,
'target_temp_step': 2,
'temperature': 66,
}),
'context': <ANY>,
'entity_id': 'climate.test_air_conditioner',

View File

@@ -5,7 +5,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from syrupy import SnapshotAssertion
from homeassistant.const import Platform
from homeassistant.const import Platform, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
@@ -23,6 +23,7 @@ async def test_all_entities(
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
hass.config.units.temperature_unit = UnitOfTemperature.FAHRENHEIT
with patch("homeassistant.components.lg_thinq.PLATFORMS", [Platform.CLIMATE]):
await setup_integration(hass, mock_config_entry)

View File

@@ -30,7 +30,6 @@ from .mock_data import (
MULTI_MAP_LIST,
NETWORK_INFO,
PROP,
SCENES,
USER_DATA,
USER_EMAIL,
)
@@ -68,24 +67,8 @@ class A01Mock(RoborockMqttClientA01):
return {prot: self.protocol_responses[prot] for prot in dyad_data_protocols}
@pytest.fixture(name="bypass_api_client_fixture")
def bypass_api_client_fixture() -> None:
"""Skip calls to the API client."""
with (
patch(
"homeassistant.components.roborock.RoborockApiClient.get_home_data_v2",
return_value=HOME_DATA,
),
patch(
"homeassistant.components.roborock.RoborockApiClient.get_scenes",
return_value=SCENES,
),
):
yield
@pytest.fixture(name="bypass_api_fixture")
def bypass_api_fixture(bypass_api_client_fixture: Any) -> None:
def bypass_api_fixture() -> None:
"""Skip calls to the API."""
with (
patch("homeassistant.components.roborock.RoborockMqttClientV1.async_connect"),
@@ -93,6 +76,10 @@ def bypass_api_fixture(bypass_api_client_fixture: Any) -> None:
patch(
"homeassistant.components.roborock.coordinator.RoborockMqttClientV1._send_command"
),
patch(
"homeassistant.components.roborock.RoborockApiClient.get_home_data_v2",
return_value=HOME_DATA,
),
patch(
"homeassistant.components.roborock.RoborockMqttClientV1.get_networking",
return_value=NETWORK_INFO,

View File

@@ -9,7 +9,6 @@ from roborock.containers import (
Consumable,
DnDTimer,
HomeData,
HomeDataScene,
MultiMapsList,
NetworkInfo,
S7Status,
@@ -1151,19 +1150,3 @@ MAP_DATA = MapData(0, 0)
MAP_DATA.image = ImageData(
100, 10, 10, 10, 10, ImageConfig(), Image.new("RGB", (1, 1)), lambda p: p
)
SCENES = [
HomeDataScene.from_dict(
{
"name": "sc1",
"id": 12,
},
),
HomeDataScene.from_dict(
{
"name": "sc2",
"id": 24,
},
),
]

View File

@@ -1,112 +0,0 @@
"""Test Roborock Scene platform."""
from unittest.mock import ANY, patch
import pytest
from roborock import RoborockException
from homeassistant.const import SERVICE_TURN_ON, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from tests.common import MockConfigEntry
@pytest.fixture
def bypass_api_client_get_scenes_fixture(bypass_api_fixture) -> None:
"""Fixture to raise when getting scenes."""
with (
patch(
"homeassistant.components.roborock.RoborockApiClient.get_scenes",
side_effect=RoborockException(),
),
):
yield
@pytest.mark.parametrize(
("entity_id"),
[
("scene.roborock_s7_maxv_sc1"),
("scene.roborock_s7_maxv_sc2"),
],
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_get_scenes_failure(
hass: HomeAssistant,
bypass_api_client_get_scenes_fixture,
setup_entry: MockConfigEntry,
entity_id: str,
) -> None:
"""Test that if scene retrieval fails, no entity is being created."""
# Ensure that the entity does not exist
assert hass.states.get(entity_id) is None
@pytest.fixture
def platforms() -> list[Platform]:
"""Fixture to set platforms used in the test."""
return [Platform.SCENE]
@pytest.mark.parametrize(
("entity_id", "scene_id"),
[
("scene.roborock_s7_maxv_sc1", 12),
("scene.roborock_s7_maxv_sc2", 24),
],
)
@pytest.mark.freeze_time("2023-10-30 08:50:00")
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_execute_success(
hass: HomeAssistant,
bypass_api_fixture,
setup_entry: MockConfigEntry,
entity_id: str,
scene_id: int,
) -> None:
"""Test activating the scene entities."""
with patch(
"homeassistant.components.roborock.RoborockApiClient.execute_scene"
) as mock_execute_scene:
await hass.services.async_call(
"scene",
SERVICE_TURN_ON,
blocking=True,
target={"entity_id": entity_id},
)
mock_execute_scene.assert_called_once_with(ANY, scene_id)
assert hass.states.get(entity_id).state == "2023-10-30T08:50:00+00:00"
@pytest.mark.parametrize(
("entity_id", "scene_id"),
[
("scene.roborock_s7_maxv_sc1", 12),
],
)
@pytest.mark.freeze_time("2023-10-30 08:50:00")
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_execute_failure(
hass: HomeAssistant,
bypass_api_fixture,
setup_entry: MockConfigEntry,
entity_id: str,
scene_id: int,
) -> None:
"""Test failure while activating the scene entity."""
with (
patch(
"homeassistant.components.roborock.RoborockApiClient.execute_scene",
side_effect=RoborockException,
) as mock_execute_scene,
pytest.raises(HomeAssistantError, match="Error while calling execute_scene"),
):
await hass.services.async_call(
"scene",
SERVICE_TURN_ON,
blocking=True,
target={"entity_id": entity_id},
)
mock_execute_scene.assert_called_once_with(ANY, scene_id)
assert hass.states.get(entity_id).state == "2023-10-30T08:50:00+00:00"