mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 17:27:52 +00:00
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 379bf106754dffd5c6c8cd8035a33597976cd866. * 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>
This commit is contained in:
commit
97cc3984c5
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -46,6 +46,8 @@
|
||||
- This PR fixes or closes issue: fixes #
|
||||
- This PR is related to issue:
|
||||
- Link to documentation pull request:
|
||||
- Link to developer documentation pull request:
|
||||
- Link to frontend pull request:
|
||||
|
||||
## Checklist
|
||||
<!--
|
||||
|
BIN
.github/assets/screenshot-integrations.png
vendored
BIN
.github/assets/screenshot-integrations.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 99 KiB |
100
.github/copilot-instructions.md
vendored
Normal file
100
.github/copilot-instructions.md
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
# Instructions for GitHub Copilot
|
||||
|
||||
This repository holds the core of Home Assistant, a Python 3 based home
|
||||
automation application.
|
||||
|
||||
- Python code must be compatible with Python 3.13
|
||||
- Use the newest Python language features if possible:
|
||||
- Pattern matching
|
||||
- Type hints
|
||||
- f-strings for string formatting over `%` or `.format()`
|
||||
- Dataclasses
|
||||
- Walrus operator
|
||||
- Code quality tools:
|
||||
- Formatting: Ruff
|
||||
- Linting: PyLint and Ruff
|
||||
- Type checking: MyPy
|
||||
- Testing: pytest with plain functions and fixtures
|
||||
- Inline code documentation:
|
||||
- File headers should be short and concise:
|
||||
```python
|
||||
"""Integration for Peblar EV chargers."""
|
||||
```
|
||||
- Every method and function needs a docstring:
|
||||
```python
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: PeblarConfigEntry) -> bool:
|
||||
"""Set up Peblar from a config entry."""
|
||||
...
|
||||
```
|
||||
- All code and comments and other text are written in American English
|
||||
- Follow existing code style patterns as much as possible
|
||||
- Core locations:
|
||||
- Shared constants: `homeassistant/const.py`, use them instead of hardcoding
|
||||
strings or creating duplicate integration constants.
|
||||
- Integration files:
|
||||
- Constants: `homeassistant/components/{domain}/const.py`
|
||||
- Models: `homeassistant/components/{domain}/models.py`
|
||||
- Coordinator: `homeassistant/components/{domain}/coordinator.py`
|
||||
- Config flow: `homeassistant/components/{domain}/config_flow.py`
|
||||
- Platform code: `homeassistant/components/{domain}/{platform}.py`
|
||||
- All external I/O operations must be async
|
||||
- Async patterns:
|
||||
- Avoid sleeping in loops
|
||||
- Avoid awaiting in loops, gather instead
|
||||
- No blocking calls
|
||||
- Polling:
|
||||
- Follow update coordinator pattern, when possible
|
||||
- Polling interval may not be configurable by the user
|
||||
- For local network polling, the minimum interval is 5 seconds
|
||||
- For cloud polling, the minimum interval is 60 seconds
|
||||
- Error handling:
|
||||
- Use specific exceptions from `homeassistant.exceptions`
|
||||
- Setup failures:
|
||||
- Temporary: Raise `ConfigEntryNotReady`
|
||||
- Permanent: Use `ConfigEntryError`
|
||||
- Logging:
|
||||
- Message format:
|
||||
- No periods at end
|
||||
- No integration names or domains (added automatically)
|
||||
- No sensitive data (keys, tokens, passwords), even when those are incorrect.
|
||||
- Be very restrictive on the use of logging info messages, use debug for
|
||||
anything which is not targeting the user.
|
||||
- Use lazy logging (no f-strings):
|
||||
```python
|
||||
_LOGGER.debug("This is a log message with %s", variable)
|
||||
```
|
||||
- Entities:
|
||||
- Ensure unique IDs for state persistence:
|
||||
- Unique IDs should not contain values that are subject to user or network change.
|
||||
- An ID needs to be unique per platform, not per integration.
|
||||
- The ID does not have to contain the integration domain or platform.
|
||||
- Acceptable examples:
|
||||
- Serial number of a device
|
||||
- MAC address of a device formatted using `homeassistant.helpers.device_registry.format_mac`
|
||||
Do not obtain the MAC address through arp cache of local network access,
|
||||
only use the MAC address provided by discovery or the device itself.
|
||||
- Unique identifier that is physically printed on the device or burned into an EEPROM
|
||||
- Not acceptable examples:
|
||||
- IP Address
|
||||
- Device name
|
||||
- Hostname
|
||||
- URL
|
||||
- Email address
|
||||
- Username
|
||||
- For entities that are setup by a config entry, the config entry ID
|
||||
can be used as a last resort if no other Unique ID is available.
|
||||
For example: `f"{entry.entry_id}-battery"`
|
||||
- If the state value is unknown, use `None`
|
||||
- Do not use the `unavailable` string as a state value,
|
||||
implement the `available()` property method instead
|
||||
- Do not use the `unknown` string as a state value, use `None` instead
|
||||
- Extra entity state attributes:
|
||||
- The keys of all state attributes should always be present
|
||||
- If the value is unknown, use `None`
|
||||
- Provide descriptive state attributes
|
||||
- Testing:
|
||||
- Test location: `tests/components/{domain}/`
|
||||
- Use pytest fixtures from `tests.common`
|
||||
- Mock external dependencies
|
||||
- Use snapshots for complex data
|
||||
- Follow existing test patterns
|
32
.github/workflows/builder.yml
vendored
32
.github/workflows/builder.yml
vendored
@ -69,7 +69,7 @@ jobs:
|
||||
run: find ./homeassistant/components/*/translations -name "*.json" | tar zcvf translations.tar.gz -T -
|
||||
|
||||
- name: Upload translations
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: translations
|
||||
path: translations.tar.gz
|
||||
@ -175,7 +175,7 @@ jobs:
|
||||
sed -i "s|pykrakenapi|# pykrakenapi|g" requirements_all.txt
|
||||
|
||||
- name: Download translations
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: translations
|
||||
|
||||
@ -197,7 +197,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build base image
|
||||
uses: home-assistant/builder@2024.08.2
|
||||
uses: home-assistant/builder@2025.02.0
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
@ -263,7 +263,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build base image
|
||||
uses: home-assistant/builder@2024.08.2
|
||||
uses: home-assistant/builder@2025.02.0
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
@ -324,7 +324,7 @@ jobs:
|
||||
uses: actions/checkout@v4.2.2
|
||||
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@v3.7.0
|
||||
uses: sigstore/cosign-installer@v3.8.1
|
||||
with:
|
||||
cosign-release: "v2.2.3"
|
||||
|
||||
@ -448,6 +448,9 @@ jobs:
|
||||
environment: ${{ needs.init.outputs.channel }}
|
||||
needs: ["init", "build_base"]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
@ -459,7 +462,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
- name: Download translations
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: translations
|
||||
|
||||
@ -473,16 +476,13 @@ jobs:
|
||||
run: |
|
||||
# Remove dist, build, and homeassistant.egg-info
|
||||
# when build locally for testing!
|
||||
pip install twine build
|
||||
pip install build
|
||||
python -m build
|
||||
|
||||
- name: Upload package
|
||||
shell: bash
|
||||
run: |
|
||||
export TWINE_USERNAME="__token__"
|
||||
export TWINE_PASSWORD="${{ secrets.TWINE_TOKEN }}"
|
||||
|
||||
twine upload dist/* --skip-existing
|
||||
- name: Upload package to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@v1.12.4
|
||||
with:
|
||||
skip-existing: true
|
||||
|
||||
hassfest-image:
|
||||
name: Build and test hassfest image
|
||||
@ -509,7 +509,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build Docker image
|
||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
|
||||
uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0
|
||||
with:
|
||||
context: . # So action will not pull the repository again
|
||||
file: ./script/hassfest/docker/Dockerfile
|
||||
@ -522,7 +522,7 @@ jobs:
|
||||
- name: Push Docker image
|
||||
if: needs.init.outputs.channel != 'dev' && needs.init.outputs.publish == 'true'
|
||||
id: push
|
||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
|
||||
uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0
|
||||
with:
|
||||
context: . # So action will not pull the repository again
|
||||
file: ./script/hassfest/docker/Dockerfile
|
||||
|
78
.github/workflows/ci.yaml
vendored
78
.github/workflows/ci.yaml
vendored
@ -40,7 +40,7 @@ env:
|
||||
CACHE_VERSION: 11
|
||||
UV_CACHE_VERSION: 1
|
||||
MYPY_CACHE_VERSION: 9
|
||||
HA_SHORT_VERSION: "2025.2"
|
||||
HA_SHORT_VERSION: "2025.3"
|
||||
DEFAULT_PYTHON: "3.13"
|
||||
ALL_PYTHON_VERSIONS: "['3.13']"
|
||||
# 10.3 is the oldest supported version
|
||||
@ -240,7 +240,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v4.2.0
|
||||
uses: actions/cache@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
key: >-
|
||||
@ -256,7 +256,7 @@ jobs:
|
||||
uv pip install "$(cat requirements_test.txt | grep pre-commit)"
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache@v4.2.0
|
||||
uses: actions/cache@v4.2.1
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
lookup-only: true
|
||||
@ -286,7 +286,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -295,7 +295,7 @@ jobs:
|
||||
needs.info.outputs.pre-commit_cache_key }}
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
fail-on-cache-miss: true
|
||||
@ -326,7 +326,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -335,7 +335,7 @@ jobs:
|
||||
needs.info.outputs.pre-commit_cache_key }}
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
fail-on-cache-miss: true
|
||||
@ -366,7 +366,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -375,7 +375,7 @@ jobs:
|
||||
needs.info.outputs.pre-commit_cache_key }}
|
||||
- name: Restore pre-commit environment from cache
|
||||
id: cache-precommit
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||
fail-on-cache-miss: true
|
||||
@ -482,7 +482,7 @@ jobs:
|
||||
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v4.2.0
|
||||
uses: actions/cache@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
key: >-
|
||||
@ -490,7 +490,7 @@ jobs:
|
||||
needs.info.outputs.python_cache_key }}
|
||||
- name: Restore uv wheel cache
|
||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||
uses: actions/cache@v4.2.0
|
||||
uses: actions/cache@v4.2.1
|
||||
with:
|
||||
path: ${{ env.UV_CACHE_DIR }}
|
||||
key: >-
|
||||
@ -537,7 +537,7 @@ jobs:
|
||||
python --version
|
||||
uv pip freeze >> pip_freeze.txt
|
||||
- name: Upload pip_freeze artifact
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: pip-freeze-${{ matrix.python-version }}
|
||||
path: pip_freeze.txt
|
||||
@ -578,7 +578,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -611,7 +611,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -649,7 +649,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -661,7 +661,7 @@ jobs:
|
||||
. venv/bin/activate
|
||||
python -m script.licenses extract --output-file=licenses-${{ matrix.python-version }}.json
|
||||
- name: Upload licenses
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: licenses-${{ github.run_number }}-${{ matrix.python-version }}
|
||||
path: licenses-${{ matrix.python-version }}.json
|
||||
@ -692,7 +692,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -739,7 +739,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -791,7 +791,7 @@ jobs:
|
||||
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
|
||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -799,7 +799,7 @@ jobs:
|
||||
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||
needs.info.outputs.python_cache_key }}
|
||||
- name: Restore mypy cache
|
||||
uses: actions/cache@v4.2.0
|
||||
uses: actions/cache@v4.2.1
|
||||
with:
|
||||
path: .mypy_cache
|
||||
key: >-
|
||||
@ -865,7 +865,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore base Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -877,7 +877,7 @@ jobs:
|
||||
. venv/bin/activate
|
||||
python -m script.split_tests ${{ needs.info.outputs.test_group_count }} tests
|
||||
- name: Upload pytest_buckets
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: pytest_buckets
|
||||
path: pytest_buckets.txt
|
||||
@ -929,7 +929,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -942,7 +942,7 @@ jobs:
|
||||
run: |
|
||||
echo "::add-matcher::.github/workflows/matchers/pytest-slow.json"
|
||||
- name: Download pytest_buckets
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: pytest_buckets
|
||||
- name: Compile English translations
|
||||
@ -975,18 +975,19 @@ jobs:
|
||||
${cov_params[@]} \
|
||||
-o console_output_style=count \
|
||||
-p no:sugar \
|
||||
--exclude-warning-annotations \
|
||||
$(sed -n "${{ matrix.group }},1p" pytest_buckets.txt) \
|
||||
2>&1 | tee pytest-${{ matrix.python-version }}-${{ matrix.group }}.txt
|
||||
- name: Upload pytest output
|
||||
if: success() || failure() && steps.pytest-full.conclusion == 'failure'
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{ matrix.group }}
|
||||
path: pytest-*.txt
|
||||
overwrite: true
|
||||
- name: Upload coverage artifact
|
||||
if: needs.info.outputs.skip_coverage != 'true'
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
|
||||
path: coverage.xml
|
||||
@ -1050,7 +1051,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -1098,6 +1099,7 @@ jobs:
|
||||
-o console_output_style=count \
|
||||
--durations=10 \
|
||||
-p no:sugar \
|
||||
--exclude-warning-annotations \
|
||||
--dburl=mysql://root:password@127.0.0.1/homeassistant-test \
|
||||
tests/components/history \
|
||||
tests/components/logbook \
|
||||
@ -1106,7 +1108,7 @@ jobs:
|
||||
2>&1 | tee pytest-${{ matrix.python-version }}-${mariadb}.txt
|
||||
- name: Upload pytest output
|
||||
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{
|
||||
steps.pytest-partial.outputs.mariadb }}
|
||||
@ -1114,7 +1116,7 @@ jobs:
|
||||
overwrite: true
|
||||
- name: Upload coverage artifact
|
||||
if: needs.info.outputs.skip_coverage != 'true'
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: coverage-${{ matrix.python-version }}-${{
|
||||
steps.pytest-partial.outputs.mariadb }}
|
||||
@ -1179,7 +1181,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -1228,6 +1230,7 @@ jobs:
|
||||
--durations=0 \
|
||||
--durations-min=10 \
|
||||
-p no:sugar \
|
||||
--exclude-warning-annotations \
|
||||
--dburl=postgresql://postgres:password@127.0.0.1/homeassistant-test \
|
||||
tests/components/history \
|
||||
tests/components/logbook \
|
||||
@ -1236,7 +1239,7 @@ jobs:
|
||||
2>&1 | tee pytest-${{ matrix.python-version }}-${postgresql}.txt
|
||||
- name: Upload pytest output
|
||||
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{
|
||||
steps.pytest-partial.outputs.postgresql }}
|
||||
@ -1244,7 +1247,7 @@ jobs:
|
||||
overwrite: true
|
||||
- name: Upload coverage artifact
|
||||
if: needs.info.outputs.skip_coverage != 'true'
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: coverage-${{ matrix.python-version }}-${{
|
||||
steps.pytest-partial.outputs.postgresql }}
|
||||
@ -1268,7 +1271,7 @@ jobs:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.2.2
|
||||
- name: Download all coverage artifacts
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
pattern: coverage-*
|
||||
- name: Upload coverage to Codecov
|
||||
@ -1325,7 +1328,7 @@ jobs:
|
||||
check-latest: true
|
||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.2.1
|
||||
with:
|
||||
path: venv
|
||||
fail-on-cache-miss: true
|
||||
@ -1374,18 +1377,19 @@ jobs:
|
||||
--durations=0 \
|
||||
--durations-min=1 \
|
||||
-p no:sugar \
|
||||
--exclude-warning-annotations \
|
||||
tests/components/${{ matrix.group }} \
|
||||
2>&1 | tee pytest-${{ matrix.python-version }}-${{ matrix.group }}.txt
|
||||
- name: Upload pytest output
|
||||
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{ matrix.group }}
|
||||
path: pytest-*.txt
|
||||
overwrite: true
|
||||
- name: Upload coverage artifact
|
||||
if: needs.info.outputs.skip_coverage != 'true'
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
|
||||
path: coverage.xml
|
||||
@ -1406,7 +1410,7 @@ jobs:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.2.2
|
||||
- name: Download all coverage artifacts
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
pattern: coverage-*
|
||||
- name: Upload coverage to Codecov
|
||||
|
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@ -24,11 +24,11 @@ jobs:
|
||||
uses: actions/checkout@v4.2.2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3.28.6
|
||||
uses: github/codeql-action/init@v3.28.10
|
||||
with:
|
||||
languages: python
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3.28.6
|
||||
uses: github/codeql-action/analyze@v3.28.10
|
||||
with:
|
||||
category: "/language:python"
|
||||
|
62
.github/workflows/wheels.yml
vendored
62
.github/workflows/wheels.yml
vendored
@ -91,7 +91,7 @@ jobs:
|
||||
) > build_constraints.txt
|
||||
|
||||
- name: Upload env_file
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: env_file
|
||||
path: ./.env_file
|
||||
@ -99,14 +99,14 @@ jobs:
|
||||
overwrite: true
|
||||
|
||||
- name: Upload build_constraints
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: build_constraints
|
||||
path: ./build_constraints.txt
|
||||
overwrite: true
|
||||
|
||||
- name: Upload requirements_diff
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: requirements_diff
|
||||
path: ./requirements_diff.txt
|
||||
@ -118,7 +118,7 @@ jobs:
|
||||
python -m script.gen_requirements_all ci
|
||||
|
||||
- name: Upload requirements_all_wheels
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: requirements_all_wheels
|
||||
path: ./requirements_all_wheels_*.txt
|
||||
@ -138,17 +138,17 @@ jobs:
|
||||
uses: actions/checkout@v4.2.2
|
||||
|
||||
- name: Download env_file
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: env_file
|
||||
|
||||
- name: Download build_constraints
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: build_constraints
|
||||
|
||||
- name: Download requirements_diff
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: requirements_diff
|
||||
|
||||
@ -187,22 +187,22 @@ jobs:
|
||||
uses: actions/checkout@v4.2.2
|
||||
|
||||
- name: Download env_file
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: env_file
|
||||
|
||||
- name: Download build_constraints
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: build_constraints
|
||||
|
||||
- name: Download requirements_diff
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: requirements_diff
|
||||
|
||||
- name: Download requirements_all_wheels
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
uses: actions/download-artifact@v4.1.9
|
||||
with:
|
||||
name: requirements_all_wheels
|
||||
|
||||
@ -218,15 +218,7 @@ jobs:
|
||||
sed -i "/uv/d" requirements.txt
|
||||
sed -i "/uv/d" requirements_diff.txt
|
||||
|
||||
- name: Split requirements all
|
||||
run: |
|
||||
# We split requirements all into multiple files.
|
||||
# This is to prevent the build from running out of memory when
|
||||
# resolving packages on 32-bits systems (like armhf, armv7).
|
||||
|
||||
split -l $(expr $(expr $(cat requirements_all.txt | wc -l) + 1) / 3) requirements_all_wheels_${{ matrix.arch }}.txt requirements_all.txt
|
||||
|
||||
- name: Build wheels (part 1)
|
||||
- name: Build wheels
|
||||
uses: home-assistant/wheels@2024.11.0
|
||||
with:
|
||||
abi: ${{ matrix.abi }}
|
||||
@ -238,32 +230,4 @@ jobs:
|
||||
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
|
||||
constraints: "homeassistant/package_constraints.txt"
|
||||
requirements-diff: "requirements_diff.txt"
|
||||
requirements: "requirements_all.txtaa"
|
||||
|
||||
- name: Build wheels (part 2)
|
||||
uses: home-assistant/wheels@2024.11.0
|
||||
with:
|
||||
abi: ${{ matrix.abi }}
|
||||
tag: musllinux_1_2
|
||||
arch: ${{ matrix.arch }}
|
||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||
env-file: true
|
||||
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev;nasm;zlib-ng-dev"
|
||||
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
|
||||
constraints: "homeassistant/package_constraints.txt"
|
||||
requirements-diff: "requirements_diff.txt"
|
||||
requirements: "requirements_all.txtab"
|
||||
|
||||
- name: Build wheels (part 3)
|
||||
uses: home-assistant/wheels@2024.11.0
|
||||
with:
|
||||
abi: ${{ matrix.abi }}
|
||||
tag: musllinux_1_2
|
||||
arch: ${{ matrix.arch }}
|
||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||
env-file: true
|
||||
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev;nasm;zlib-ng-dev"
|
||||
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
|
||||
constraints: "homeassistant/package_constraints.txt"
|
||||
requirements-diff: "requirements_diff.txt"
|
||||
requirements: "requirements_all.txtac"
|
||||
requirements: "requirements_all.txt"
|
||||
|
@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.9.1
|
||||
rev: v0.9.7
|
||||
hooks:
|
||||
- id: ruff
|
||||
args:
|
||||
@ -8,7 +8,7 @@ repos:
|
||||
- id: ruff-format
|
||||
files: ^((homeassistant|pylint|script|tests)/.+)?[^/]+\.(py|pyi)$
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.3.0
|
||||
rev: v2.4.1
|
||||
hooks:
|
||||
- id: codespell
|
||||
args:
|
||||
|
@ -103,6 +103,7 @@ homeassistant.components.auth.*
|
||||
homeassistant.components.automation.*
|
||||
homeassistant.components.awair.*
|
||||
homeassistant.components.axis.*
|
||||
homeassistant.components.azure_storage.*
|
||||
homeassistant.components.backup.*
|
||||
homeassistant.components.baf.*
|
||||
homeassistant.components.bang_olufsen.*
|
||||
@ -119,6 +120,7 @@ homeassistant.components.bluetooth_tracker.*
|
||||
homeassistant.components.bmw_connected_drive.*
|
||||
homeassistant.components.bond.*
|
||||
homeassistant.components.braviatv.*
|
||||
homeassistant.components.bring.*
|
||||
homeassistant.components.brother.*
|
||||
homeassistant.components.browser.*
|
||||
homeassistant.components.bryant_evolution.*
|
||||
@ -233,6 +235,7 @@ homeassistant.components.here_travel_time.*
|
||||
homeassistant.components.history.*
|
||||
homeassistant.components.history_stats.*
|
||||
homeassistant.components.holiday.*
|
||||
homeassistant.components.home_connect.*
|
||||
homeassistant.components.homeassistant.*
|
||||
homeassistant.components.homeassistant_alerts.*
|
||||
homeassistant.components.homeassistant_green.*
|
||||
@ -405,6 +408,7 @@ homeassistant.components.raspberry_pi.*
|
||||
homeassistant.components.rdw.*
|
||||
homeassistant.components.recollect_waste.*
|
||||
homeassistant.components.recorder.*
|
||||
homeassistant.components.remember_the_milk.*
|
||||
homeassistant.components.remote.*
|
||||
homeassistant.components.renault.*
|
||||
homeassistant.components.reolink.*
|
||||
@ -436,6 +440,7 @@ homeassistant.components.select.*
|
||||
homeassistant.components.sensibo.*
|
||||
homeassistant.components.sensirion_ble.*
|
||||
homeassistant.components.sensor.*
|
||||
homeassistant.components.sensorpush_cloud.*
|
||||
homeassistant.components.sensoterra.*
|
||||
homeassistant.components.senz.*
|
||||
homeassistant.components.sfr_box.*
|
||||
|
11
.vscode/launch.json
vendored
11
.vscode/launch.json
vendored
@ -38,10 +38,17 @@
|
||||
"module": "pytest",
|
||||
"justMyCode": false,
|
||||
"args": [
|
||||
"--timeout=10",
|
||||
"--picked"
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Home Assistant: Debug Current Test File",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "pytest",
|
||||
"console": "integratedTerminal",
|
||||
"args": ["-vv", "${file}"]
|
||||
},
|
||||
{
|
||||
// Debug by attaching to local Home Assistant server using Remote Python Debugger.
|
||||
// See https://www.home-assistant.io/integrations/debugpy/
|
||||
@ -77,4 +84,4 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@ -148,7 +148,7 @@
|
||||
{
|
||||
"label": "Install all Test Requirements",
|
||||
"type": "shell",
|
||||
"command": "uv pip install -r requirements_test_all.txt",
|
||||
"command": "uv pip install -r requirements.txt -r requirements_test_all.txt",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
|
34
CODEOWNERS
generated
34
CODEOWNERS
generated
@ -180,6 +180,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/azure_event_hub/ @eavanvalkenburg
|
||||
/tests/components/azure_event_hub/ @eavanvalkenburg
|
||||
/homeassistant/components/azure_service_bus/ @hfurubotten
|
||||
/homeassistant/components/azure_storage/ @zweckj
|
||||
/tests/components/azure_storage/ @zweckj
|
||||
/homeassistant/components/backup/ @home-assistant/core
|
||||
/tests/components/backup/ @home-assistant/core
|
||||
/homeassistant/components/baf/ @bdraco @jfroy
|
||||
@ -625,8 +627,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/hlk_sw16/ @jameshilliard
|
||||
/homeassistant/components/holiday/ @jrieger @gjohansson-ST
|
||||
/tests/components/holiday/ @jrieger @gjohansson-ST
|
||||
/homeassistant/components/home_connect/ @DavidMStraub @Diegorro98
|
||||
/tests/components/home_connect/ @DavidMStraub @Diegorro98
|
||||
/homeassistant/components/home_connect/ @DavidMStraub @Diegorro98 @MartinHjelmare
|
||||
/tests/components/home_connect/ @DavidMStraub @Diegorro98 @MartinHjelmare
|
||||
/homeassistant/components/homeassistant/ @home-assistant/core
|
||||
/tests/components/homeassistant/ @home-assistant/core
|
||||
/homeassistant/components/homeassistant_alerts/ @home-assistant/core
|
||||
@ -731,6 +733,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/intent/ @home-assistant/core @synesthesiam
|
||||
/tests/components/intent/ @home-assistant/core @synesthesiam
|
||||
/homeassistant/components/intesishome/ @jnimmo
|
||||
/homeassistant/components/iometer/ @MaestroOnICe
|
||||
/tests/components/iometer/ @MaestroOnICe
|
||||
/homeassistant/components/ios/ @robbiet480
|
||||
/tests/components/ios/ @robbiet480
|
||||
/homeassistant/components/iotawatt/ @gtdiehl @jyavenard
|
||||
@ -765,8 +769,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/ituran/ @shmuelzon
|
||||
/homeassistant/components/izone/ @Swamp-Ig
|
||||
/tests/components/izone/ @Swamp-Ig
|
||||
/homeassistant/components/jellyfin/ @j-stienstra @ctalkington
|
||||
/tests/components/jellyfin/ @j-stienstra @ctalkington
|
||||
/homeassistant/components/jellyfin/ @RunC0deRun @ctalkington
|
||||
/tests/components/jellyfin/ @RunC0deRun @ctalkington
|
||||
/homeassistant/components/jewish_calendar/ @tsvi
|
||||
/tests/components/jewish_calendar/ @tsvi
|
||||
/homeassistant/components/juicenet/ @jesserockz
|
||||
@ -965,8 +969,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/motionblinds_ble/ @LennP @jerrybboy
|
||||
/homeassistant/components/motioneye/ @dermotduffy
|
||||
/tests/components/motioneye/ @dermotduffy
|
||||
/homeassistant/components/motionmount/ @RJPoelstra
|
||||
/tests/components/motionmount/ @RJPoelstra
|
||||
/homeassistant/components/motionmount/ @laiho-vogels
|
||||
/tests/components/motionmount/ @laiho-vogels
|
||||
/homeassistant/components/mqtt/ @emontnemery @jbouwh @bdraco
|
||||
/tests/components/mqtt/ @emontnemery @jbouwh @bdraco
|
||||
/homeassistant/components/msteams/ @peroyvind
|
||||
@ -1049,8 +1053,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/numato/ @clssn
|
||||
/homeassistant/components/number/ @home-assistant/core @Shulyaka
|
||||
/tests/components/number/ @home-assistant/core @Shulyaka
|
||||
/homeassistant/components/nut/ @bdraco @ollo69 @pestevez
|
||||
/tests/components/nut/ @bdraco @ollo69 @pestevez
|
||||
/homeassistant/components/nut/ @bdraco @ollo69 @pestevez @tdfountain
|
||||
/tests/components/nut/ @bdraco @ollo69 @pestevez @tdfountain
|
||||
/homeassistant/components/nws/ @MatthewFlamm @kamiyo
|
||||
/tests/components/nws/ @MatthewFlamm @kamiyo
|
||||
/homeassistant/components/nyt_games/ @joostlek
|
||||
@ -1136,12 +1140,14 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/permobil/ @IsakNyberg
|
||||
/homeassistant/components/persistent_notification/ @home-assistant/core
|
||||
/tests/components/persistent_notification/ @home-assistant/core
|
||||
/homeassistant/components/pglab/ @pglab-electronics
|
||||
/tests/components/pglab/ @pglab-electronics
|
||||
/homeassistant/components/philips_js/ @elupus
|
||||
/tests/components/philips_js/ @elupus
|
||||
/homeassistant/components/pi_hole/ @shenxn
|
||||
/tests/components/pi_hole/ @shenxn
|
||||
/homeassistant/components/picnic/ @corneyl
|
||||
/tests/components/picnic/ @corneyl
|
||||
/homeassistant/components/picnic/ @corneyl @codesalatdev
|
||||
/tests/components/picnic/ @corneyl @codesalatdev
|
||||
/homeassistant/components/ping/ @jpbede
|
||||
/tests/components/ping/ @jpbede
|
||||
/homeassistant/components/plaato/ @JohNan
|
||||
@ -1338,6 +1344,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/sensorpro/ @bdraco
|
||||
/homeassistant/components/sensorpush/ @bdraco
|
||||
/tests/components/sensorpush/ @bdraco
|
||||
/homeassistant/components/sensorpush_cloud/ @sstallion
|
||||
/tests/components/sensorpush_cloud/ @sstallion
|
||||
/homeassistant/components/sensoterra/ @markruys
|
||||
/tests/components/sensoterra/ @markruys
|
||||
/homeassistant/components/sentry/ @dcramer @frenck
|
||||
@ -1393,6 +1401,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/smappee/ @bsmappee
|
||||
/homeassistant/components/smart_meter_texas/ @grahamwetzler
|
||||
/tests/components/smart_meter_texas/ @grahamwetzler
|
||||
/homeassistant/components/smartthings/ @joostlek
|
||||
/tests/components/smartthings/ @joostlek
|
||||
/homeassistant/components/smarttub/ @mdz
|
||||
/tests/components/smarttub/ @mdz
|
||||
/homeassistant/components/smarty/ @z0mbieprocess
|
||||
@ -1407,6 +1417,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/snapcast/ @luar123
|
||||
/homeassistant/components/snmp/ @nmaggioni
|
||||
/tests/components/snmp/ @nmaggioni
|
||||
/homeassistant/components/snoo/ @Lash-L
|
||||
/tests/components/snoo/ @Lash-L
|
||||
/homeassistant/components/snooz/ @AustinBrunkhorst
|
||||
/tests/components/snooz/ @AustinBrunkhorst
|
||||
/homeassistant/components/solaredge/ @frenck @bdraco
|
||||
@ -1687,6 +1699,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/weatherflow_cloud/ @jeeftor
|
||||
/homeassistant/components/weatherkit/ @tjhorner
|
||||
/tests/components/weatherkit/ @tjhorner
|
||||
/homeassistant/components/webdav/ @jpbede
|
||||
/tests/components/webdav/ @jpbede
|
||||
/homeassistant/components/webhook/ @home-assistant/core
|
||||
/tests/components/webhook/ @home-assistant/core
|
||||
/homeassistant/components/webmin/ @autinerd
|
||||
|
38
Dockerfile
generated
38
Dockerfile
generated
@ -12,8 +12,26 @@ ENV \
|
||||
|
||||
ARG QEMU_CPU
|
||||
|
||||
# Home Assistant S6-Overlay
|
||||
COPY rootfs /
|
||||
|
||||
# Needs to be redefined inside the FROM statement to be set for RUN commands
|
||||
ARG BUILD_ARCH
|
||||
# Get go2rtc binary
|
||||
RUN \
|
||||
case "${BUILD_ARCH}" in \
|
||||
"aarch64") go2rtc_suffix='arm64' ;; \
|
||||
"armhf") go2rtc_suffix='armv6' ;; \
|
||||
"armv7") go2rtc_suffix='arm' ;; \
|
||||
*) go2rtc_suffix=${BUILD_ARCH} ;; \
|
||||
esac \
|
||||
&& curl -L https://github.com/AlexxIT/go2rtc/releases/download/v1.9.8/go2rtc_linux_${go2rtc_suffix} --output /bin/go2rtc \
|
||||
&& chmod +x /bin/go2rtc \
|
||||
# Verify go2rtc can be executed
|
||||
&& go2rtc --version
|
||||
|
||||
# Install uv
|
||||
RUN pip3 install uv==0.5.21
|
||||
RUN pip3 install uv==0.6.1
|
||||
|
||||
WORKDIR /usr/src
|
||||
|
||||
@ -42,22 +60,4 @@ RUN \
|
||||
&& python3 -m compileall \
|
||||
homeassistant/homeassistant
|
||||
|
||||
# Home Assistant S6-Overlay
|
||||
COPY rootfs /
|
||||
|
||||
# Needs to be redefined inside the FROM statement to be set for RUN commands
|
||||
ARG BUILD_ARCH
|
||||
# Get go2rtc binary
|
||||
RUN \
|
||||
case "${BUILD_ARCH}" in \
|
||||
"aarch64") go2rtc_suffix='arm64' ;; \
|
||||
"armhf") go2rtc_suffix='armv6' ;; \
|
||||
"armv7") go2rtc_suffix='arm' ;; \
|
||||
*) go2rtc_suffix=${BUILD_ARCH} ;; \
|
||||
esac \
|
||||
&& curl -L https://github.com/AlexxIT/go2rtc/releases/download/v1.9.8/go2rtc_linux_${go2rtc_suffix} --output /bin/go2rtc \
|
||||
&& chmod +x /bin/go2rtc \
|
||||
# Verify go2rtc can be executed
|
||||
&& go2rtc --version
|
||||
|
||||
WORKDIR /config
|
||||
|
10
build.yaml
10
build.yaml
@ -1,10 +1,10 @@
|
||||
image: ghcr.io/home-assistant/{arch}-homeassistant
|
||||
build_from:
|
||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2024.12.0
|
||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2024.12.0
|
||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2024.12.0
|
||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2024.12.0
|
||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2024.12.0
|
||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2025.02.1
|
||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2025.02.1
|
||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2025.02.1
|
||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2025.02.1
|
||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2025.02.1
|
||||
codenotary:
|
||||
signer: notary@home-assistant.io
|
||||
base_image: notary@home-assistant.io
|
||||
|
@ -74,6 +74,7 @@ from .core_config import async_process_ha_core_config
|
||||
from .exceptions import HomeAssistantError
|
||||
from .helpers import (
|
||||
area_registry,
|
||||
backup,
|
||||
category_registry,
|
||||
config_validation as cv,
|
||||
device_registry,
|
||||
@ -134,14 +135,12 @@ DATA_REGISTRIES_LOADED: HassKey[None] = HassKey("bootstrap_registries_loaded")
|
||||
LOG_SLOW_STARTUP_INTERVAL = 60
|
||||
SLOW_STARTUP_CHECK_INTERVAL = 1
|
||||
|
||||
STAGE_0_SUBSTAGE_TIMEOUT = 60
|
||||
STAGE_1_TIMEOUT = 120
|
||||
STAGE_2_TIMEOUT = 300
|
||||
WRAP_UP_TIMEOUT = 300
|
||||
COOLDOWN_TIME = 60
|
||||
|
||||
|
||||
DEBUGGER_INTEGRATIONS = {"debugpy"}
|
||||
|
||||
# Core integrations are unconditionally loaded
|
||||
CORE_INTEGRATIONS = {"homeassistant", "persistent_notification"}
|
||||
|
||||
@ -152,6 +151,10 @@ LOGGING_AND_HTTP_DEPS_INTEGRATIONS = {
|
||||
"isal",
|
||||
# Set log levels
|
||||
"logger",
|
||||
# Ensure network config is available
|
||||
# before hassio or any other integration is
|
||||
# loaded that might create an aiohttp client session
|
||||
"network",
|
||||
# Error logging
|
||||
"system_log",
|
||||
"sentry",
|
||||
@ -161,23 +164,28 @@ FRONTEND_INTEGRATIONS = {
|
||||
# integrations can be removed and database migration status is
|
||||
# visible in frontend
|
||||
"frontend",
|
||||
# Hassio is an after dependency of backup, after dependencies
|
||||
# are not promoted from stage 2 to earlier stages, so we need to
|
||||
# add it here. Hassio needs to be setup before backup, otherwise
|
||||
# the backup integration will think we are a container/core install
|
||||
# when using HAOS or Supervised install.
|
||||
"hassio",
|
||||
# Backup is an after dependency of frontend, after dependencies
|
||||
# are not promoted from stage 2 to earlier stages, so we need to
|
||||
# add it here.
|
||||
"backup",
|
||||
}
|
||||
RECORDER_INTEGRATIONS = {
|
||||
# Setup after frontend
|
||||
# To record data
|
||||
"recorder",
|
||||
}
|
||||
DISCOVERY_INTEGRATIONS = ("bluetooth", "dhcp", "ssdp", "usb", "zeroconf")
|
||||
# Stage 0 is divided into substages. Each substage has a name, a set of integrations and a timeout.
|
||||
# The substage containing recorder should have no timeout, as it could cancel a database migration.
|
||||
# Recorder freezes "recorder" timeout during a migration, but it does not freeze other timeouts.
|
||||
# The substages preceding it should also have no timeout, until we ensure that the recorder
|
||||
# is not accidentally promoted as a dependency of any of the integrations in them.
|
||||
# If we add timeouts to the frontend substages, we should make sure they don't apply in recovery mode.
|
||||
STAGE_0_INTEGRATIONS = (
|
||||
# Load logging and http deps as soon as possible
|
||||
("logging, http deps", LOGGING_AND_HTTP_DEPS_INTEGRATIONS, None),
|
||||
# Setup frontend
|
||||
("frontend", FRONTEND_INTEGRATIONS, None),
|
||||
# Setup recorder
|
||||
("recorder", {"recorder"}, None),
|
||||
# Start up debuggers. Start these first in case they want to wait.
|
||||
("debugger", {"debugpy"}, STAGE_0_SUBSTAGE_TIMEOUT),
|
||||
# Zeroconf is used for mdns resolution in aiohttp client helper.
|
||||
("zeroconf", {"zeroconf"}, STAGE_0_SUBSTAGE_TIMEOUT),
|
||||
)
|
||||
|
||||
DISCOVERY_INTEGRATIONS = ("bluetooth", "dhcp", "ssdp", "usb")
|
||||
# Stage 1 integrations are not to be preimported in bootstrap.
|
||||
STAGE_1_INTEGRATIONS = {
|
||||
# We need to make sure discovery integrations
|
||||
# update their deps before stage 2 integrations
|
||||
@ -192,6 +200,7 @@ STAGE_1_INTEGRATIONS = {
|
||||
# Ensure supervisor is available
|
||||
"hassio",
|
||||
}
|
||||
|
||||
DEFAULT_INTEGRATIONS = {
|
||||
# These integrations are set up unless recovery mode is activated.
|
||||
#
|
||||
@ -232,22 +241,12 @@ DEFAULT_INTEGRATIONS_SUPERVISOR = {
|
||||
# These integrations are set up if using the Supervisor
|
||||
"hassio",
|
||||
}
|
||||
|
||||
CRITICAL_INTEGRATIONS = {
|
||||
# Recovery mode is activated if these integrations fail to set up
|
||||
"frontend",
|
||||
}
|
||||
|
||||
SETUP_ORDER = (
|
||||
# Load logging and http deps as soon as possible
|
||||
("logging, http deps", LOGGING_AND_HTTP_DEPS_INTEGRATIONS),
|
||||
# Setup frontend
|
||||
("frontend", FRONTEND_INTEGRATIONS),
|
||||
# Setup recorder
|
||||
("recorder", RECORDER_INTEGRATIONS),
|
||||
# Start up debuggers. Start these first in case they want to wait.
|
||||
("debugger", DEBUGGER_INTEGRATIONS),
|
||||
)
|
||||
|
||||
#
|
||||
# Storage keys we are likely to load during startup
|
||||
# in order of when we expect to load them.
|
||||
@ -322,10 +321,10 @@ async def async_setup_hass(
|
||||
|
||||
block_async_io.enable()
|
||||
|
||||
config_dict = None
|
||||
basic_setup_success = False
|
||||
|
||||
if not (recovery_mode := runtime_config.recovery_mode):
|
||||
config_dict = None
|
||||
basic_setup_success = False
|
||||
|
||||
await hass.async_add_executor_job(conf_util.process_ha_config_upgrade, hass)
|
||||
|
||||
try:
|
||||
@ -343,39 +342,43 @@ async def async_setup_hass(
|
||||
await async_from_config_dict(config_dict, hass) is not None
|
||||
)
|
||||
|
||||
if config_dict is None:
|
||||
recovery_mode = True
|
||||
await stop_hass(hass)
|
||||
hass = await create_hass()
|
||||
if config_dict is None:
|
||||
recovery_mode = True
|
||||
await stop_hass(hass)
|
||||
hass = await create_hass()
|
||||
|
||||
elif not basic_setup_success:
|
||||
_LOGGER.warning("Unable to set up core integrations. Activating recovery mode")
|
||||
recovery_mode = True
|
||||
await stop_hass(hass)
|
||||
hass = await create_hass()
|
||||
elif not basic_setup_success:
|
||||
_LOGGER.warning(
|
||||
"Unable to set up core integrations. Activating recovery mode"
|
||||
)
|
||||
recovery_mode = True
|
||||
await stop_hass(hass)
|
||||
hass = await create_hass()
|
||||
|
||||
elif any(domain not in hass.config.components for domain in CRITICAL_INTEGRATIONS):
|
||||
_LOGGER.warning(
|
||||
"Detected that %s did not load. Activating recovery mode",
|
||||
",".join(CRITICAL_INTEGRATIONS),
|
||||
)
|
||||
elif any(
|
||||
domain not in hass.config.components for domain in CRITICAL_INTEGRATIONS
|
||||
):
|
||||
_LOGGER.warning(
|
||||
"Detected that %s did not load. Activating recovery mode",
|
||||
",".join(CRITICAL_INTEGRATIONS),
|
||||
)
|
||||
|
||||
old_config = hass.config
|
||||
old_logging = hass.data.get(DATA_LOGGING)
|
||||
old_config = hass.config
|
||||
old_logging = hass.data.get(DATA_LOGGING)
|
||||
|
||||
recovery_mode = True
|
||||
await stop_hass(hass)
|
||||
hass = await create_hass()
|
||||
recovery_mode = True
|
||||
await stop_hass(hass)
|
||||
hass = await create_hass()
|
||||
|
||||
if old_logging:
|
||||
hass.data[DATA_LOGGING] = old_logging
|
||||
hass.config.debug = old_config.debug
|
||||
hass.config.skip_pip = old_config.skip_pip
|
||||
hass.config.skip_pip_packages = old_config.skip_pip_packages
|
||||
hass.config.internal_url = old_config.internal_url
|
||||
hass.config.external_url = old_config.external_url
|
||||
# Setup loader cache after the config dir has been set
|
||||
loader.async_setup(hass)
|
||||
if old_logging:
|
||||
hass.data[DATA_LOGGING] = old_logging
|
||||
hass.config.debug = old_config.debug
|
||||
hass.config.skip_pip = old_config.skip_pip
|
||||
hass.config.skip_pip_packages = old_config.skip_pip_packages
|
||||
hass.config.internal_url = old_config.internal_url
|
||||
hass.config.external_url = old_config.external_url
|
||||
# Setup loader cache after the config dir has been set
|
||||
loader.async_setup(hass)
|
||||
|
||||
if recovery_mode:
|
||||
_LOGGER.info("Starting in recovery mode")
|
||||
@ -694,7 +697,6 @@ async def async_mount_local_lib_path(config_dir: str) -> str:
|
||||
return deps_dir
|
||||
|
||||
|
||||
@core.callback
|
||||
def _get_domains(hass: core.HomeAssistant, config: dict[str, Any]) -> set[str]:
|
||||
"""Get domains of components to set up."""
|
||||
# Filter out the repeating and common config section [homeassistant]
|
||||
@ -716,109 +718,6 @@ def _get_domains(hass: core.HomeAssistant, config: dict[str, Any]) -> set[str]:
|
||||
return domains
|
||||
|
||||
|
||||
class _WatchPendingSetups:
|
||||
"""Periodic log and dispatch of setups that are pending."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: core.HomeAssistant,
|
||||
setup_started: dict[tuple[str, str | None], float],
|
||||
) -> None:
|
||||
"""Initialize the WatchPendingSetups class."""
|
||||
self._hass = hass
|
||||
self._setup_started = setup_started
|
||||
self._duration_count = 0
|
||||
self._handle: asyncio.TimerHandle | None = None
|
||||
self._previous_was_empty = True
|
||||
self._loop = hass.loop
|
||||
|
||||
def _async_watch(self) -> None:
|
||||
"""Periodic log of setups that are pending."""
|
||||
now = monotonic()
|
||||
self._duration_count += SLOW_STARTUP_CHECK_INTERVAL
|
||||
|
||||
remaining_with_setup_started: defaultdict[str, float] = defaultdict(float)
|
||||
for integration_group, start_time in self._setup_started.items():
|
||||
domain, _ = integration_group
|
||||
remaining_with_setup_started[domain] += now - start_time
|
||||
|
||||
if remaining_with_setup_started:
|
||||
_LOGGER.debug("Integration remaining: %s", remaining_with_setup_started)
|
||||
elif waiting_tasks := self._hass._active_tasks: # noqa: SLF001
|
||||
_LOGGER.debug("Waiting on tasks: %s", waiting_tasks)
|
||||
self._async_dispatch(remaining_with_setup_started)
|
||||
if (
|
||||
self._setup_started
|
||||
and self._duration_count % LOG_SLOW_STARTUP_INTERVAL == 0
|
||||
):
|
||||
# We log every LOG_SLOW_STARTUP_INTERVAL until all integrations are done
|
||||
# once we take over LOG_SLOW_STARTUP_INTERVAL (60s) to start up
|
||||
_LOGGER.warning(
|
||||
"Waiting on integrations to complete setup: %s",
|
||||
self._setup_started,
|
||||
)
|
||||
|
||||
_LOGGER.debug("Running timeout Zones: %s", self._hass.timeout.zones)
|
||||
self._async_schedule_next()
|
||||
|
||||
def _async_dispatch(self, remaining_with_setup_started: dict[str, float]) -> None:
|
||||
"""Dispatch the signal."""
|
||||
if remaining_with_setup_started or not self._previous_was_empty:
|
||||
async_dispatcher_send_internal(
|
||||
self._hass, SIGNAL_BOOTSTRAP_INTEGRATIONS, remaining_with_setup_started
|
||||
)
|
||||
self._previous_was_empty = not remaining_with_setup_started
|
||||
|
||||
def _async_schedule_next(self) -> None:
|
||||
"""Schedule the next call."""
|
||||
self._handle = self._loop.call_later(
|
||||
SLOW_STARTUP_CHECK_INTERVAL, self._async_watch
|
||||
)
|
||||
|
||||
def async_start(self) -> None:
|
||||
"""Start watching."""
|
||||
self._async_schedule_next()
|
||||
|
||||
def async_stop(self) -> None:
|
||||
"""Stop watching."""
|
||||
self._async_dispatch({})
|
||||
if self._handle:
|
||||
self._handle.cancel()
|
||||
self._handle = None
|
||||
|
||||
|
||||
async def async_setup_multi_components(
|
||||
hass: core.HomeAssistant,
|
||||
domains: set[str],
|
||||
config: dict[str, Any],
|
||||
) -> None:
|
||||
"""Set up multiple domains. Log on failure."""
|
||||
# Avoid creating tasks for domains that were setup in a previous stage
|
||||
domains_not_yet_setup = domains - hass.config.components
|
||||
# Create setup tasks for base platforms first since everything will have
|
||||
# to wait to be imported, and the sooner we can get the base platforms
|
||||
# loaded the sooner we can start loading the rest of the integrations.
|
||||
futures = {
|
||||
domain: hass.async_create_task_internal(
|
||||
async_setup_component(hass, domain, config),
|
||||
f"setup component {domain}",
|
||||
eager_start=True,
|
||||
)
|
||||
for domain in sorted(
|
||||
domains_not_yet_setup, key=SETUP_ORDER_SORT_KEY, reverse=True
|
||||
)
|
||||
}
|
||||
results = await asyncio.gather(*futures.values(), return_exceptions=True)
|
||||
for idx, domain in enumerate(futures):
|
||||
result = results[idx]
|
||||
if isinstance(result, BaseException):
|
||||
_LOGGER.error(
|
||||
"Error setting up integration %s - received exception",
|
||||
domain,
|
||||
exc_info=(type(result), result, result.__traceback__),
|
||||
)
|
||||
|
||||
|
||||
async def _async_resolve_domains_to_setup(
|
||||
hass: core.HomeAssistant, config: dict[str, Any]
|
||||
) -> tuple[set[str], dict[str, loader.Integration]]:
|
||||
@ -993,69 +892,52 @@ async def _async_set_up_integrations(
|
||||
domains_to_setup, integration_cache = await _async_resolve_domains_to_setup(
|
||||
hass, config
|
||||
)
|
||||
stage_2_domains = domains_to_setup.copy()
|
||||
|
||||
# Initialize recorder
|
||||
if "recorder" in domains_to_setup:
|
||||
recorder.async_initialize_recorder(hass)
|
||||
|
||||
pre_stage_domains = [
|
||||
(name, domains_to_setup & domain_group) for name, domain_group in SETUP_ORDER
|
||||
# Initialize backup
|
||||
if "backup" in domains_to_setup:
|
||||
backup.async_initialize_backup(hass)
|
||||
|
||||
stage_0_and_1_domains: list[tuple[str, set[str], int | None]] = [
|
||||
*(
|
||||
(name, domain_group & domains_to_setup, timeout)
|
||||
for name, domain_group, timeout in STAGE_0_INTEGRATIONS
|
||||
),
|
||||
("stage 1", STAGE_1_INTEGRATIONS & domains_to_setup, STAGE_1_TIMEOUT),
|
||||
]
|
||||
|
||||
# calculate what components to setup in what stage
|
||||
stage_1_domains: set[str] = set()
|
||||
_LOGGER.info("Setting up stage 0 and 1")
|
||||
for name, domain_group, timeout in stage_0_and_1_domains:
|
||||
if not domain_group:
|
||||
continue
|
||||
|
||||
# Find all dependencies of any dependency of any stage 1 integration that
|
||||
# we plan on loading and promote them to stage 1. This is done only to not
|
||||
# get misleading log messages
|
||||
deps_promotion: set[str] = STAGE_1_INTEGRATIONS
|
||||
while deps_promotion:
|
||||
old_deps_promotion = deps_promotion
|
||||
deps_promotion = set()
|
||||
_LOGGER.info("Setting up %s: %s", name, domain_group)
|
||||
to_be_loaded = domain_group.copy()
|
||||
to_be_loaded.update(
|
||||
dep
|
||||
for domain in domain_group
|
||||
if (integration := integration_cache.get(domain)) is not None
|
||||
for dep in integration.all_dependencies
|
||||
)
|
||||
async_set_domains_to_be_loaded(hass, to_be_loaded)
|
||||
stage_2_domains -= to_be_loaded
|
||||
|
||||
for domain in old_deps_promotion:
|
||||
if domain not in domains_to_setup or domain in stage_1_domains:
|
||||
continue
|
||||
|
||||
stage_1_domains.add(domain)
|
||||
|
||||
if (dep_itg := integration_cache.get(domain)) is None:
|
||||
continue
|
||||
|
||||
deps_promotion.update(dep_itg.all_dependencies)
|
||||
|
||||
stage_2_domains = domains_to_setup - stage_1_domains
|
||||
|
||||
for name, domain_group in pre_stage_domains:
|
||||
if domain_group:
|
||||
stage_2_domains -= domain_group
|
||||
_LOGGER.info("Setting up %s: %s", name, domain_group)
|
||||
to_be_loaded = domain_group.copy()
|
||||
to_be_loaded.update(
|
||||
dep
|
||||
for domain in domain_group
|
||||
if (integration := integration_cache.get(domain)) is not None
|
||||
for dep in integration.all_dependencies
|
||||
)
|
||||
async_set_domains_to_be_loaded(hass, to_be_loaded)
|
||||
await async_setup_multi_components(hass, domain_group, config)
|
||||
|
||||
# Enables after dependencies when setting up stage 1 domains
|
||||
async_set_domains_to_be_loaded(hass, stage_1_domains)
|
||||
|
||||
# Start setup
|
||||
if stage_1_domains:
|
||||
_LOGGER.info("Setting up stage 1: %s", stage_1_domains)
|
||||
try:
|
||||
async with hass.timeout.async_timeout(
|
||||
STAGE_1_TIMEOUT, cool_down=COOLDOWN_TIME
|
||||
):
|
||||
await async_setup_multi_components(hass, stage_1_domains, config)
|
||||
except TimeoutError:
|
||||
_LOGGER.warning(
|
||||
"Setup timed out for stage 1 waiting on %s - moving forward",
|
||||
hass._active_tasks, # noqa: SLF001
|
||||
)
|
||||
if timeout is None:
|
||||
await _async_setup_multi_components(hass, domain_group, config)
|
||||
else:
|
||||
try:
|
||||
async with hass.timeout.async_timeout(timeout, cool_down=COOLDOWN_TIME):
|
||||
await _async_setup_multi_components(hass, domain_group, config)
|
||||
except TimeoutError:
|
||||
_LOGGER.warning(
|
||||
"Setup timed out for %s waiting on %s - moving forward",
|
||||
name,
|
||||
hass._active_tasks, # noqa: SLF001
|
||||
)
|
||||
|
||||
# Add after dependencies when setting up stage 2 domains
|
||||
async_set_domains_to_be_loaded(hass, stage_2_domains)
|
||||
@ -1066,7 +948,7 @@ async def _async_set_up_integrations(
|
||||
async with hass.timeout.async_timeout(
|
||||
STAGE_2_TIMEOUT, cool_down=COOLDOWN_TIME
|
||||
):
|
||||
await async_setup_multi_components(hass, stage_2_domains, config)
|
||||
await _async_setup_multi_components(hass, stage_2_domains, config)
|
||||
except TimeoutError:
|
||||
_LOGGER.warning(
|
||||
"Setup timed out for stage 2 waiting on %s - moving forward",
|
||||
@ -1092,3 +974,106 @@ async def _async_set_up_integrations(
|
||||
"Integration setup times: %s",
|
||||
dict(sorted(setup_time.items(), key=itemgetter(1), reverse=True)),
|
||||
)
|
||||
|
||||
|
||||
class _WatchPendingSetups:
|
||||
"""Periodic log and dispatch of setups that are pending."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: core.HomeAssistant,
|
||||
setup_started: dict[tuple[str, str | None], float],
|
||||
) -> None:
|
||||
"""Initialize the WatchPendingSetups class."""
|
||||
self._hass = hass
|
||||
self._setup_started = setup_started
|
||||
self._duration_count = 0
|
||||
self._handle: asyncio.TimerHandle | None = None
|
||||
self._previous_was_empty = True
|
||||
self._loop = hass.loop
|
||||
|
||||
def _async_watch(self) -> None:
|
||||
"""Periodic log of setups that are pending."""
|
||||
now = monotonic()
|
||||
self._duration_count += SLOW_STARTUP_CHECK_INTERVAL
|
||||
|
||||
remaining_with_setup_started: defaultdict[str, float] = defaultdict(float)
|
||||
for integration_group, start_time in self._setup_started.items():
|
||||
domain, _ = integration_group
|
||||
remaining_with_setup_started[domain] += now - start_time
|
||||
|
||||
if remaining_with_setup_started:
|
||||
_LOGGER.debug("Integration remaining: %s", remaining_with_setup_started)
|
||||
elif waiting_tasks := self._hass._active_tasks: # noqa: SLF001
|
||||
_LOGGER.debug("Waiting on tasks: %s", waiting_tasks)
|
||||
self._async_dispatch(remaining_with_setup_started)
|
||||
if (
|
||||
self._setup_started
|
||||
and self._duration_count % LOG_SLOW_STARTUP_INTERVAL == 0
|
||||
):
|
||||
# We log every LOG_SLOW_STARTUP_INTERVAL until all integrations are done
|
||||
# once we take over LOG_SLOW_STARTUP_INTERVAL (60s) to start up
|
||||
_LOGGER.warning(
|
||||
"Waiting on integrations to complete setup: %s",
|
||||
self._setup_started,
|
||||
)
|
||||
|
||||
_LOGGER.debug("Running timeout Zones: %s", self._hass.timeout.zones)
|
||||
self._async_schedule_next()
|
||||
|
||||
def _async_dispatch(self, remaining_with_setup_started: dict[str, float]) -> None:
|
||||
"""Dispatch the signal."""
|
||||
if remaining_with_setup_started or not self._previous_was_empty:
|
||||
async_dispatcher_send_internal(
|
||||
self._hass, SIGNAL_BOOTSTRAP_INTEGRATIONS, remaining_with_setup_started
|
||||
)
|
||||
self._previous_was_empty = not remaining_with_setup_started
|
||||
|
||||
def _async_schedule_next(self) -> None:
|
||||
"""Schedule the next call."""
|
||||
self._handle = self._loop.call_later(
|
||||
SLOW_STARTUP_CHECK_INTERVAL, self._async_watch
|
||||
)
|
||||
|
||||
def async_start(self) -> None:
|
||||
"""Start watching."""
|
||||
self._async_schedule_next()
|
||||
|
||||
def async_stop(self) -> None:
|
||||
"""Stop watching."""
|
||||
self._async_dispatch({})
|
||||
if self._handle:
|
||||
self._handle.cancel()
|
||||
self._handle = None
|
||||
|
||||
|
||||
async def _async_setup_multi_components(
|
||||
hass: core.HomeAssistant,
|
||||
domains: set[str],
|
||||
config: dict[str, Any],
|
||||
) -> None:
|
||||
"""Set up multiple domains. Log on failure."""
|
||||
# Avoid creating tasks for domains that were setup in a previous stage
|
||||
domains_not_yet_setup = domains - hass.config.components
|
||||
# Create setup tasks for base platforms first since everything will have
|
||||
# to wait to be imported, and the sooner we can get the base platforms
|
||||
# loaded the sooner we can start loading the rest of the integrations.
|
||||
futures = {
|
||||
domain: hass.async_create_task_internal(
|
||||
async_setup_component(hass, domain, config),
|
||||
f"setup component {domain}",
|
||||
eager_start=True,
|
||||
)
|
||||
for domain in sorted(
|
||||
domains_not_yet_setup, key=SETUP_ORDER_SORT_KEY, reverse=True
|
||||
)
|
||||
}
|
||||
results = await asyncio.gather(*futures.values(), return_exceptions=True)
|
||||
for idx, domain in enumerate(futures):
|
||||
result = results[idx]
|
||||
if isinstance(result, BaseException):
|
||||
_LOGGER.error(
|
||||
"Error setting up integration %s - received exception",
|
||||
domain,
|
||||
exc_info=(type(result), result, result.__traceback__),
|
||||
)
|
||||
|
@ -6,6 +6,7 @@
|
||||
"azure_devops",
|
||||
"azure_event_hub",
|
||||
"azure_service_bus",
|
||||
"azure_storage",
|
||||
"microsoft_face_detect",
|
||||
"microsoft_face_identify",
|
||||
"microsoft_face",
|
||||
|
5
homeassistant/brands/sensorpush.json
Normal file
5
homeassistant/brands/sensorpush.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"domain": "sensorpush",
|
||||
"name": "SensorPush",
|
||||
"integrations": ["sensorpush", "sensorpush_cloud"]
|
||||
}
|
@ -11,7 +11,7 @@ from homeassistant.components.alarm_control_panel import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AbodeSystem
|
||||
from .const import DOMAIN
|
||||
@ -19,7 +19,9 @@ from .entity import AbodeDevice
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Abode alarm control panel device."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
@ -12,7 +12,7 @@ from homeassistant.components.binary_sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util.enum import try_parse_enum
|
||||
|
||||
from . import AbodeSystem
|
||||
@ -21,7 +21,9 @@ from .entity import AbodeDevice
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Abode binary sensor devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
@ -15,7 +15,7 @@ from homeassistant.components.camera import Camera
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import Event, HomeAssistant
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
from . import AbodeSystem
|
||||
@ -26,7 +26,9 @@ MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Abode camera devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
@ -7,7 +7,7 @@ from jaraco.abode.devices.cover import Cover
|
||||
from homeassistant.components.cover import CoverEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AbodeSystem
|
||||
from .const import DOMAIN
|
||||
@ -15,7 +15,9 @@ from .entity import AbodeDevice
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Abode cover devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
@ -18,7 +18,7 @@ from homeassistant.components.light import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AbodeSystem
|
||||
from .const import DOMAIN
|
||||
@ -26,7 +26,9 @@ from .entity import AbodeDevice
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Abode light devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
@ -7,7 +7,7 @@ from jaraco.abode.devices.lock import Lock
|
||||
from homeassistant.components.lock import LockEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AbodeSystem
|
||||
from .const import DOMAIN
|
||||
@ -15,7 +15,9 @@ from .entity import AbodeDevice
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Abode lock devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
@ -16,7 +16,7 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import LIGHT_LUX, PERCENTAGE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AbodeSystem
|
||||
from .const import DOMAIN
|
||||
@ -61,7 +61,9 @@ SENSOR_TYPES: tuple[AbodeSensorDescription, ...] = (
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Abode sensor devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
@ -10,7 +10,7 @@ from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AbodeSystem
|
||||
from .const import DOMAIN
|
||||
@ -20,7 +20,9 @@ DEVICE_TYPES = ["switch", "valve"]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Abode switch devices."""
|
||||
data: AbodeSystem = hass.data[DOMAIN]
|
||||
|
@ -11,7 +11,7 @@ from homeassistant.components.binary_sensor import (
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .coordinator import AcaiaConfigEntry
|
||||
from .entity import AcaiaEntity
|
||||
@ -40,7 +40,7 @@ BINARY_SENSORS: tuple[AcaiaBinarySensorEntityDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AcaiaConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up binary sensors."""
|
||||
|
||||
|
@ -8,7 +8,7 @@ from aioacaia.acaiascale import AcaiaScale
|
||||
|
||||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .coordinator import AcaiaConfigEntry
|
||||
from .entity import AcaiaEntity
|
||||
@ -45,7 +45,7 @@ BUTTONS: tuple[AcaiaButtonEntityDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AcaiaConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up button entities and services."""
|
||||
|
||||
|
@ -16,7 +16,7 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import PERCENTAGE, UnitOfMass, UnitOfVolumeFlowRate
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .coordinator import AcaiaConfigEntry
|
||||
from .entity import AcaiaEntity
|
||||
@ -77,7 +77,7 @@ RESTORE_SENSORS: tuple[AcaiaSensorEntityDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AcaiaConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up sensors."""
|
||||
|
||||
|
@ -7,6 +7,6 @@
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["accuweather"],
|
||||
"requirements": ["accuweather==4.0.0"],
|
||||
"requirements": ["accuweather==4.1.0"],
|
||||
"single_config_entry": true
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ from homeassistant.const import (
|
||||
UnitOfVolumetricFlux,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .const import (
|
||||
@ -375,7 +375,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AccuWeatherConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add AccuWeather entities from a config_entry."""
|
||||
observation_coordinator: AccuWeatherObservationDataUpdateCoordinator = (
|
||||
|
@ -16,7 +16,7 @@
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_api_key": "[%key:common::config_flow::error::invalid_api_key%]",
|
||||
"requests_exceeded": "The allowed number of requests to Accuweather API has been exceeded. You have to wait or change API Key."
|
||||
"requests_exceeded": "The allowed number of requests to the AccuWeather API has been exceeded. You have to wait or change the API key."
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
|
@ -30,7 +30,7 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util.dt import utc_from_timestamp
|
||||
|
||||
from .const import (
|
||||
@ -54,7 +54,7 @@ PARALLEL_UPDATES = 1
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AccuWeatherConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add a AccuWeather weather entity from a config_entry."""
|
||||
async_add_entities([AccuWeatherEntity(entry.runtime_data)])
|
||||
|
@ -11,7 +11,7 @@ from homeassistant.components.cover import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AcmedaConfigEntry
|
||||
from .const import ACMEDA_HUB_UPDATE
|
||||
@ -22,7 +22,7 @@ from .helpers import async_add_acmeda_entities
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AcmedaConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Acmeda Rollers from a config entry."""
|
||||
hub = config_entry.runtime_data
|
||||
|
@ -9,7 +9,7 @@ from aiopulse import Roller
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import DOMAIN, LOGGER
|
||||
|
||||
@ -23,7 +23,7 @@ def async_add_acmeda_entities(
|
||||
entity_class: type,
|
||||
config_entry: AcmedaConfigEntry,
|
||||
current: set[int],
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add any new entities."""
|
||||
hub = config_entry.runtime_data
|
||||
|
@ -6,7 +6,7 @@ from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
|
||||
from homeassistant.const import PERCENTAGE
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AcmedaConfigEntry
|
||||
from .const import ACMEDA_HUB_UPDATE
|
||||
@ -17,7 +17,7 @@ from .helpers import async_add_acmeda_entities
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AcmedaConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Acmeda Rollers from a config entry."""
|
||||
hub = config_entry.runtime_data
|
||||
|
@ -25,7 +25,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import ACCOUNT_ID, CONNECTION_TYPE, DOMAIN, LOCAL
|
||||
|
||||
@ -33,7 +33,7 @@ from .const import ACCOUNT_ID, CONNECTION_TYPE, DOMAIN, LOCAL
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Adax thermostat with config flow."""
|
||||
if entry.data.get(CONNECTION_TYPE) == LOCAL:
|
||||
|
@ -7,7 +7,7 @@ from dataclasses import dataclass
|
||||
from adguardhome import AdGuardHome, AdGuardHomeConnectionError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_NAME,
|
||||
@ -123,12 +123,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AdGuardConfigEntry) -> b
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: AdGuardConfigEntry) -> bool:
|
||||
"""Unload AdGuard Home config entry."""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
loaded_entries = [
|
||||
entry
|
||||
for entry in hass.config_entries.async_entries(DOMAIN)
|
||||
if entry.state == ConfigEntryState.LOADED
|
||||
]
|
||||
if len(loaded_entries) == 1:
|
||||
if not hass.config_entries.async_loaded_entries(DOMAIN):
|
||||
# This is the last loaded instance of AdGuard, deregister any services
|
||||
hass.services.async_remove(DOMAIN, SERVICE_ADD_URL)
|
||||
hass.services.async_remove(DOMAIN, SERVICE_REMOVE_URL)
|
||||
|
@ -12,7 +12,7 @@ from adguardhome import AdGuardHome
|
||||
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
||||
from homeassistant.const import PERCENTAGE, UnitOfTime
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdGuardConfigEntry, AdGuardData
|
||||
from .const import DOMAIN
|
||||
@ -85,7 +85,7 @@ SENSORS: tuple[AdGuardHomeEntityDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AdGuardConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdGuard Home sensor based on a config entry."""
|
||||
data = entry.runtime_data
|
||||
|
@ -79,7 +79,7 @@
|
||||
"services": {
|
||||
"add_url": {
|
||||
"name": "Add URL",
|
||||
"description": "Add a new filter subscription to AdGuard Home.",
|
||||
"description": "Adds a new filter subscription to AdGuard Home.",
|
||||
"fields": {
|
||||
"name": {
|
||||
"name": "[%key:common::config_flow::data::name%]",
|
||||
@ -123,11 +123,11 @@
|
||||
},
|
||||
"refresh": {
|
||||
"name": "Refresh",
|
||||
"description": "Refresh all filter subscriptions in AdGuard Home.",
|
||||
"description": "Refreshes all filter subscriptions in AdGuard Home.",
|
||||
"fields": {
|
||||
"force": {
|
||||
"name": "Force",
|
||||
"description": "Force update (bypasses AdGuard Home throttling). \"true\" to force, or \"false\" to omit for a regular refresh."
|
||||
"description": "Force update (bypasses AdGuard Home throttling), omit for a regular refresh."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ from adguardhome import AdGuardHome, AdGuardHomeError
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdGuardConfigEntry, AdGuardData
|
||||
from .const import DOMAIN, LOGGER
|
||||
@ -79,7 +79,7 @@ SWITCHES: tuple[AdGuardHomeSwitchEntityDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AdGuardConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdGuard Home switch based on a config entry."""
|
||||
data = entry.runtime_data
|
||||
|
@ -8,7 +8,7 @@ from homeassistant.components.binary_sensor import (
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdvantageAirDataConfigEntry
|
||||
from .entity import AdvantageAirAcEntity, AdvantageAirZoneEntity
|
||||
@ -20,7 +20,7 @@ PARALLEL_UPDATES = 0
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AdvantageAirDataConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir Binary Sensor platform."""
|
||||
|
||||
|
@ -19,7 +19,7 @@ from homeassistant.components.climate import (
|
||||
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_WHOLE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdvantageAirDataConfigEntry
|
||||
from .const import (
|
||||
@ -76,7 +76,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AdvantageAirDataConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir climate platform."""
|
||||
|
||||
|
@ -9,7 +9,7 @@ from homeassistant.components.cover import (
|
||||
CoverEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdvantageAirDataConfigEntry
|
||||
from .const import ADVANTAGE_AIR_STATE_CLOSE, ADVANTAGE_AIR_STATE_OPEN
|
||||
@ -22,7 +22,7 @@ PARALLEL_UPDATES = 0
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AdvantageAirDataConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir cover platform."""
|
||||
|
||||
|
@ -5,7 +5,7 @@ from typing import Any
|
||||
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdvantageAirDataConfigEntry
|
||||
from .const import ADVANTAGE_AIR_STATE_ON, DOMAIN as ADVANTAGE_AIR_DOMAIN
|
||||
@ -16,7 +16,7 @@ from .models import AdvantageAirData
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AdvantageAirDataConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir light platform."""
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from homeassistant.components.select import SelectEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdvantageAirDataConfigEntry
|
||||
from .entity import AdvantageAirAcEntity
|
||||
@ -14,7 +14,7 @@ ADVANTAGE_AIR_INACTIVE = "Inactive"
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AdvantageAirDataConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir select platform."""
|
||||
|
||||
|
@ -15,7 +15,7 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdvantageAirDataConfigEntry
|
||||
from .const import ADVANTAGE_AIR_STATE_OPEN
|
||||
@ -32,7 +32,7 @@ PARALLEL_UPDATES = 0
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AdvantageAirDataConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir sensor platform."""
|
||||
|
||||
|
@ -4,7 +4,7 @@ from typing import Any
|
||||
|
||||
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdvantageAirDataConfigEntry
|
||||
from .const import (
|
||||
@ -19,7 +19,7 @@ from .models import AdvantageAirData
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AdvantageAirDataConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir switch platform."""
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
from homeassistant.components.update import UpdateEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AdvantageAirDataConfigEntry
|
||||
from .const import DOMAIN as ADVANTAGE_AIR_DOMAIN
|
||||
@ -14,7 +14,7 @@ from .models import AdvantageAirData
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AdvantageAirDataConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AdvantageAir update platform."""
|
||||
|
||||
|
@ -9,7 +9,7 @@ from aemet_opendata.helpers import dict_nested_value
|
||||
|
||||
from homeassistant.components.image import Image, ImageEntity, ImageEntityDescription
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .coordinator import AemetConfigEntry, WeatherUpdateCoordinator
|
||||
from .entity import AemetEntity
|
||||
@ -25,7 +25,7 @@ AEMET_IMAGES: Final[tuple[ImageEntityDescription, ...]] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AemetConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AEMET OpenData image entities based on a config entry."""
|
||||
domain_data = config_entry.runtime_data
|
||||
|
@ -52,7 +52,7 @@ from homeassistant.const import (
|
||||
UnitOfVolumetricFlux,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import (
|
||||
@ -358,7 +358,7 @@ WEATHER_SENSORS: Final[tuple[AemetSensorEntityDescription, ...]] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AemetConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AEMET OpenData sensor entities based on a config entry."""
|
||||
domain_data = config_entry.runtime_data
|
||||
|
@ -25,7 +25,7 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import CONDITIONS_MAP
|
||||
from .coordinator import AemetConfigEntry, WeatherUpdateCoordinator
|
||||
@ -35,7 +35,7 @@ from .entity import AemetEntity
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AemetConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AEMET OpenData weather entity based on a config entry."""
|
||||
domain_data = config_entry.runtime_data
|
||||
|
@ -14,7 +14,7 @@ from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
)
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
from . import AfterShipConfigEntry
|
||||
@ -42,7 +42,7 @@ PLATFORM_SCHEMA: Final = cv.removed(DOMAIN, raise_if_present=False)
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AfterShipConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AfterShip sensor entities based on a config entry."""
|
||||
aftership = config_entry.runtime_data
|
||||
|
@ -9,7 +9,7 @@ from homeassistant.components.alarm_control_panel import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AgentDVRConfigEntry
|
||||
from .const import DOMAIN as AGENT_DOMAIN
|
||||
@ -24,7 +24,7 @@ CONST_ALARM_CONTROL_PANEL_NAME = "Alarm Panel"
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AgentDVRConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Agent DVR Alarm Control Panels."""
|
||||
async_add_entities([AgentBaseStation(config_entry.runtime_data)])
|
||||
|
@ -10,7 +10,7 @@ from homeassistant.components.mjpeg import MjpegCamera, filter_urllib3_logging
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
AddConfigEntryEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
)
|
||||
|
||||
@ -39,7 +39,7 @@ CAMERA_SERVICES = {
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AgentDVRConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Agent cameras."""
|
||||
filter_urllib3_logging()
|
||||
|
@ -4,12 +4,11 @@ from __future__ import annotations
|
||||
|
||||
from airgradient import AirGradientClient
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .coordinator import AirGradientCoordinator
|
||||
from .coordinator import AirGradientConfigEntry, AirGradientCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [
|
||||
Platform.BUTTON,
|
||||
@ -21,9 +20,6 @@ PLATFORMS: list[Platform] = [
|
||||
]
|
||||
|
||||
|
||||
type AirGradientConfigEntry = ConfigEntry[AirGradientCoordinator]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: AirGradientConfigEntry) -> bool:
|
||||
"""Set up Airgradient from a config entry."""
|
||||
|
||||
@ -31,7 +27,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirGradientConfigEntry)
|
||||
entry.data[CONF_HOST], session=async_get_clientsession(hass)
|
||||
)
|
||||
|
||||
coordinator = AirGradientCoordinator(hass, client)
|
||||
coordinator = AirGradientCoordinator(hass, entry, client)
|
||||
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
|
@ -13,7 +13,7 @@ from homeassistant.components.button import (
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirGradientConfigEntry
|
||||
from .const import DOMAIN
|
||||
@ -47,7 +47,7 @@ LED_BAR_TEST = AirGradientButtonEntityDescription(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirGradientConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AirGradient button entities based on a config entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -4,18 +4,17 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from airgradient import AirGradientClient, AirGradientError, Config, Measures
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import DOMAIN, LOGGER
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import AirGradientConfigEntry
|
||||
type AirGradientConfigEntry = ConfigEntry[AirGradientCoordinator]
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -32,11 +31,17 @@ class AirGradientCoordinator(DataUpdateCoordinator[AirGradientData]):
|
||||
config_entry: AirGradientConfigEntry
|
||||
_current_version: str
|
||||
|
||||
def __init__(self, hass: HomeAssistant, client: AirGradientClient) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: AirGradientConfigEntry,
|
||||
client: AirGradientClient,
|
||||
) -> None:
|
||||
"""Initialize coordinator."""
|
||||
super().__init__(
|
||||
hass,
|
||||
logger=LOGGER,
|
||||
config_entry=config_entry,
|
||||
name=f"AirGradient {client.host}",
|
||||
update_interval=timedelta(minutes=1),
|
||||
)
|
||||
|
@ -14,7 +14,7 @@ from homeassistant.components.number import (
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirGradientConfigEntry
|
||||
from .const import DOMAIN
|
||||
@ -60,7 +60,7 @@ LED_BAR_BRIGHTNESS = AirGradientNumberEntityDescription(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirGradientConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AirGradient number entities based on a config entry."""
|
||||
|
||||
|
@ -14,7 +14,7 @@ from homeassistant.components.select import (
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirGradientConfigEntry
|
||||
from .const import DOMAIN, PM_STANDARD, PM_STANDARD_REVERSE
|
||||
@ -142,7 +142,7 @@ CONTROL_ENTITIES: tuple[AirGradientSelectEntityDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirGradientConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AirGradient select entities based on a config entry."""
|
||||
|
||||
|
@ -27,7 +27,7 @@ from homeassistant.const import (
|
||||
UnitOfTime,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import AirGradientConfigEntry
|
||||
@ -225,7 +225,7 @@ CONFIG_DISPLAY_SENSOR_TYPES: tuple[AirGradientConfigSensorEntityDescription, ...
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirGradientConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AirGradient sensor entities based on a config entry."""
|
||||
|
||||
|
@ -15,7 +15,7 @@ from homeassistant.components.switch import (
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirGradientConfigEntry
|
||||
from .const import DOMAIN
|
||||
@ -45,7 +45,7 @@ POST_DATA_TO_AIRGRADIENT = AirGradientSwitchEntityDescription(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirGradientConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AirGradient switch entities based on a config entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -6,7 +6,7 @@ from propcache.api import cached_property
|
||||
|
||||
from homeassistant.components.update import UpdateDeviceClass, UpdateEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirGradientConfigEntry, AirGradientCoordinator
|
||||
from .entity import AirGradientEntity
|
||||
@ -18,7 +18,7 @@ SCAN_INTERVAL = timedelta(hours=1)
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AirGradientConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Airgradient update platform."""
|
||||
|
||||
|
@ -6,21 +6,18 @@ from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from homeassistant.components.air_quality import DOMAIN as AIR_QUALITY_PLATFORM
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import CONF_USE_NEAREST, DOMAIN, MIN_UPDATE_INTERVAL
|
||||
from .coordinator import AirlyDataUpdateCoordinator
|
||||
from .coordinator import AirlyConfigEntry, AirlyDataUpdateCoordinator
|
||||
|
||||
PLATFORMS = [Platform.SENSOR]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type AirlyConfigEntry = ConfigEntry[AirlyDataUpdateCoordinator]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: AirlyConfigEntry) -> bool:
|
||||
"""Set up Airly as config entry."""
|
||||
@ -60,7 +57,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirlyConfigEntry) -> boo
|
||||
update_interval = timedelta(minutes=MIN_UPDATE_INTERVAL)
|
||||
|
||||
coordinator = AirlyDataUpdateCoordinator(
|
||||
hass, websession, api_key, latitude, longitude, update_interval, use_nearest
|
||||
hass,
|
||||
entry,
|
||||
websession,
|
||||
api_key,
|
||||
latitude,
|
||||
longitude,
|
||||
update_interval,
|
||||
use_nearest,
|
||||
)
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
|
@ -10,6 +10,7 @@ from aiohttp.client_exceptions import ClientConnectorError
|
||||
from airly import Airly
|
||||
from airly.exceptions import AirlyError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
from homeassistant.util import dt as dt_util
|
||||
@ -27,6 +28,8 @@ from .const import (
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type AirlyConfigEntry = ConfigEntry[AirlyDataUpdateCoordinator]
|
||||
|
||||
|
||||
def set_update_interval(instances_count: int, requests_remaining: int) -> timedelta:
|
||||
"""Return data update interval.
|
||||
@ -58,9 +61,12 @@ def set_update_interval(instances_count: int, requests_remaining: int) -> timede
|
||||
class AirlyDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str | float | int]]):
|
||||
"""Define an object to hold Airly data."""
|
||||
|
||||
config_entry: AirlyConfigEntry
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: AirlyConfigEntry,
|
||||
session: ClientSession,
|
||||
api_key: str,
|
||||
latitude: float,
|
||||
@ -76,7 +82,13 @@ class AirlyDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str | float | i
|
||||
self.airly = Airly(api_key, session, language=language)
|
||||
self.use_nearest = use_nearest
|
||||
|
||||
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
config_entry=config_entry,
|
||||
name=DOMAIN,
|
||||
update_interval=update_interval,
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, str | float | int]:
|
||||
"""Update data via library."""
|
||||
|
@ -13,7 +13,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import AirlyConfigEntry
|
||||
from .coordinator import AirlyConfigEntry
|
||||
|
||||
TO_REDACT = {CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_UNIQUE_ID}
|
||||
|
||||
|
@ -21,10 +21,9 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import AirlyConfigEntry, AirlyDataUpdateCoordinator
|
||||
from .const import (
|
||||
ATTR_ADVICE,
|
||||
ATTR_API_ADVICE,
|
||||
@ -52,6 +51,7 @@ from .const import (
|
||||
SUFFIX_PERCENT,
|
||||
URL,
|
||||
)
|
||||
from .coordinator import AirlyConfigEntry, AirlyDataUpdateCoordinator
|
||||
|
||||
PARALLEL_UPDATES = 1
|
||||
|
||||
@ -175,7 +175,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirlyConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Airly sensor entities based on a config entry."""
|
||||
name = entry.data[CONF_NAME]
|
||||
|
@ -9,8 +9,8 @@ from airly import Airly
|
||||
from homeassistant.components import system_health
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
|
||||
from . import AirlyConfigEntry
|
||||
from .const import DOMAIN
|
||||
from .coordinator import AirlyConfigEntry
|
||||
|
||||
|
||||
@callback
|
||||
|
@ -15,13 +15,11 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .coordinator import AirNowDataUpdateCoordinator
|
||||
from .coordinator import AirNowConfigEntry, AirNowDataUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
PLATFORMS = [Platform.SENSOR]
|
||||
|
||||
type AirNowConfigEntry = ConfigEntry[AirNowDataUpdateCoordinator]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: AirNowConfigEntry) -> bool:
|
||||
"""Set up AirNow from a config entry."""
|
||||
@ -38,7 +36,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirNowConfigEntry) -> bo
|
||||
# Setup the Coordinator
|
||||
session = async_get_clientsession(hass)
|
||||
coordinator = AirNowDataUpdateCoordinator(
|
||||
hass, session, api_key, latitude, longitude, distance, update_interval
|
||||
hass, entry, session, api_key, latitude, longitude, distance, update_interval
|
||||
)
|
||||
|
||||
# Sync with Coordinator
|
||||
|
@ -10,6 +10,7 @@ from pyairnow import WebServiceAPI
|
||||
from pyairnow.conv import aqi_to_concentration
|
||||
from pyairnow.errors import AirNowError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
@ -34,13 +35,18 @@ from .const import (
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type AirNowConfigEntry = ConfigEntry[AirNowDataUpdateCoordinator]
|
||||
|
||||
|
||||
class AirNowDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""The AirNow update coordinator."""
|
||||
|
||||
config_entry: AirNowConfigEntry
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: AirNowConfigEntry,
|
||||
session: ClientSession,
|
||||
api_key: str,
|
||||
latitude: float,
|
||||
@ -55,7 +61,13 @@ class AirNowDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
|
||||
self.airnow = WebServiceAPI(api_key, session=session)
|
||||
|
||||
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
config_entry=config_entry,
|
||||
name=DOMAIN,
|
||||
update_interval=update_interval,
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
"""Update data via library."""
|
||||
|
@ -13,7 +13,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import AirNowConfigEntry
|
||||
from .coordinator import AirNowConfigEntry
|
||||
|
||||
ATTR_LATITUDE_CAP = "Latitude"
|
||||
ATTR_LONGITUDE_CAP = "Longitude"
|
||||
|
@ -21,11 +21,10 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import AirNowConfigEntry, AirNowDataUpdateCoordinator
|
||||
from .const import (
|
||||
ATTR_API_AQI,
|
||||
ATTR_API_AQI_DESCRIPTION,
|
||||
@ -43,6 +42,7 @@ from .const import (
|
||||
DOMAIN,
|
||||
US_TZ_OFFSETS,
|
||||
)
|
||||
from .coordinator import AirNowConfigEntry, AirNowDataUpdateCoordinator
|
||||
|
||||
ATTRIBUTION = "Data provided by AirNow"
|
||||
|
||||
@ -130,7 +130,7 @@ SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AirNowConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AirNow sensor entities based on a config entry."""
|
||||
coordinator = config_entry.runtime_data
|
||||
|
@ -83,6 +83,7 @@ class AirQConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
await self.async_set_unique_id(device_info["id"])
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
_LOGGER.debug("Creating an entry for %s", device_info["name"])
|
||||
return self.async_create_entry(title=device_info["name"], data=user_input)
|
||||
|
||||
return self.async_show_form(
|
||||
|
@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from aioairq import AirQ
|
||||
from aioairq.core import AirQ, identify_warming_up_sensors
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD
|
||||
@ -22,6 +22,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
class AirQCoordinator(DataUpdateCoordinator):
|
||||
"""Coordinator is responsible for querying the device at a specified route."""
|
||||
|
||||
config_entry: ConfigEntry
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
@ -33,6 +35,7 @@ class AirQCoordinator(DataUpdateCoordinator):
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
config_entry=entry,
|
||||
name=DOMAIN,
|
||||
update_interval=timedelta(seconds=UPDATE_INTERVAL),
|
||||
)
|
||||
@ -52,6 +55,9 @@ class AirQCoordinator(DataUpdateCoordinator):
|
||||
async def _async_update_data(self) -> dict:
|
||||
"""Fetch the data from the device."""
|
||||
if "name" not in self.device_info:
|
||||
_LOGGER.debug(
|
||||
"'name' not found in AirQCoordinator.device_info, fetching from the device"
|
||||
)
|
||||
info = await self.airq.fetch_device_info()
|
||||
self.device_info.update(
|
||||
DeviceInfo(
|
||||
@ -61,7 +67,16 @@ class AirQCoordinator(DataUpdateCoordinator):
|
||||
hw_version=info["hw_version"],
|
||||
)
|
||||
)
|
||||
return await self.airq.get_latest_data( # type: ignore[no-any-return]
|
||||
_LOGGER.debug(
|
||||
"Updated AirQCoordinator.device_info for 'name' %s",
|
||||
self.device_info.get("name"),
|
||||
)
|
||||
data: dict = await self.airq.get_latest_data(
|
||||
return_average=self.return_average,
|
||||
clip_negative_values=self.clip_negative,
|
||||
)
|
||||
if warming_up_sensors := identify_warming_up_sensors(data):
|
||||
_LOGGER.debug(
|
||||
"Following sensors are still warming up: %s", warming_up_sensors
|
||||
)
|
||||
return data
|
||||
|
@ -7,5 +7,5 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairq"],
|
||||
"requirements": ["aioairq==0.4.3"]
|
||||
"requirements": ["aioairq==0.4.4"]
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import AirQConfigEntry, AirQCoordinator
|
||||
@ -399,7 +399,7 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirQConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up sensor entities based on a config entry."""
|
||||
|
||||
|
@ -22,7 +22,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
@ -114,7 +114,7 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirthingsConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Airthings sensor."""
|
||||
|
||||
|
@ -25,7 +25,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.entity_registry import (
|
||||
RegistryEntry,
|
||||
async_entries_for_device,
|
||||
@ -153,7 +153,7 @@ def async_migrate(hass: HomeAssistant, address: str, sensor_name: str) -> None:
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirthingsBLEConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Airthings BLE sensors."""
|
||||
is_metric = hass.config.units is METRIC_SYSTEM
|
||||
|
@ -19,7 +19,7 @@ from homeassistant.components.climate import (
|
||||
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import AirTouch4ConfigEntry
|
||||
@ -64,7 +64,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: AirTouch4ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Airtouch 4."""
|
||||
coordinator = config_entry.runtime_data
|
||||
|
@ -37,7 +37,7 @@ from homeassistant.components.climate import (
|
||||
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import Airtouch5ConfigEntry
|
||||
from .const import DOMAIN, FAN_INTELLIGENT_AUTO, FAN_TURBO
|
||||
@ -93,7 +93,7 @@ FAN_MODE_TO_SET_AC_FAN_SPEED = {
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: Airtouch5ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Airtouch 5 Climate entities."""
|
||||
client = config_entry.runtime_data
|
||||
|
@ -20,7 +20,7 @@ from homeassistant.components.cover import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import Airtouch5ConfigEntry
|
||||
from .const import DOMAIN
|
||||
@ -32,7 +32,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: Airtouch5ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Airtouch 5 Cover entities."""
|
||||
client = config_entry.runtime_data
|
||||
|
@ -23,7 +23,7 @@ from homeassistant.const import (
|
||||
CONF_STATE,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from . import AirVisualConfigEntry
|
||||
@ -108,7 +108,7 @@ POLLUTANT_UNITS = {
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirVisualConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AirVisual sensors based on a config entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -20,7 +20,7 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirVisualProConfigEntry
|
||||
from .entity import AirVisualProEntity
|
||||
@ -130,7 +130,7 @@ def async_get_aqi_locale(settings: dict[str, Any]) -> str:
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirVisualProConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up AirVisual sensors based on a config entry."""
|
||||
async_add_entities(
|
||||
|
@ -15,7 +15,6 @@ from aioairzone.const import (
|
||||
)
|
||||
from aioairzone.localapi import AirzoneLocalApi, ConnectionOptions
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_ID, CONF_PORT, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import (
|
||||
@ -25,7 +24,7 @@ from homeassistant.helpers import (
|
||||
)
|
||||
|
||||
from .const import DOMAIN, MANUFACTURER
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [
|
||||
Platform.BINARY_SENSOR,
|
||||
@ -38,8 +37,6 @@ PLATFORMS: list[Platform] = [
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type AirzoneConfigEntry = ConfigEntry[AirzoneUpdateCoordinator]
|
||||
|
||||
|
||||
async def _async_migrate_unique_ids(
|
||||
hass: HomeAssistant,
|
||||
@ -90,7 +87,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirzoneConfigEntry) -> b
|
||||
)
|
||||
|
||||
airzone = AirzoneLocalApi(aiohttp_client.async_get_clientsession(hass), options)
|
||||
coordinator = AirzoneUpdateCoordinator(hass, airzone)
|
||||
coordinator = AirzoneUpdateCoordinator(hass, entry, airzone)
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
await _async_migrate_unique_ids(hass, entry, coordinator)
|
||||
|
||||
|
@ -23,10 +23,9 @@ from homeassistant.components.binary_sensor import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneConfigEntry
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneEntity, AirzoneSystemEntity, AirzoneZoneEntity
|
||||
|
||||
|
||||
@ -77,7 +76,7 @@ ZONE_BINARY_SENSOR_TYPES: Final[tuple[AirzoneBinarySensorEntityDescription, ...]
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone binary sensors from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -48,11 +48,10 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_TEMPERATURE
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneConfigEntry
|
||||
from .const import API_TEMPERATURE_STEP, TEMP_UNIT_LIB_TO_HASS
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneZoneEntity
|
||||
|
||||
BASE_FAN_SPEEDS: Final[dict[int, str]] = {
|
||||
@ -101,7 +100,7 @@ HVAC_MODE_HASS_TO_LIB: Final[dict[HVACMode, OperationMode]] = {
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone climate from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -10,6 +10,7 @@ from typing import Any
|
||||
from aioairzone.exceptions import AirzoneError
|
||||
from aioairzone.localapi import AirzoneLocalApi
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
@ -19,17 +20,27 @@ SCAN_INTERVAL = timedelta(seconds=60)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type AirzoneConfigEntry = ConfigEntry[AirzoneUpdateCoordinator]
|
||||
|
||||
|
||||
class AirzoneUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""Class to manage fetching data from the Airzone device."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, airzone: AirzoneLocalApi) -> None:
|
||||
config_entry: AirzoneConfigEntry
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: AirzoneConfigEntry,
|
||||
airzone: AirzoneLocalApi,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
self.airzone = airzone
|
||||
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
config_entry=config_entry,
|
||||
name=DOMAIN,
|
||||
update_interval=SCAN_INTERVAL,
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ from homeassistant.components.diagnostics import async_redact_data
|
||||
from homeassistant.const import CONF_UNIQUE_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import AirzoneConfigEntry
|
||||
from .coordinator import AirzoneConfigEntry
|
||||
|
||||
TO_REDACT_API = [
|
||||
API_MAC,
|
||||
|
@ -31,9 +31,8 @@ from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import AirzoneConfigEntry
|
||||
from .const import DOMAIN, MANUFACTURER
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -25,10 +25,9 @@ from homeassistant.components.select import SelectEntity, SelectEntityDescriptio
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneConfigEntry
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneEntity, AirzoneZoneEntity
|
||||
|
||||
|
||||
@ -118,7 +117,7 @@ ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone select from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -28,11 +28,10 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneConfigEntry
|
||||
from .const import TEMP_UNIT_LIB_TO_HASS
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import (
|
||||
AirzoneEntity,
|
||||
AirzoneHotWaterEntity,
|
||||
@ -80,7 +79,7 @@ ZONE_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone sensors from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -14,10 +14,9 @@ from homeassistant.components.switch import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneConfigEntry
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneEntity, AirzoneZoneEntity
|
||||
|
||||
|
||||
@ -40,7 +39,7 @@ ZONE_SWITCH_TYPES: Final[tuple[AirzoneSwitchDescription, ...]] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone switch from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -28,11 +28,10 @@ from homeassistant.components.water_heater import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_TEMPERATURE, STATE_OFF
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneConfigEntry
|
||||
from .const import TEMP_UNIT_LIB_TO_HASS
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneHotWaterEntity
|
||||
|
||||
OPERATION_LIB_TO_HASS: Final[dict[HotWaterOperation, str]] = {
|
||||
@ -59,7 +58,7 @@ OPERATION_MODE_TO_DHW_PARAMS: Final[dict[str, dict[str, Any]]] = {
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone Water Heater from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -5,12 +5,11 @@ from __future__ import annotations
|
||||
from aioairzone_cloud.cloudapi import AirzoneCloudApi
|
||||
from aioairzone_cloud.common import ConnectionOptions
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_ID, CONF_PASSWORD, CONF_USERNAME, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneCloudConfigEntry, AirzoneUpdateCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [
|
||||
Platform.BINARY_SENSOR,
|
||||
@ -21,8 +20,6 @@ PLATFORMS: list[Platform] = [
|
||||
Platform.WATER_HEATER,
|
||||
]
|
||||
|
||||
type AirzoneCloudConfigEntry = ConfigEntry[AirzoneUpdateCoordinator]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: AirzoneCloudConfigEntry
|
||||
@ -42,7 +39,7 @@ async def async_setup_entry(
|
||||
airzone.select_installation(inst)
|
||||
await airzone.update_installation(inst)
|
||||
|
||||
coordinator = AirzoneUpdateCoordinator(hass, airzone)
|
||||
coordinator = AirzoneUpdateCoordinator(hass, entry, airzone)
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
entry.runtime_data = coordinator
|
||||
|
@ -26,10 +26,9 @@ from homeassistant.components.binary_sensor import (
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneCloudConfigEntry
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneCloudConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import (
|
||||
AirzoneAidooEntity,
|
||||
AirzoneEntity,
|
||||
@ -112,7 +111,7 @@ ZONE_BINARY_SENSOR_TYPES: Final[tuple[AirzoneBinarySensorEntityDescription, ...]
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneCloudConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone Cloud binary sensors from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -56,10 +56,9 @@ from homeassistant.components.climate import (
|
||||
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneCloudConfigEntry
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneCloudConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import (
|
||||
AirzoneAidooEntity,
|
||||
AirzoneEntity,
|
||||
@ -120,7 +119,7 @@ HVAC_MODE_HASS_TO_LIB: Final[dict[HVACMode, OperationMode]] = {
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneCloudConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone climate from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -10,6 +10,7 @@ from typing import Any
|
||||
from aioairzone_cloud.cloudapi import AirzoneCloudApi
|
||||
from aioairzone_cloud.exceptions import AirzoneCloudError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
@ -19,11 +20,20 @@ SCAN_INTERVAL = timedelta(seconds=60)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type AirzoneCloudConfigEntry = ConfigEntry[AirzoneUpdateCoordinator]
|
||||
|
||||
|
||||
class AirzoneUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""Class to manage fetching data from the Airzone Cloud device."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, airzone: AirzoneCloudApi) -> None:
|
||||
config_entry: AirzoneCloudConfigEntry
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: AirzoneCloudConfigEntry,
|
||||
airzone: AirzoneCloudApi,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
self.airzone = airzone
|
||||
self.airzone.set_update_callback(self.async_set_updated_data)
|
||||
@ -31,6 +41,7 @@ class AirzoneUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
config_entry=config_entry,
|
||||
name=DOMAIN,
|
||||
update_interval=SCAN_INTERVAL,
|
||||
)
|
||||
|
@ -25,7 +25,7 @@ from homeassistant.components.diagnostics import async_redact_data
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import AirzoneCloudConfigEntry
|
||||
from .coordinator import AirzoneCloudConfigEntry
|
||||
|
||||
TO_REDACT_API = [
|
||||
API_CITY,
|
||||
|
@ -21,10 +21,9 @@ from aioairzone_cloud.const import (
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneCloudConfigEntry
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneCloudConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneEntity, AirzoneZoneEntity
|
||||
|
||||
|
||||
@ -90,7 +89,7 @@ ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneCloudConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone Cloud select from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -47,10 +47,9 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneCloudConfigEntry
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneCloudConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import (
|
||||
AirzoneAidooEntity,
|
||||
AirzoneEntity,
|
||||
@ -222,7 +221,7 @@ ZONE_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneCloudConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone Cloud sensors from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
@ -13,10 +13,9 @@ from homeassistant.components.switch import (
|
||||
SwitchEntityDescription,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import AirzoneCloudConfigEntry
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .coordinator import AirzoneCloudConfigEntry, AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneEntity, AirzoneZoneEntity
|
||||
|
||||
|
||||
@ -39,7 +38,7 @@ ZONE_SWITCH_TYPES: Final[tuple[AirzoneSwitchDescription, ...]] = (
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: AirzoneCloudConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add Airzone Cloud switch from a config_entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user