├── .browserslistrc ├── .devcontainer ├── Dockerfile ├── devcontainer.json └── post_create.sh ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── labeler.yml ├── move.yml ├── release-drafter.yml └── workflows │ ├── cast_deployment.yaml │ ├── ci.yaml │ ├── codeql-analysis.yml │ ├── demo_deployment.yaml │ ├── design_deployment.yaml │ ├── design_preview.yaml │ ├── labeler.yaml │ ├── lock.yml │ ├── nightly.yaml │ ├── relative-ci.yaml │ ├── release-drafter.yaml │ ├── release.yaml │ ├── stale.yml │ └── translations.yaml ├── .gitignore ├── .gitmodules ├── .husky └── pre-commit ├── .nvmrc ├── .prettierignore ├── .vscode ├── extensions.json ├── launch.json └── tasks.json ├── .yarn ├── patches │ ├── @material-mwc-formfield-npm-0.27.0-9528cb60f6.patch │ ├── @material-mwc-list-npm-0.27.0-5344fc9de4.patch │ ├── leaflet-draw-npm-1.0.4-0ca0ebcf65.patch │ ├── sortablejs-npm-1.15.6-3235a8f83b.patch │ └── workbox-build-npm-7.1.1-a854f3faae.patch └── releases │ └── yarn-4.9.1.cjs ├── .yarnrc.yml ├── CLA.md ├── CODE_OF_CONDUCT.md ├── LICENSE.md ├── MANIFEST.in ├── README.md ├── build-scripts ├── README.md ├── babel-plugins │ ├── custom-polyfill-plugin.js │ └── inline-constants-plugin.cjs ├── bundle.cjs ├── env.cjs ├── eslint.config.mjs ├── gulp │ ├── app.js │ ├── cast.js │ ├── clean.js │ ├── compress.js │ ├── demo.js │ ├── download-translations.js │ ├── entry-html.js │ ├── fetch-nightly-translations.js │ ├── gallery.js │ ├── gather-static.js │ ├── gen-icons-json.js │ ├── hassio.js │ ├── index.mjs │ ├── landing-page.js │ ├── locale-data.js │ ├── rspack.js │ ├── service-worker.js │ └── translations.js ├── list-plugins-and-polyfills.js ├── paths.cjs ├── removedIcons.json └── rspack.cjs ├── cast ├── README.md ├── public │ ├── _headers │ ├── _redirects │ ├── images │ │ ├── arsaboo.jpg │ │ ├── favicon.ico │ │ ├── google-nest-hub.png │ │ ├── ha-cast-icon.png │ │ ├── melody.jpg │ │ └── nabu-loves-hass.png │ ├── manifest.json │ ├── sw-legacy.js │ └── sw-modern.js ├── script │ ├── build_cast │ ├── develop_cast │ └── upload └── src │ ├── html │ ├── _social_meta.html.template │ ├── faq.html.template │ ├── index.html.template │ ├── media.html.template │ └── receiver.html.template │ ├── launcher │ ├── entrypoint.ts │ └── layout │ │ ├── hc-cast.ts │ │ ├── hc-connect.ts │ │ └── hc-layout.ts │ ├── media │ └── entrypoint.ts │ └── receiver │ ├── cast_context.ts │ ├── cast_framework.ts │ ├── demo │ ├── cast-demo-entities.ts │ └── cast-demo-lovelace.ts │ ├── entrypoint.ts │ ├── layout │ ├── hc-demo.ts │ ├── hc-launch-screen.ts │ ├── hc-lovelace.ts │ └── hc-main.ts │ └── types.ts ├── demo ├── public │ ├── _headers │ ├── assets │ │ ├── arsaboo │ │ │ ├── floorplans │ │ │ │ ├── ecobee_blank.png │ │ │ │ ├── main.png │ │ │ │ └── second.png │ │ │ ├── icons │ │ │ │ ├── Harmony.png │ │ │ │ ├── abode_disabled.png │ │ │ │ ├── abode_enabled.png │ │ │ │ ├── automation_disabled.png │ │ │ │ ├── automation_enabled.png │ │ │ │ ├── camera_backyard_recording.png │ │ │ │ ├── camera_backyard_streaming.png │ │ │ │ ├── camera_driveway_recording.png │ │ │ │ ├── camera_driveway_streaming.png │ │ │ │ ├── camera_patio_recording.png │ │ │ │ ├── camera_patio_streaming.png │ │ │ │ ├── camera_porch_recording.png │ │ │ │ ├── camera_porch_streaming.png │ │ │ │ ├── ecobee_blank.png │ │ │ │ ├── garage_door_closed.png │ │ │ │ ├── garage_door_open.png │ │ │ │ ├── light_bulb_off.png │ │ │ │ ├── light_bulb_on.png │ │ │ │ ├── light_off.png │ │ │ │ ├── light_on.png │ │ │ │ ├── security_armed_red.png │ │ │ │ ├── security_disarmed.png │ │ │ │ ├── tv_disabled.png │ │ │ │ ├── tv_enabled.png │ │ │ │ ├── tv_off2.png │ │ │ │ └── tv_on2.png │ │ │ └── images │ │ │ │ ├── arsaboo.jpg │ │ │ │ ├── camera.backyard.jpg │ │ │ │ ├── camera.driveway.jpg │ │ │ │ ├── camera.patio.jpg │ │ │ │ ├── camera.porch.jpg │ │ │ │ ├── media_player_family_room.jpg │ │ │ │ └── melody.jpg │ │ ├── jimpower │ │ │ ├── background-15.jpg │ │ │ ├── cardbackK.png │ │ │ ├── home │ │ │ │ ├── bus_10.jpg │ │ │ │ ├── git.png │ │ │ │ ├── house_4.png │ │ │ │ ├── james_10.jpg │ │ │ │ └── tina_4.jpg │ │ │ └── security │ │ │ │ ├── air_8.jpg │ │ │ │ ├── alarm_3.jpg │ │ │ │ ├── door_3.png │ │ │ │ ├── leak_2.png │ │ │ │ ├── motion_3.jpg │ │ │ │ ├── smoke_4.jpg │ │ │ │ └── window_2.jpg │ │ ├── kernehed │ │ │ ├── bella.jpg │ │ │ ├── camera.entre.jpg │ │ │ └── oscar.jpg │ │ ├── sections │ │ │ └── images │ │ │ │ └── media_player_family_room.jpg │ │ └── teachingbirds │ │ │ ├── House_square.jpg │ │ │ ├── Stefan_square.jpg │ │ │ ├── background_square.png │ │ │ ├── cleaning_square.jpg │ │ │ ├── clothes_drying_square.jpg │ │ │ ├── dryer_square.jpg │ │ │ ├── folded_clothes_square.jpg │ │ │ ├── guests_square.jpg │ │ │ ├── isa_square.jpg │ │ │ ├── laundry_clean_2_square.jpg │ │ │ ├── laundry_running_square.jpg │ │ │ ├── mailbox_bw_square.jpg │ │ │ ├── mailbox_square.jpg │ │ │ ├── meteogram.png │ │ │ ├── plants.png │ │ │ ├── radiator_off.jpg │ │ │ ├── radiator_on.jpg │ │ │ ├── roomba_bw_square.jpg │ │ │ ├── roomba_square.jpg │ │ │ ├── trash_bear_bw_square.jpg │ │ │ ├── trash_square.jpg │ │ │ └── washer_square.jpg │ ├── manifest.json │ ├── stub_config │ │ ├── bedroom.png │ │ ├── floorplan.png │ │ ├── kitchen.png │ │ └── t-shirt-promo.png │ ├── sw-legacy.js │ └── sw-modern.js ├── script │ ├── build_demo │ ├── develop_demo │ └── size_stats └── src │ ├── configs │ ├── arsaboo │ │ ├── entities.ts │ │ ├── index.ts │ │ ├── lovelace.ts │ │ └── theme.ts │ ├── demo-configs.ts │ ├── jimpower │ │ ├── entities.ts │ │ ├── index.ts │ │ ├── lovelace.ts │ │ └── theme.ts │ ├── kernehed │ │ ├── entities.ts │ │ ├── index.ts │ │ ├── lovelace.ts │ │ └── theme.ts │ ├── sections │ │ ├── entities.ts │ │ ├── index.ts │ │ └── lovelace.ts │ ├── teachingbirds │ │ ├── entities.ts │ │ ├── index.ts │ │ ├── lovelace.ts │ │ └── theme.ts │ └── types.ts │ ├── custom-cards │ ├── card-modder.js │ ├── card-tools.js │ ├── cast-demo-row.ts │ └── ha-demo-card.ts │ ├── entrypoint.ts │ ├── ha-demo.ts │ ├── html │ ├── _social_meta.html.template │ └── index.html.template │ ├── stubs │ ├── area_registry.ts │ ├── auth.ts │ ├── config.ts │ ├── config_entries.ts │ ├── device_registry.ts │ ├── energy.ts │ ├── entities.ts │ ├── entity_registry.ts │ ├── events.ts │ ├── floor_registry.ts │ ├── frontend.ts │ ├── hassio_supervisor.ts │ ├── history.ts │ ├── icons.ts │ ├── label_registry.ts │ ├── lovelace.ts │ ├── media_player.ts │ ├── persistent_notification.ts │ ├── recorder.ts │ ├── sensor.ts │ ├── system_log.ts │ ├── tags.ts │ ├── template.ts │ ├── todo.ts │ └── translations.ts │ └── util │ └── is_frontpage.ts ├── docs └── screenshot.png ├── eslint.config.mjs ├── gallery ├── eslint.config.mjs ├── public │ ├── api │ │ ├── hassio │ │ │ └── addons │ │ │ │ └── core_zwave_js │ │ │ │ └── icon │ │ └── media_player_proxy │ │ │ ├── media_player.bedroom │ │ │ ├── media_player.living_room │ │ │ └── media_player.walkman │ └── images │ │ ├── album_cover.jpg │ │ ├── album_cover_2.jpg │ │ ├── bed.png │ │ ├── brand │ │ ├── README.md │ │ ├── logo-exclusion-zone.png │ │ ├── logo-layout-variants.png │ │ └── logo.png │ │ ├── clearspace.png │ │ ├── divider.png │ │ ├── floorplan.png │ │ ├── frenck.jpg │ │ ├── kitchen.png │ │ ├── light_bulb_off.png │ │ ├── light_bulb_on.png │ │ ├── living_room.png │ │ ├── logo-variants.png │ │ ├── logo-with-text.png │ │ ├── netflix.jpg │ │ ├── office.jpg │ │ ├── paulus.jpg │ │ ├── select_box │ │ ├── card.svg │ │ └── text_only.svg │ │ └── sunflowers.jpg ├── script │ ├── build_gallery │ └── develop_gallery ├── sidebar.js └── src │ ├── components │ ├── demo-black-white-row.ts │ ├── demo-card.ts │ ├── demo-cards.ts │ ├── demo-more-info.ts │ ├── demo-more-infos.ts │ └── page-description.ts │ ├── data │ ├── date-options.ts │ ├── demo_states.js │ ├── hass.js │ ├── media_players.ts │ ├── plants.ts │ ├── text.ts │ └── traces │ │ ├── basic_trace.ts │ │ ├── mock-demo-trace.ts │ │ ├── motion-light-trace.ts │ │ └── types.ts │ ├── entrypoint.js │ ├── ha-demo-options.ts │ ├── ha-gallery.ts │ ├── html │ └── index.html.template │ └── pages │ ├── Text │ └── remove-delete-add-create.markdown │ ├── automation │ ├── describe-action.markdown │ ├── describe-action.ts │ ├── describe-condition.markdown │ ├── describe-condition.ts │ ├── describe-trigger.markdown │ ├── describe-trigger.ts │ ├── editor-action.markdown │ ├── editor-action.ts │ ├── editor-condition.markdown │ ├── editor-condition.ts │ ├── editor-trigger.markdown │ ├── editor-trigger.ts │ ├── trace-timeline.markdown │ ├── trace-timeline.ts │ ├── trace.markdown │ └── trace.ts │ ├── brand │ ├── logo.markdown │ └── our-story.markdown │ ├── components │ ├── ha-alert.markdown │ ├── ha-alert.ts │ ├── ha-badge.markdown │ ├── ha-badge.ts │ ├── ha-bar.markdown │ ├── ha-bar.ts │ ├── ha-chips.markdown │ ├── ha-chips.ts │ ├── ha-control-button.markdown │ ├── ha-control-button.ts │ ├── ha-control-circular-slider.markdown │ ├── ha-control-circular-slider.ts │ ├── ha-control-number-buttons.markdown │ ├── ha-control-number-buttons.ts │ ├── ha-control-select-menu.markdown │ ├── ha-control-select-menu.ts │ ├── ha-control-select.markdown │ ├── ha-control-select.ts │ ├── ha-control-slider.markdown │ ├── ha-control-slider.ts │ ├── ha-control-switch.markdown │ ├── ha-control-switch.ts │ ├── ha-dialogs.markdown │ ├── ha-expansion-panel.markdown │ ├── ha-expansion-panel.ts │ ├── ha-faded.markdown │ ├── ha-faded.ts │ ├── ha-form.markdown │ ├── ha-form.ts │ ├── ha-gauge.markdown │ ├── ha-gauge.ts │ ├── ha-hs-color-picker.markdown │ ├── ha-hs-color-picker.ts │ ├── ha-label-badge.markdown │ ├── ha-label-badge.ts │ ├── ha-select-box.markdown │ ├── ha-select-box.ts │ ├── ha-selector.markdown │ ├── ha-selector.ts │ ├── ha-spinner.markdown │ ├── ha-spinner.ts │ ├── ha-switch.markdown │ ├── ha-switch.ts │ ├── ha-tip.markdown │ ├── ha-tip.ts │ ├── ha-tooltip.markdown │ └── ha-tooltip.ts │ ├── concepts │ └── home.markdown │ ├── date-time │ ├── date-time-numeric.markdown │ ├── date-time-numeric.ts │ ├── date-time-seconds.markdown │ ├── date-time-seconds.ts │ ├── date-time-short-year.markdown │ ├── date-time-short-year.ts │ ├── date-time-short.markdown │ ├── date-time-short.ts │ ├── date-time.markdown │ ├── date-time.ts │ ├── date.markdown │ ├── date.ts │ ├── time-seconds.markdown │ ├── time-seconds.ts │ ├── time-weekday.markdown │ ├── time-weekday.ts │ ├── time.markdown │ └── time.ts │ ├── design.home-assistant.io │ └── editing.markdown │ ├── lovelace │ ├── alarm-panel-card.markdown │ ├── alarm-panel-card.ts │ ├── area-card.markdown │ ├── area-card.ts │ ├── conditional-card.markdown │ ├── conditional-card.ts │ ├── entities-card.markdown │ ├── entities-card.ts │ ├── entity-button-card.markdown │ ├── entity-button-card.ts │ ├── entity-filter-card.markdown │ ├── entity-filter-card.ts │ ├── gauge-card.markdown │ ├── gauge-card.ts │ ├── glance-card.markdown │ ├── glance-card.ts │ ├── grid-and-stack-card.markdown │ ├── grid-and-stack-card.ts │ ├── iframe-card.markdown │ ├── iframe-card.ts │ ├── introduction.markdown │ ├── light-card.markdown │ ├── light-card.ts │ ├── map-card.markdown │ ├── map-card.ts │ ├── markdown-card.markdown │ ├── markdown-card.ts │ ├── media-control-card.markdown │ ├── media-control-card.ts │ ├── media-player-row.markdown │ ├── media-player-row.ts │ ├── picture-card.markdown │ ├── picture-card.ts │ ├── picture-elements-card.markdown │ ├── picture-elements-card.ts │ ├── picture-entity-card.markdown │ ├── picture-entity-card.ts │ ├── picture-glance-card.markdown │ ├── picture-glance-card.ts │ ├── plant-card.markdown │ ├── plant-card.ts │ ├── thermostat-card.markdown │ ├── thermostat-card.ts │ ├── tile-card.markdown │ ├── tile-card.ts │ ├── todo-list-card.markdown │ └── todo-list-card.ts │ ├── misc │ ├── entity-state.markdown │ ├── entity-state.ts │ ├── ha-markdown.markdown │ ├── ha-markdown.ts │ ├── integration-card.markdown │ ├── integration-card.ts │ ├── util-long-press.markdown │ └── util-long-press.ts │ ├── more-info │ ├── climate.markdown │ ├── climate.ts │ ├── cover.markdown │ ├── cover.ts │ ├── humidifier.markdown │ ├── humidifier.ts │ ├── input-number.markdown │ ├── input-number.ts │ ├── input-text.markdown │ ├── input-text.ts │ ├── light.markdown │ ├── light.ts │ ├── lock.markdown │ ├── lock.ts │ ├── media-player.markdown │ ├── media-player.ts │ ├── number.markdown │ ├── number.ts │ ├── scene.markdown │ ├── scene.ts │ ├── timer.markdown │ ├── timer.ts │ ├── update.markdown │ ├── update.ts │ ├── vacuum.markdown │ ├── vacuum.ts │ ├── water-heater.markdown │ └── water-heater.ts │ └── user-test │ ├── configuration-menu.markdown │ └── user-types.markdown ├── gulpfile.js ├── hassio ├── config.cjs ├── script │ ├── build_hassio │ └── develop └── src │ ├── addon-store │ ├── hassio-addon-repository.ts │ └── hassio-addon-store.ts │ ├── addon-view │ ├── config │ │ ├── hassio-addon-audio.ts │ │ ├── hassio-addon-config-tab.ts │ │ ├── hassio-addon-config.ts │ │ └── hassio-addon-network.ts │ ├── documentation │ │ └── hassio-addon-documentation-tab.ts │ ├── hassio-addon-dashboard.ts │ ├── hassio-addon-router.ts │ ├── info │ │ ├── hassio-addon-info-tab.ts │ │ ├── hassio-addon-info.ts │ │ └── hassio-addon-system-managed.ts │ └── log │ │ └── hassio-addon-log-tab.ts │ ├── backups │ └── hassio-backups.ts │ ├── components │ ├── hassio-card-content.ts │ ├── hassio-filter-addons.ts │ ├── hassio-upload-backup.ts │ ├── supervisor-backup-content.ts │ ├── supervisor-formfield-label.ts │ └── supervisor-metric.ts │ ├── dashboard │ ├── hassio-addons.ts │ ├── hassio-dashboard.ts │ └── hassio-update.ts │ ├── dialogs │ ├── backup │ │ ├── dialog-hassio-backup-location.ts │ │ ├── dialog-hassio-backup-upload.ts │ │ ├── dialog-hassio-backup.ts │ │ ├── dialog-hassio-create-backup.ts │ │ ├── show-dialog-backup-upload.ts │ │ ├── show-dialog-hassio-backu-location.ts │ │ ├── show-dialog-hassio-backup.ts │ │ └── show-dialog-hassio-create-backup.ts │ ├── datadisk │ │ ├── dialog-hassio-datadisk.ts │ │ └── show-dialog-hassio-datadisk.ts │ ├── hardware │ │ ├── dialog-hassio-hardware.ts │ │ └── show-dialog-hassio-hardware.ts │ ├── markdown │ │ ├── dialog-hassio-markdown.ts │ │ └── show-dialog-hassio-markdown.ts │ ├── network │ │ ├── dialog-hassio-network.ts │ │ └── show-dialog-network.ts │ ├── registries │ │ ├── dialog-hassio-registries.ts │ │ └── show-dialog-registries.ts │ ├── repositories │ │ ├── dialog-hassio-repositories.ts │ │ └── show-dialog-repositories.ts │ ├── suggestAddonRestart.ts │ └── system-managed │ │ ├── dialog-system-managed.ts │ │ └── show-dialog-system-managed.ts │ ├── entrypoint.js.template │ ├── entrypoint.ts │ ├── hassio-main.ts │ ├── hassio-my-redirect.ts │ ├── hassio-panel-router.ts │ ├── hassio-panel.ts │ ├── hassio-router.ts │ ├── hassio-tabs.ts │ ├── ingress-view │ └── hassio-ingress-view.ts │ ├── resources │ └── hassio-style.ts │ ├── supervisor-base-element.ts │ ├── system │ ├── hassio-core-info.ts │ ├── hassio-host-info.ts │ ├── hassio-supervisor-info.ts │ ├── hassio-supervisor-log.ts │ └── hassio-system.ts │ ├── update-available │ ├── update-available-card.ts │ └── update-available-dashboard.ts │ └── util │ └── addon.ts ├── landing-page ├── README.md ├── eslintrc.config.mjs ├── public │ └── static │ │ ├── icons │ │ ├── favicon-192x192.png │ │ ├── favicon.ico │ │ ├── logo_ohf.svg │ │ └── ohf.svg │ │ └── images │ │ ├── appstore.svg │ │ ├── logo_discord.png │ │ ├── logo_mastodon.svg │ │ ├── logo_x.svg │ │ ├── playstore.svg │ │ ├── qr-appstore.svg │ │ └── qr-playstore.svg ├── script │ ├── build_landing_page │ └── develop └── src │ ├── components │ ├── landing-page-logs.ts │ └── landing-page-network.ts │ ├── data │ ├── observer.ts │ └── supervisor.ts │ ├── entrypoint.js │ ├── ha-landing-page.ts │ ├── html │ └── index.html.template │ └── landing-page-base-element.ts ├── lint-staged.config.js ├── netlify.toml ├── package.json ├── prettier.config.js ├── public ├── __init__.py ├── py.typed ├── robots.txt └── static │ ├── icons │ ├── browserconfig.xml │ ├── favicon-1024x1024.png │ ├── favicon-16x16.png │ ├── favicon-192x192.png │ ├── favicon-32x32.png │ ├── favicon-384x384.png │ ├── favicon-512x512.png │ ├── favicon-apple-180x180.png │ ├── favicon.ico │ ├── logo_ohf.svg │ ├── mask-icon.svg │ ├── maskable_icon-128x128.png │ ├── maskable_icon-192x192.png │ ├── maskable_icon-384x384.png │ ├── maskable_icon-48x48.png │ ├── maskable_icon-512x512.png │ ├── maskable_icon-72x72.png │ ├── maskable_icon-96x96.png │ ├── ohf.svg │ ├── tile-win-150x150.png │ ├── tile-win-310x150.png │ ├── tile-win-310x310.png │ └── tile-win-70x70.png │ └── images │ ├── appstore.svg │ ├── card_media_player_bg.png │ ├── color_wheel.png │ ├── config_ecobee_thermostat.png │ ├── config_fitbit_app.png │ ├── config_flows │ └── config_homematicip_cloud.png │ ├── config_freebox.png │ ├── config_icloud.png │ ├── config_insteon.png │ ├── config_philips_hue.jpg │ ├── config_webos.png │ ├── config_wink.png │ ├── darksky │ ├── weather-cloudy.svg │ ├── weather-fog.svg │ ├── weather-hail.svg │ ├── weather-night.svg │ ├── weather-partlycloudy.svg │ ├── weather-pouring.svg │ ├── weather-rainy.svg │ ├── weather-snowy.svg │ ├── weather-sunny.svg │ └── weather-windy.svg │ ├── form │ ├── markdown_card.svg │ ├── markdown_card_dark.svg │ ├── markdown_text_only.svg │ ├── markdown_text_only_dark.svg │ ├── tile_content_layout_horizontal.svg │ ├── tile_content_layout_horizontal_dark.svg │ ├── tile_content_layout_vertical.svg │ ├── tile_content_layout_vertical_dark.svg │ ├── tile_features_position_bottom.svg │ ├── tile_features_position_bottom_dark.svg │ ├── tile_features_position_inline.svg │ ├── tile_features_position_inline_dark.svg │ ├── view_header_badges_position_bottom.svg │ ├── view_header_badges_position_bottom_dark.svg │ ├── view_header_badges_position_top.svg │ ├── view_header_badges_position_top_dark.svg │ ├── view_header_badges_wrap_scroll.svg │ ├── view_header_badges_wrap_scroll_dark.svg │ ├── view_header_badges_wrap_wrap.svg │ ├── view_header_badges_wrap_wrap_dark.svg │ ├── view_header_layout_center.svg │ ├── view_header_layout_center_dark.svg │ ├── view_header_layout_responsive.svg │ ├── view_header_layout_responsive_dark.svg │ ├── view_header_layout_start.svg │ └── view_header_layout_start_dark.svg │ ├── image-broken.svg │ ├── logo_apple_home.png │ ├── logo_automatic.png │ ├── logo_axis.png │ ├── logo_deconz.jpeg │ ├── logo_discord.png │ ├── logo_google_home.png │ ├── logo_mastodon.svg │ ├── logo_nabu_casa.png │ ├── logo_nabu_casa_dark.png │ ├── logo_philips_hue.png │ ├── logo_plex_mediaserver.png │ ├── logo_x.svg │ ├── notification-badge.png │ ├── ohf-badge.svg │ ├── playstore.svg │ ├── qr-appstore.svg │ ├── qr-playstore.svg │ ├── screenshots │ └── screenshot-1.png │ ├── smart-tv.png │ ├── voice-assistant │ ├── area.png │ ├── change-wake-word.png │ ├── error.png │ ├── great-job.png │ ├── heart.png │ ├── hi.png │ ├── ok-nabu.png │ ├── sleep.png │ └── update.png │ └── z-wave-add-node │ ├── long-range.svg │ ├── long-range_dark.svg │ ├── mesh.svg │ └── mesh_dark.svg ├── pyproject.toml ├── renovate.json ├── rspack.config.cjs ├── script ├── bootstrap ├── build_frontend ├── core ├── develop ├── develop_and_serve ├── release ├── serve-config.json ├── setup ├── setup_translations ├── size_stats ├── translations_download ├── translations_upload_base └── version_bump.js ├── src ├── auth │ ├── ha-auth-flow.ts │ ├── ha-auth-form-string.ts │ ├── ha-auth-form.ts │ ├── ha-auth-textfield.ts │ ├── ha-authorize.ts │ └── ha-pick-auth-provider.ts ├── cast │ ├── cast_framework.ts │ ├── cast_manager.ts │ ├── const.ts │ ├── dev_const.ts │ ├── receiver_messages.ts │ ├── sender_messages.ts │ └── types.ts ├── common │ ├── array │ │ ├── combinations.ts │ │ ├── ensure-array.ts │ │ └── literal-includes.ts │ ├── auth │ │ └── token_storage.ts │ ├── color │ │ ├── colors.ts │ │ ├── compute-color.ts │ │ ├── convert-color.ts │ │ ├── convert-light-color.ts │ │ ├── hex.ts │ │ ├── lab.ts │ │ └── rgb.ts │ ├── config │ │ ├── can_show_page.ts │ │ ├── components_with_service.ts │ │ ├── is_component_loaded.ts │ │ ├── is_pwa.ts │ │ ├── is_service_loaded.ts │ │ ├── location_name.ts │ │ └── version.ts │ ├── const.ts │ ├── controllers │ │ └── drag-scroll-controller.ts │ ├── datetime │ │ ├── absolute_time.ts │ │ ├── calc_date.ts │ │ ├── calc_date_range.ts │ │ ├── check_valid_date.ts │ │ ├── create_duration_data.ts │ │ ├── duration_to_seconds.ts │ │ ├── first_weekday.ts │ │ ├── format_date.ts │ │ ├── format_date_time.ts │ │ ├── format_duration.ts │ │ ├── format_time.ts │ │ ├── localize_date.ts │ │ ├── milliseconds_to_duration.ts │ │ ├── relative_time.ts │ │ ├── resolve-time-zone.ts │ │ ├── seconds_to_duration.ts │ │ └── use_am_pm.ts │ ├── decorators │ │ ├── restore-scroll.ts │ │ ├── storage.ts │ │ └── transform.ts │ ├── dom │ │ ├── ancestors-with-property.ts │ │ ├── apply_themes_on_element.ts │ │ ├── can-override-input.ts │ │ ├── deep-active-element.ts │ │ ├── dynamic-element-directive.ts │ │ ├── fire_event.ts │ │ ├── get_main_window.ts │ │ ├── is-navigation-click.ts │ │ ├── load_resource.ts │ │ ├── media_query.ts │ │ ├── prevent_default.ts │ │ ├── scroll-to-target.ts │ │ ├── setup-leaflet-map.ts │ │ ├── stop_propagation.ts │ │ └── toggle_attribute.ts │ ├── empty_image_base64.ts │ ├── entity │ │ ├── attribute_class_names.ts │ │ ├── battery_icon.ts │ │ ├── can_toggle_domain.ts │ │ ├── can_toggle_state.ts │ │ ├── color │ │ │ └── battery_color.ts │ │ ├── compute_area_name.ts │ │ ├── compute_attribute_display.ts │ │ ├── compute_device_name.ts │ │ ├── compute_domain.ts │ │ ├── compute_entity_name.ts │ │ ├── compute_floor_name.ts │ │ ├── compute_object_id.ts │ │ ├── compute_state_display.ts │ │ ├── compute_state_domain.ts │ │ ├── compute_state_name.ts │ │ ├── context │ │ │ ├── get_area_context.ts │ │ │ ├── get_device_context.ts │ │ │ └── get_entity_context.ts │ │ ├── cover_icon.ts │ │ ├── delete_entity.ts │ │ ├── device_tracker_icon.ts │ │ ├── entity_domain_filter.ts │ │ ├── entity_filter.ts │ │ ├── extract_views.ts │ │ ├── feature_class_names.ts │ │ ├── get_group_entities.ts │ │ ├── get_states.ts │ │ ├── get_view_entities.ts │ │ ├── has_location.ts │ │ ├── split_by_groups.ts │ │ ├── state_active.ts │ │ ├── state_card_type.ts │ │ ├── state_color.ts │ │ ├── state_icon.ts │ │ ├── states_sort_by_name.ts │ │ ├── strip_prefix_from_entity_name.ts │ │ ├── supports-feature.ts │ │ ├── update_icon.ts │ │ ├── valid_entity_id.ts │ │ └── valid_service_id.ts │ ├── feature-detect │ │ └── support-web-components.ts │ ├── image │ │ └── extract_color.ts │ ├── integrations │ │ └── protocolIntegrationPicked.ts │ ├── language │ │ └── format_language.ts │ ├── location │ │ └── add_distance_to_coord.ts │ ├── map │ │ └── decorated_marker.ts │ ├── mwc │ │ └── handle-request-selected-event.ts │ ├── navigate.ts │ ├── number │ │ ├── clamp.ts │ │ ├── format_number.ts │ │ └── round.ts │ ├── string │ │ ├── capitalize-first-letter.ts │ │ ├── compare.ts │ │ ├── escape_regexp.ts │ │ ├── filter │ │ │ ├── char-code.ts │ │ │ ├── filter.ts │ │ │ └── sequence-matching.ts │ │ ├── format-list.ts │ │ ├── get_duplicates.ts │ │ ├── has-template.ts │ │ ├── is_date.ts │ │ ├── is_ip_address.ts │ │ ├── is_timestamp.ts │ │ ├── slugify.ts │ │ ├── starts-with.ts │ │ ├── strip-diacritics.ts │ │ └── title-case.ts │ ├── structs │ │ ├── handle-errors.ts │ │ ├── is-custom-type.ts │ │ └── is-icon.ts │ ├── style │ │ ├── derived-css-vars.ts │ │ └── icon_color_css.ts │ ├── translations │ │ ├── auto_case_noun.ts │ │ ├── blank_before_percent.ts │ │ ├── blank_before_unit.ts │ │ ├── day_names.ts │ │ ├── entity-state.ts │ │ ├── localize.ts │ │ ├── markdown_support.ts │ │ └── month_names.ts │ ├── url │ │ ├── construct-url.ts │ │ └── search-params.ts │ └── util │ │ ├── compute_rtl.ts │ │ ├── copy-clipboard.ts │ │ ├── debounce.ts │ │ ├── deep-equal.ts │ │ ├── group-by.ts │ │ ├── parse-aspect-ratio.ts │ │ ├── patch.ts │ │ ├── promise-all-settled-results.ts │ │ ├── promise-timeout.ts │ │ ├── render-status.ts │ │ ├── select-unit.ts │ │ ├── shallow-equal.ts │ │ ├── subscribe-one.ts │ │ ├── subscribe-polling.ts │ │ ├── throttle.ts │ │ ├── time-cache-entity-promise-func.ts │ │ ├── time-cache-function-promise.ts │ │ ├── uid.ts │ │ └── wait.ts ├── components │ ├── buttons │ │ ├── ha-call-service-button.ts │ │ └── ha-progress-button.ts │ ├── chart │ │ ├── axis-label.ts │ │ ├── down-sample.ts │ │ ├── ha-chart-base.ts │ │ ├── ha-network-graph.ts │ │ ├── ha-sankey-chart.ts │ │ ├── state-history-chart-line.ts │ │ ├── state-history-chart-timeline.ts │ │ ├── state-history-charts.ts │ │ ├── statistics-chart.ts │ │ └── timeline-color.ts │ ├── chips │ │ ├── ha-assist-chip.ts │ │ ├── ha-chip-set.ts │ │ ├── ha-filter-chip.ts │ │ └── ha-input-chip.ts │ ├── data-table │ │ ├── dialog-data-table-settings.ts │ │ ├── ha-data-table-icon.ts │ │ ├── ha-data-table-labels.ts │ │ ├── ha-data-table.ts │ │ ├── show-dialog-data-table-settings.ts │ │ ├── sort-filter-worker.ts │ │ └── sort-filter.ts │ ├── date-range-picker.ts │ ├── device │ │ ├── ha-device-action-picker.ts │ │ ├── ha-device-automation-picker.ts │ │ ├── ha-device-condition-picker.ts │ │ ├── ha-device-picker.ts │ │ ├── ha-device-trigger-picker.ts │ │ └── ha-devices-picker.ts │ ├── entity │ │ ├── ha-battery-icon.ts │ │ ├── ha-entities-picker.ts │ │ ├── ha-entity-attribute-picker.ts │ │ ├── ha-entity-picker.ts │ │ ├── ha-entity-state-content-picker.ts │ │ ├── ha-entity-state-picker.ts │ │ ├── ha-entity-toggle.ts │ │ ├── ha-state-label-badge.ts │ │ ├── ha-statistic-picker.ts │ │ ├── ha-statistics-picker.ts │ │ ├── state-badge.ts │ │ └── state-info.ts │ ├── ha-absolute-time.ts │ ├── ha-addon-picker.ts │ ├── ha-alert.ts │ ├── ha-aliases-editor.ts │ ├── ha-analytics.ts │ ├── ha-ansi-to-html.ts │ ├── ha-area-floor-picker.ts │ ├── ha-area-picker.ts │ ├── ha-areas-display-editor.ts │ ├── ha-areas-picker.ts │ ├── ha-assist-chat.ts │ ├── ha-assist-pipeline-picker.ts │ ├── ha-attribute-icon.ts │ ├── ha-attribute-value.ts │ ├── ha-attributes.ts │ ├── ha-badge.ts │ ├── ha-bar.ts │ ├── ha-base-time-input.ts │ ├── ha-big-number.ts │ ├── ha-blueprint-picker.ts │ ├── ha-button-menu.ts │ ├── ha-button-toggle-group.ts │ ├── ha-button.ts │ ├── ha-camera-stream.ts │ ├── ha-card.ts │ ├── ha-check-list-item.ts │ ├── ha-checkbox.ts │ ├── ha-climate-state.ts │ ├── ha-code-editor.ts │ ├── ha-color-picker.ts │ ├── ha-combo-box-item.ts │ ├── ha-combo-box-textfield.ts │ ├── ha-combo-box.ts │ ├── ha-config-entry-picker.ts │ ├── ha-control-button-group.ts │ ├── ha-control-button.ts │ ├── ha-control-circular-slider.ts │ ├── ha-control-number-buttons.ts │ ├── ha-control-select-menu.ts │ ├── ha-control-select.ts │ ├── ha-control-slider.ts │ ├── ha-control-switch.ts │ ├── ha-conversation-agent-picker.ts │ ├── ha-copy-textfield.ts │ ├── ha-country-picker.ts │ ├── ha-cover-controls.ts │ ├── ha-cover-tilt-controls.ts │ ├── ha-currency-picker.ts │ ├── ha-date-input.ts │ ├── ha-date-range-picker.ts │ ├── ha-dialog-date-picker.ts │ ├── ha-dialog-header.ts │ ├── ha-dialog.ts │ ├── ha-divider.ts │ ├── ha-domain-icon.ts │ ├── ha-drawer.ts │ ├── ha-duration-input.ts │ ├── ha-entities-display-editor.ts │ ├── ha-expansion-panel.ts │ ├── ha-fab.ts │ ├── ha-fade-in.ts │ ├── ha-faded.ts │ ├── ha-file-upload.ts │ ├── ha-filter-blueprints.ts │ ├── ha-filter-categories.ts │ ├── ha-filter-devices.ts │ ├── ha-filter-domains.ts │ ├── ha-filter-entities.ts │ ├── ha-filter-floor-areas.ts │ ├── ha-filter-integrations.ts │ ├── ha-filter-labels.ts │ ├── ha-filter-states.ts │ ├── ha-floor-icon.ts │ ├── ha-floor-picker.ts │ ├── ha-floors-picker.ts │ ├── ha-form │ │ ├── compute-initial-ha-form-data.ts │ │ ├── ha-form-boolean.ts │ │ ├── ha-form-constant.ts │ │ ├── ha-form-expandable.ts │ │ ├── ha-form-float.ts │ │ ├── ha-form-grid.ts │ │ ├── ha-form-integer.ts │ │ ├── ha-form-multi_select.ts │ │ ├── ha-form-optional_actions.ts │ │ ├── ha-form-positive_time_period_dict.ts │ │ ├── ha-form-select.ts │ │ ├── ha-form-string.ts │ │ ├── ha-form.ts │ │ └── types.ts │ ├── ha-formfield.ts │ ├── ha-gauge.ts │ ├── ha-generic-picker.ts │ ├── ha-grid-size-picker.ts │ ├── ha-header-bar.ts │ ├── ha-heading-badge.ts │ ├── ha-help-tooltip.ts │ ├── ha-hls-player.ts │ ├── ha-hs-color-picker.ts │ ├── ha-humidifier-state.ts │ ├── ha-icon-button-arrow-next.ts │ ├── ha-icon-button-arrow-prev.ts │ ├── ha-icon-button-group.ts │ ├── ha-icon-button-next.ts │ ├── ha-icon-button-prev.ts │ ├── ha-icon-button-toggle.ts │ ├── ha-icon-button.ts │ ├── ha-icon-next.ts │ ├── ha-icon-overflow-menu.ts │ ├── ha-icon-picker.ts │ ├── ha-icon-prev.ts │ ├── ha-icon.ts │ ├── ha-input-helper-text.ts │ ├── ha-items-display-editor.ts │ ├── ha-label-badge.ts │ ├── ha-label-picker.ts │ ├── ha-label.ts │ ├── ha-labeled-slider.ts │ ├── ha-labels-picker.ts │ ├── ha-language-picker.ts │ ├── ha-lawn_mower-action-button.ts │ ├── ha-list-item.ts │ ├── ha-list.ts │ ├── ha-logo-svg.ts │ ├── ha-markdown-element.ts │ ├── ha-markdown.ts │ ├── ha-md-button-menu.ts │ ├── ha-md-dialog.ts │ ├── ha-md-divider.ts │ ├── ha-md-list-item.ts │ ├── ha-md-list.ts │ ├── ha-md-menu-item.ts │ ├── ha-md-menu.ts │ ├── ha-md-select-option.ts │ ├── ha-md-select.ts │ ├── ha-md-textfield.ts │ ├── ha-menu-button.ts │ ├── ha-menu.ts │ ├── ha-metric.ts │ ├── ha-mount-picker.ts │ ├── ha-multi-textfield.ts │ ├── ha-navigation-list.ts │ ├── ha-navigation-picker.ts │ ├── ha-network.ts │ ├── ha-outlined-button.ts │ ├── ha-outlined-field.ts │ ├── ha-outlined-icon-button.ts │ ├── ha-outlined-text-field.ts │ ├── ha-password-field.ts │ ├── ha-picker-combo-box.ts │ ├── ha-picker-field.ts │ ├── ha-picture-upload.ts │ ├── ha-progress-ring.ts │ ├── ha-push-notifications-toggle.ts │ ├── ha-qr-code.ts │ ├── ha-qr-scanner.ts │ ├── ha-radio-list-item.ts │ ├── ha-radio.ts │ ├── ha-related-items.ts │ ├── ha-relative-time.ts │ ├── ha-ripple.ts │ ├── ha-select-box.ts │ ├── ha-select.ts │ ├── ha-selector │ │ ├── ha-selector-action.ts │ │ ├── ha-selector-addon.ts │ │ ├── ha-selector-area.ts │ │ ├── ha-selector-areas-display.ts │ │ ├── ha-selector-assist-pipeline.ts │ │ ├── ha-selector-attribute.ts │ │ ├── ha-selector-background.ts │ │ ├── ha-selector-backup-location.ts │ │ ├── ha-selector-boolean.ts │ │ ├── ha-selector-button-toggle.ts │ │ ├── ha-selector-color-rgb.ts │ │ ├── ha-selector-color-temp.ts │ │ ├── ha-selector-condition.ts │ │ ├── ha-selector-config-entry.ts │ │ ├── ha-selector-constant.ts │ │ ├── ha-selector-conversation-agent.ts │ │ ├── ha-selector-country.ts │ │ ├── ha-selector-date.ts │ │ ├── ha-selector-datetime.ts │ │ ├── ha-selector-device.ts │ │ ├── ha-selector-duration.ts │ │ ├── ha-selector-entity.ts │ │ ├── ha-selector-file.ts │ │ ├── ha-selector-floor.ts │ │ ├── ha-selector-icon.ts │ │ ├── ha-selector-image.ts │ │ ├── ha-selector-label.ts │ │ ├── ha-selector-language.ts │ │ ├── ha-selector-location.ts │ │ ├── ha-selector-media.ts │ │ ├── ha-selector-navigation.ts │ │ ├── ha-selector-number.ts │ │ ├── ha-selector-object.ts │ │ ├── ha-selector-qr-code.ts │ │ ├── ha-selector-select.ts │ │ ├── ha-selector-selector.ts │ │ ├── ha-selector-state.ts │ │ ├── ha-selector-statistic.ts │ │ ├── ha-selector-stt.ts │ │ ├── ha-selector-target.ts │ │ ├── ha-selector-template.ts │ │ ├── ha-selector-text.ts │ │ ├── ha-selector-theme.ts │ │ ├── ha-selector-time.ts │ │ ├── ha-selector-trigger.ts │ │ ├── ha-selector-tts-voice.ts │ │ ├── ha-selector-tts.ts │ │ ├── ha-selector-ui-action.ts │ │ ├── ha-selector-ui-color.ts │ │ ├── ha-selector-ui-state-content.ts │ │ └── ha-selector.ts │ ├── ha-service-control.ts │ ├── ha-service-icon.ts │ ├── ha-service-picker.ts │ ├── ha-service-section-icon.ts │ ├── ha-settings-row.ts │ ├── ha-sidebar.ts │ ├── ha-slider.ts │ ├── ha-sortable.ts │ ├── ha-spinner.ts │ ├── ha-state-icon.ts │ ├── ha-stt-picker.ts │ ├── ha-sub-menu.ts │ ├── ha-svg-icon.ts │ ├── ha-switch.ts │ ├── ha-tab.ts │ ├── ha-target-picker.ts │ ├── ha-textarea.ts │ ├── ha-textfield.ts │ ├── ha-theme-picker.ts │ ├── ha-time-input.ts │ ├── ha-timezone-picker.ts │ ├── ha-tip.ts │ ├── ha-toast.ts │ ├── ha-tooltip.ts │ ├── ha-top-app-bar-fixed.ts │ ├── ha-top-app-bar.ts │ ├── ha-tree-indicator.ts │ ├── ha-tts-picker.ts │ ├── ha-tts-voice-picker.ts │ ├── ha-two-pane-top-app-bar-fixed.ts │ ├── ha-vacuum-state.ts │ ├── ha-valve-controls.ts │ ├── ha-water_heater-state.ts │ ├── ha-web-rtc-player.ts │ ├── ha-yaml-editor.ts │ ├── map │ │ ├── ha-entity-marker.ts │ │ ├── ha-locations-editor.ts │ │ └── ha-map.ts │ ├── media-player │ │ ├── dialog-join-media-players.ts │ │ ├── dialog-media-manage.ts │ │ ├── dialog-media-player-browse.ts │ │ ├── ha-browse-media-tts.ts │ │ ├── ha-media-manage-button.ts │ │ ├── ha-media-player-browse.ts │ │ ├── ha-media-player-toggle.ts │ │ ├── ha-media-upload-button.ts │ │ ├── show-join-media-players-dialog.ts │ │ ├── show-media-browser-dialog.ts │ │ └── show-media-manage-dialog.ts │ ├── search-input-outlined.ts │ ├── search-input.ts │ ├── sl-tab-group.ts │ ├── tile │ │ ├── ha-tile-badge.ts │ │ ├── ha-tile-icon.ts │ │ └── ha-tile-info.ts │ ├── timezone-datalist.ts │ ├── trace │ │ ├── ha-timeline.ts │ │ ├── ha-trace-blueprint-config.ts │ │ ├── ha-trace-config.ts │ │ ├── ha-trace-logbook.ts │ │ ├── ha-trace-path-details.ts │ │ ├── ha-trace-timeline.ts │ │ ├── hat-graph-branch.ts │ │ ├── hat-graph-const.ts │ │ ├── hat-graph-node.ts │ │ ├── hat-graph-spacer.ts │ │ ├── hat-logbook-note.ts │ │ ├── hat-script-graph.ts │ │ ├── hat-trace-timeline.ts │ │ └── trace-tab-styles.ts │ └── user │ │ ├── ha-person-badge.ts │ │ ├── ha-user-badge.ts │ │ ├── ha-user-picker.ts │ │ └── ha-users-picker.ts ├── data │ ├── action.ts │ ├── alarm_control_panel.ts │ ├── alexa.ts │ ├── analytics.ts │ ├── application_credential.ts │ ├── area_registry.ts │ ├── assist_pipeline.ts │ ├── assist_satellite.ts │ ├── auth.ts │ ├── automation.ts │ ├── automation_i18n.ts │ ├── backup.ts │ ├── backup_manager.ts │ ├── backup_onboarding.ts │ ├── blueprint.ts │ ├── bluetooth.ts │ ├── bootstrap_integrations.ts │ ├── calendar.ts │ ├── camera.ts │ ├── category_registry.ts │ ├── climate.ts │ ├── cloud.ts │ ├── cloud │ │ └── tts.ts │ ├── collection.ts │ ├── condition.ts │ ├── config.ts │ ├── config_entries.ts │ ├── config_flow.ts │ ├── connection-status.ts │ ├── context.ts │ ├── conversation.ts │ ├── core.ts │ ├── counter.ts │ ├── cover.ts │ ├── currency.ts │ ├── custom_icons.ts │ ├── custom_iconsets.ts │ ├── data_entry_flow.ts │ ├── data_table_filters.ts │ ├── date.ts │ ├── datetime.ts │ ├── device_automation.ts │ ├── device_registry.ts │ ├── dhcp.ts │ ├── diagnostics.ts │ ├── energy.ts │ ├── entity.ts │ ├── entity_attributes.ts │ ├── entity_registry.ts │ ├── entity_sources.ts │ ├── error_log.ts │ ├── expose.ts │ ├── external.ts │ ├── fan.ts │ ├── file_upload.ts │ ├── floor_registry.ts │ ├── frontend.ts │ ├── google_assistant.ts │ ├── graph.ts │ ├── group.ts │ ├── haptics.ts │ ├── hardware.ts │ ├── hassio │ │ ├── addon.ts │ │ ├── backup.ts │ │ ├── common.ts │ │ ├── docker.ts │ │ ├── hardware.ts │ │ ├── host.ts │ │ ├── ingress.ts │ │ ├── network.ts │ │ ├── resolution.ts │ │ └── supervisor.ts │ ├── helpers_crud.ts │ ├── history.ts │ ├── humidifier.ts │ ├── icons.ts │ ├── iconsets.ts │ ├── image.ts │ ├── image_upload.ts │ ├── input_boolean.ts │ ├── input_button.ts │ ├── input_datetime.ts │ ├── input_number.ts │ ├── input_select.ts │ ├── input_text.ts │ ├── integration.ts │ ├── integration_quality_scale.ts │ ├── integrations.ts │ ├── label_registry.ts │ ├── lawn_mower.ts │ ├── light.ts │ ├── lock.ts │ ├── logbook.ts │ ├── lovelace.ts │ ├── lovelace │ │ ├── action_handler.ts │ │ ├── config │ │ │ ├── action.ts │ │ │ ├── badge.ts │ │ │ ├── card.ts │ │ │ ├── section.ts │ │ │ ├── strategy.ts │ │ │ ├── types.ts │ │ │ └── view.ts │ │ ├── dashboard.ts │ │ └── resource.ts │ ├── lovelace_custom_cards.ts │ ├── main_window.ts │ ├── matter.ts │ ├── media-player.ts │ ├── media_source.ts │ ├── mqtt.ts │ ├── network.ts │ ├── notify_html5.ts │ ├── number.ts │ ├── onboarding.ts │ ├── openstreetmap.ts │ ├── options_flow.ts │ ├── otbr.ts │ ├── panel.ts │ ├── panel_custom.ts │ ├── persistent_notification.ts │ ├── person.ts │ ├── preloads.ts │ ├── preview.ts │ ├── recorder.ts │ ├── refresh_token.ts │ ├── regenerate_entity_ids.ts │ ├── registry.ts │ ├── remote.ts │ ├── repairs.ts │ ├── scene.ts │ ├── schedule.ts │ ├── script.ts │ ├── script_i18n.ts │ ├── search.ts │ ├── select.ts │ ├── selector.ts │ ├── sensor.ts │ ├── service.ts │ ├── siren.ts │ ├── ssdp.ts │ ├── stt.ts │ ├── sub_config_flow.ts │ ├── supervisor │ │ ├── common.ts │ │ ├── core.ts │ │ ├── mounts.ts │ │ ├── store.ts │ │ ├── supervisor.ts │ │ └── update.ts │ ├── system_health.ts │ ├── system_log.ts │ ├── tag.ts │ ├── text.ts │ ├── thread.ts │ ├── time.ts │ ├── timer.ts │ ├── todo.ts │ ├── trace.ts │ ├── translation.ts │ ├── trigger.ts │ ├── tts.ts │ ├── update.ts │ ├── usb.ts │ ├── user.ts │ ├── vacuum.ts │ ├── valve.ts │ ├── wake_word.ts │ ├── water_heater.ts │ ├── weather.ts │ ├── webhook.ts │ ├── websocket_api.ts │ ├── ws-area_registry.ts │ ├── ws-device_registry.ts │ ├── ws-entity_registry_display.ts │ ├── ws-floor_registry.ts │ ├── ws-panels.ts │ ├── ws-templates.ts │ ├── ws-themes.ts │ ├── ws-user.ts │ ├── wyoming.ts │ ├── zeroconf.ts │ ├── zha.ts │ ├── zone.ts │ └── zwave_js.ts ├── dialogs │ ├── config-entry-system-options │ │ ├── dialog-config-entry-system-options.ts │ │ └── show-dialog-config-entry-system-options.ts │ ├── config-flow │ │ ├── dialog-data-entry-flow.ts │ │ ├── previews │ │ │ ├── entity-preview-row.ts │ │ │ ├── flow-preview-generic.ts │ │ │ ├── flow-preview-generic_camera.ts │ │ │ └── flow-preview-template.ts │ │ ├── show-dialog-config-flow.ts │ │ ├── show-dialog-data-entry-flow.ts │ │ ├── show-dialog-options-flow.ts │ │ ├── show-dialog-sub-config-flow.ts │ │ ├── step-flow-abort.ts │ │ ├── step-flow-create-entry.ts │ │ ├── step-flow-external.ts │ │ ├── step-flow-form.ts │ │ ├── step-flow-loading.ts │ │ ├── step-flow-menu.ts │ │ ├── step-flow-progress.ts │ │ └── styles.ts │ ├── enter-code │ │ ├── dialog-enter-code.ts │ │ └── show-enter-code-dialog.ts │ ├── generic │ │ ├── dialog-box.ts │ │ └── show-dialog-box.ts │ ├── image-cropper-dialog │ │ ├── image-cropper-dialog.ts │ │ └── show-image-cropper-dialog.ts │ ├── make-dialog-manager.ts │ ├── more-info │ │ ├── components │ │ │ ├── ha-more-info-control-select-container.ts │ │ │ ├── ha-more-info-state-header.ts │ │ │ ├── lights │ │ │ │ ├── dialog-light-color-favorite.ts │ │ │ │ ├── ha-favorite-color-button.ts │ │ │ │ ├── ha-more-info-light-favorite-colors.ts │ │ │ │ ├── light-color-rgb-picker.ts │ │ │ │ ├── light-color-temp-picker.ts │ │ │ │ └── show-dialog-light-color-favorite.ts │ │ │ ├── more-info-control-style.ts │ │ │ ├── siren │ │ │ │ ├── ha-more-info-siren-advanced-controls.ts │ │ │ │ └── show-dialog-siren-advanced-controls.ts │ │ │ └── voice │ │ │ │ ├── ha-more-info-view-voice-assistants.ts │ │ │ │ └── show-view-voice-assistants.ts │ │ ├── const.ts │ │ ├── controls │ │ │ ├── more-info-alarm_control_panel.ts │ │ │ ├── more-info-automation.ts │ │ │ ├── more-info-camera.ts │ │ │ ├── more-info-climate.ts │ │ │ ├── more-info-configurator.ts │ │ │ ├── more-info-conversation.ts │ │ │ ├── more-info-counter.ts │ │ │ ├── more-info-cover.ts │ │ │ ├── more-info-date.ts │ │ │ ├── more-info-datetime.ts │ │ │ ├── more-info-default.ts │ │ │ ├── more-info-fan.ts │ │ │ ├── more-info-group.ts │ │ │ ├── more-info-humidifier.ts │ │ │ ├── more-info-image.ts │ │ │ ├── more-info-input_boolean.ts │ │ │ ├── more-info-input_datetime.ts │ │ │ ├── more-info-lawn_mower.ts │ │ │ ├── more-info-light.ts │ │ │ ├── more-info-lock.ts │ │ │ ├── more-info-media_player.ts │ │ │ ├── more-info-person.ts │ │ │ ├── more-info-remote.ts │ │ │ ├── more-info-script.ts │ │ │ ├── more-info-siren.ts │ │ │ ├── more-info-sun.ts │ │ │ ├── more-info-switch.ts │ │ │ ├── more-info-time.ts │ │ │ ├── more-info-timer.ts │ │ │ ├── more-info-update.ts │ │ │ ├── more-info-vacuum.ts │ │ │ ├── more-info-valve.ts │ │ │ ├── more-info-water_heater.ts │ │ │ └── more-info-weather.ts │ │ ├── ha-more-info-dialog.ts │ │ ├── ha-more-info-history-and-logbook.ts │ │ ├── ha-more-info-history.ts │ │ ├── ha-more-info-info.ts │ │ ├── ha-more-info-logbook.ts │ │ ├── ha-more-info-settings.ts │ │ ├── more-info-content.ts │ │ ├── show-ha-more-info-dialog.ts │ │ └── state_more_info_control.ts │ ├── notifications │ │ ├── configurator-notification-item.ts │ │ ├── notification-drawer.ts │ │ ├── notification-item-template.ts │ │ ├── notification-item.ts │ │ ├── persistent-notification-item.ts │ │ └── show-notification-drawer.ts │ ├── quick-bar │ │ ├── ha-quick-bar.ts │ │ └── show-dialog-quick-bar.ts │ ├── restart │ │ ├── dialog-restart-wait.ts │ │ ├── dialog-restart.ts │ │ └── show-dialog-restart.ts │ ├── shortcuts │ │ ├── dialog-shortcuts.ts │ │ └── show-shortcuts-dialog.ts │ ├── sidebar │ │ ├── dialog-edit-sidebar.ts │ │ └── show-dialog-edit-sidebar.ts │ ├── tts-try │ │ ├── dialog-tts-try.ts │ │ └── show-dialog-tts-try.ts │ ├── update_backup │ │ ├── dialog-update-backup.ts │ │ └── show-update-backup-dialog.ts │ ├── voice-assistant-setup │ │ ├── cloud │ │ │ ├── cloud-step-intro.ts │ │ │ ├── cloud-step-signin.ts │ │ │ └── cloud-step-signup.ts │ │ ├── show-voice-assistant-setup-dialog.ts │ │ ├── styles.ts │ │ ├── voice-assistant-setup-dialog.ts │ │ ├── voice-assistant-setup-step-area.ts │ │ ├── voice-assistant-setup-step-change-wake-word.ts │ │ ├── voice-assistant-setup-step-check.ts │ │ ├── voice-assistant-setup-step-cloud.ts │ │ ├── voice-assistant-setup-step-local.ts │ │ ├── voice-assistant-setup-step-pipeline.ts │ │ ├── voice-assistant-setup-step-success.ts │ │ ├── voice-assistant-setup-step-update.ts │ │ └── voice-assistant-setup-step-wake-word.ts │ └── voice-command-dialog │ │ ├── ha-voice-command-dialog.ts │ │ └── show-ha-voice-command-dialog.ts ├── entrypoints │ ├── app.ts │ ├── authorize.ts │ ├── core.ts │ ├── custom-panel.ts │ ├── onboarding.ts │ └── service-worker.ts ├── external_app │ ├── external_app_entrypoint.ts │ ├── external_auth.ts │ └── external_messaging.ts ├── fake_data │ ├── demo_config.ts │ ├── demo_panels.ts │ ├── demo_services.ts │ ├── entity.ts │ ├── entity_component_icons.ts │ └── provide_hass.ts ├── html │ ├── _header.html.template │ ├── _js_base.html.template │ ├── _preload_roboto.html.template │ ├── _script_loader.html.template │ ├── _style_base.html.template │ ├── authorize.html.template │ ├── index.html.template │ └── onboarding.html.template ├── layouts │ ├── ha-init-page.ts │ ├── hass-error-screen.ts │ ├── hass-loading-screen.ts │ ├── hass-router-page.ts │ ├── hass-subpage.ts │ ├── hass-tabs-subpage-data-table.ts │ ├── hass-tabs-subpage.ts │ ├── home-assistant-main.ts │ ├── home-assistant.ts │ ├── partial-panel-resolver.ts │ └── supervisor-error-screen.ts ├── managers │ └── notification-manager.ts ├── mixins │ ├── keyboard-shortcut-mixin.ts │ ├── lit-localize-lite-mixin.ts │ ├── prevent-unsaved-mixin.ts │ ├── provide-hass-lit-mixin.ts │ ├── subscribe-mixin.ts │ └── wakelock-mixin.ts ├── onboarding │ ├── dialogs │ │ ├── app-dialog.ts │ │ ├── community-dialog.ts │ │ ├── show-app-dialog.ts │ │ └── show-community-dialog.ts │ ├── ha-onboarding.ts │ ├── integration-badge.ts │ ├── onboarding-analytics.ts │ ├── onboarding-core-config.ts │ ├── onboarding-create-user.ts │ ├── onboarding-integrations.ts │ ├── onboarding-loading.ts │ ├── onboarding-location.ts │ ├── onboarding-restore-backup.ts │ ├── onboarding-welcome-link.ts │ ├── onboarding-welcome-links.ts │ ├── onboarding-welcome.ts │ ├── restore-backup │ │ ├── onboarding-restore-backup-cloud-login.ts │ │ ├── onboarding-restore-backup-no-cloud-backup.ts │ │ ├── onboarding-restore-backup-restore.ts │ │ ├── onboarding-restore-backup-status.ts │ │ └── onboarding-restore-backup-upload.ts │ └── styles.ts ├── panels │ ├── calendar │ │ ├── confirm-event-dialog-box.ts │ │ ├── dialog-calendar-event-detail.ts │ │ ├── dialog-calendar-event-editor.ts │ │ ├── ha-full-calendar.ts │ │ ├── ha-panel-calendar.ts │ │ ├── ha-recurrence-rule-editor.ts │ │ ├── recurrence.ts │ │ ├── show-confirm-event-dialog-box.ts │ │ ├── show-dialog-calendar-event-detail.ts │ │ └── show-dialog-calendar-event-editor.ts │ ├── config │ │ ├── application_credentials │ │ │ ├── dialog-add-application-credential.ts │ │ │ ├── ha-config-application-credentials.ts │ │ │ └── show-dialog-add-application-credential.ts │ │ ├── areas │ │ │ ├── dialog-area-registry-detail.ts │ │ │ ├── dialog-floor-registry-detail.ts │ │ │ ├── ha-config-area-page.ts │ │ │ ├── ha-config-areas-dashboard.ts │ │ │ ├── ha-config-areas.ts │ │ │ ├── show-dialog-area-registry-detail.ts │ │ │ └── show-dialog-floor-registry-detail.ts │ │ ├── automation │ │ │ ├── action │ │ │ │ ├── ha-automation-action-row.ts │ │ │ │ ├── ha-automation-action.ts │ │ │ │ └── types │ │ │ │ │ ├── ha-automation-action-choose.ts │ │ │ │ │ ├── ha-automation-action-condition.ts │ │ │ │ │ ├── ha-automation-action-delay.ts │ │ │ │ │ ├── ha-automation-action-device_id.ts │ │ │ │ │ ├── ha-automation-action-event.ts │ │ │ │ │ ├── ha-automation-action-if.ts │ │ │ │ │ ├── ha-automation-action-parallel.ts │ │ │ │ │ ├── ha-automation-action-play_media.ts │ │ │ │ │ ├── ha-automation-action-repeat.ts │ │ │ │ │ ├── ha-automation-action-sequence.ts │ │ │ │ │ ├── ha-automation-action-service.ts │ │ │ │ │ ├── ha-automation-action-set_conversation_response.ts │ │ │ │ │ ├── ha-automation-action-stop.ts │ │ │ │ │ ├── ha-automation-action-wait_for_trigger.ts │ │ │ │ │ └── ha-automation-action-wait_template.ts │ │ │ ├── add-automation-element-dialog.ts │ │ │ ├── automation-mode-dialog │ │ │ │ ├── dialog-automation-mode.ts │ │ │ │ └── show-dialog-automation-mode.ts │ │ │ ├── automation-save-dialog │ │ │ │ ├── dialog-automation-save.ts │ │ │ │ └── show-dialog-automation-save.ts │ │ │ ├── blueprint-automation-editor.ts │ │ │ ├── condition │ │ │ │ ├── ha-automation-condition-editor.ts │ │ │ │ ├── ha-automation-condition-row.ts │ │ │ │ ├── ha-automation-condition.ts │ │ │ │ └── types │ │ │ │ │ ├── ha-automation-condition-and.ts │ │ │ │ │ ├── ha-automation-condition-device.ts │ │ │ │ │ ├── ha-automation-condition-logical.ts │ │ │ │ │ ├── ha-automation-condition-not.ts │ │ │ │ │ ├── ha-automation-condition-numeric_state.ts │ │ │ │ │ ├── ha-automation-condition-or.ts │ │ │ │ │ ├── ha-automation-condition-state.ts │ │ │ │ │ ├── ha-automation-condition-sun.ts │ │ │ │ │ ├── ha-automation-condition-template.ts │ │ │ │ │ ├── ha-automation-condition-time.ts │ │ │ │ │ ├── ha-automation-condition-trigger.ts │ │ │ │ │ └── ha-automation-condition-zone.ts │ │ │ ├── dialog-new-automation.ts │ │ │ ├── ha-automation-editor.ts │ │ │ ├── ha-automation-picker.ts │ │ │ ├── ha-automation-trace.ts │ │ │ ├── ha-config-automation.ts │ │ │ ├── manual-automation-editor.ts │ │ │ ├── option │ │ │ │ ├── ha-automation-option-row.ts │ │ │ │ └── ha-automation-option.ts │ │ │ ├── paste-replace-dialog │ │ │ │ ├── dialog-paste-replace.ts │ │ │ │ └── show-dialog-paste-replace.ts │ │ │ ├── show-add-automation-element-dialog.ts │ │ │ ├── show-dialog-new-automation.ts │ │ │ ├── structs.ts │ │ │ └── trigger │ │ │ │ ├── ha-automation-trigger-row.ts │ │ │ │ ├── ha-automation-trigger.ts │ │ │ │ └── types │ │ │ │ ├── ha-automation-trigger-calendar.ts │ │ │ │ ├── ha-automation-trigger-conversation.ts │ │ │ │ ├── ha-automation-trigger-device.ts │ │ │ │ ├── ha-automation-trigger-event.ts │ │ │ │ ├── ha-automation-trigger-geo_location.ts │ │ │ │ ├── ha-automation-trigger-homeassistant.ts │ │ │ │ ├── ha-automation-trigger-list.ts │ │ │ │ ├── ha-automation-trigger-mqtt.ts │ │ │ │ ├── ha-automation-trigger-numeric_state.ts │ │ │ │ ├── ha-automation-trigger-persistent_notification.ts │ │ │ │ ├── ha-automation-trigger-state.ts │ │ │ │ ├── ha-automation-trigger-sun.ts │ │ │ │ ├── ha-automation-trigger-tag.ts │ │ │ │ ├── ha-automation-trigger-template.ts │ │ │ │ ├── ha-automation-trigger-time.ts │ │ │ │ ├── ha-automation-trigger-time_pattern.ts │ │ │ │ ├── ha-automation-trigger-webhook.ts │ │ │ │ └── ha-automation-trigger-zone.ts │ │ ├── backup │ │ │ ├── components │ │ │ │ ├── config │ │ │ │ │ ├── ha-backup-config-addon.ts │ │ │ │ │ ├── ha-backup-config-agents.ts │ │ │ │ │ ├── ha-backup-config-data.ts │ │ │ │ │ ├── ha-backup-config-encryption-key.ts │ │ │ │ │ ├── ha-backup-config-retention.ts │ │ │ │ │ └── ha-backup-config-schedule.ts │ │ │ │ ├── ha-backup-addons-picker.ts │ │ │ │ ├── ha-backup-agents-picker.ts │ │ │ │ ├── ha-backup-data-picker.ts │ │ │ │ ├── ha-backup-details-restore.ts │ │ │ │ ├── ha-backup-details-summary.ts │ │ │ │ ├── ha-backup-formfield-label.ts │ │ │ │ ├── ha-backup-summary-card.ts │ │ │ │ └── overview │ │ │ │ │ ├── ha-backup-overview-backups.ts │ │ │ │ │ ├── ha-backup-overview-onboarding.ts │ │ │ │ │ ├── ha-backup-overview-progress.ts │ │ │ │ │ ├── ha-backup-overview-settings.ts │ │ │ │ │ └── ha-backup-overview-summary.ts │ │ │ ├── dialogs │ │ │ │ ├── dialog-backup-onboarding.ts │ │ │ │ ├── dialog-change-backup-encryption-key.ts │ │ │ │ ├── dialog-download-decrypted-backup.ts │ │ │ │ ├── dialog-generate-backup.ts │ │ │ │ ├── dialog-local-backup-location.ts │ │ │ │ ├── dialog-new-backup.ts │ │ │ │ ├── dialog-restore-backup.ts │ │ │ │ ├── dialog-set-backup-encryption-key.ts │ │ │ │ ├── dialog-show-backup-encryption-key.ts │ │ │ │ ├── dialog-upload-backup.ts │ │ │ │ ├── show-dialog-backup_onboarding.ts │ │ │ │ ├── show-dialog-change-backup-encryption-key.ts │ │ │ │ ├── show-dialog-download-decrypted-backup.ts │ │ │ │ ├── show-dialog-generate-backup.ts │ │ │ │ ├── show-dialog-local-backup-location.ts │ │ │ │ ├── show-dialog-new-backup.ts │ │ │ │ ├── show-dialog-restore-backup.ts │ │ │ │ ├── show-dialog-set-backup-encryption-key.ts │ │ │ │ ├── show-dialog-show-backup-encryption-key.ts │ │ │ │ └── show-dialog-upload-backup.ts │ │ │ ├── ha-config-backup-backups.ts │ │ │ ├── ha-config-backup-details.ts │ │ │ ├── ha-config-backup-location.ts │ │ │ ├── ha-config-backup-overview.ts │ │ │ ├── ha-config-backup-settings.ts │ │ │ ├── ha-config-backup.ts │ │ │ └── helper │ │ │ │ └── download_backup.ts │ │ ├── blueprint │ │ │ ├── blueprint-generic-editor.ts │ │ │ ├── dialog-import-blueprint.ts │ │ │ ├── ha-blueprint-overview.ts │ │ │ ├── ha-config-blueprint.ts │ │ │ └── show-dialog-import-blueprint.ts │ │ ├── category │ │ │ ├── dialog-assign-category.ts │ │ │ ├── dialog-category-registry-detail.ts │ │ │ ├── ha-category-picker.ts │ │ │ ├── show-dialog-assign-category.ts │ │ │ └── show-dialog-category-registry-detail.ts │ │ ├── cloud │ │ │ ├── account │ │ │ │ ├── cloud-account.ts │ │ │ │ ├── cloud-ice-servers-pref.ts │ │ │ │ ├── cloud-remote-pref.ts │ │ │ │ ├── cloud-tts-pref.ts │ │ │ │ ├── cloud-webhooks.ts │ │ │ │ ├── dialog-cloud-support-package.ts │ │ │ │ ├── dialog-cloud-tts-try.ts │ │ │ │ ├── show-dialog-cloud-support-package.ts │ │ │ │ └── show-dialog-cloud-tts-try.ts │ │ │ ├── dialog-cloud-already-connected │ │ │ │ ├── dialog-cloud-already-connected.ts │ │ │ │ └── show-dialog-cloud-already-connected.ts │ │ │ ├── dialog-cloud-certificate │ │ │ │ ├── dialog-cloud-certificate.ts │ │ │ │ └── show-dialog-cloud-certificate.ts │ │ │ ├── dialog-manage-cloudhook │ │ │ │ ├── dialog-manage-cloudhook.ts │ │ │ │ └── show-dialog-manage-cloudhook.ts │ │ │ ├── forgot-password │ │ │ │ ├── cloud-forgot-password-card.ts │ │ │ │ └── cloud-forgot-password.ts │ │ │ ├── ha-config-cloud.ts │ │ │ ├── login │ │ │ │ ├── cloud-login-panel.ts │ │ │ │ └── cloud-login.ts │ │ │ └── register │ │ │ │ └── cloud-register.ts │ │ ├── core │ │ │ ├── ha-config-analytics.ts │ │ │ ├── ha-config-section-analytics.ts │ │ │ ├── ha-config-section-general.ts │ │ │ ├── ha-config-section-updates.ts │ │ │ ├── ha-config-system-navigation.ts │ │ │ └── updates │ │ │ │ ├── dialog-join-beta.ts │ │ │ │ └── show-dialog-join-beta.ts │ │ ├── dashboard │ │ │ ├── dialog-new-dashboard.ts │ │ │ ├── ha-config-dashboard.ts │ │ │ ├── ha-config-navigation.ts │ │ │ ├── ha-config-updates.ts │ │ │ └── show-dialog-new-dashboard.ts │ │ ├── devices │ │ │ ├── device-detail │ │ │ │ ├── ha-device-automation-dialog.ts │ │ │ │ ├── ha-device-entities-card.ts │ │ │ │ ├── ha-device-info-card.ts │ │ │ │ ├── ha-device-via-devices-card.ts │ │ │ │ ├── integration-elements │ │ │ │ │ ├── matter │ │ │ │ │ │ ├── device-actions.ts │ │ │ │ │ │ └── ha-device-info-matter.ts │ │ │ │ │ ├── mqtt │ │ │ │ │ │ ├── device-actions.ts │ │ │ │ │ │ ├── dialog-mqtt-device-debug-info.ts │ │ │ │ │ │ ├── mqtt-discovery-payload.ts │ │ │ │ │ │ ├── mqtt-messages.ts │ │ │ │ │ │ └── show-dialog-mqtt-device-debug-info.ts │ │ │ │ │ ├── zha │ │ │ │ │ │ ├── device-actions.ts │ │ │ │ │ │ └── ha-device-info-zha.ts │ │ │ │ │ └── zwave_js │ │ │ │ │ │ ├── device-actions.ts │ │ │ │ │ │ ├── device-alerts.ts │ │ │ │ │ │ └── ha-device-info-zwave_js.ts │ │ │ │ └── show-dialog-device-automation.ts │ │ │ ├── device-registry-detail │ │ │ │ ├── dialog-device-registry-detail.ts │ │ │ │ └── show-dialog-device-registry-detail.ts │ │ │ ├── ha-config-device-page.ts │ │ │ ├── ha-config-devices-dashboard.ts │ │ │ └── ha-config-devices.ts │ │ ├── energy │ │ │ ├── components │ │ │ │ ├── ha-energy-battery-settings.ts │ │ │ │ ├── ha-energy-device-settings.ts │ │ │ │ ├── ha-energy-gas-settings.ts │ │ │ │ ├── ha-energy-grid-settings.ts │ │ │ │ ├── ha-energy-solar-settings.ts │ │ │ │ ├── ha-energy-validation-result.ts │ │ │ │ ├── ha-energy-water-settings.ts │ │ │ │ └── styles.ts │ │ │ ├── dialogs │ │ │ │ ├── dialog-energy-battery-settings.ts │ │ │ │ ├── dialog-energy-device-settings.ts │ │ │ │ ├── dialog-energy-gas-settings.ts │ │ │ │ ├── dialog-energy-grid-flow-settings.ts │ │ │ │ ├── dialog-energy-solar-settings.ts │ │ │ │ ├── dialog-energy-water-settings.ts │ │ │ │ └── show-dialogs-energy.ts │ │ │ └── ha-config-energy.ts │ │ ├── entities │ │ │ ├── const.ts │ │ │ ├── editor-tabs │ │ │ │ └── settings │ │ │ │ │ └── entity-settings-helper-tab.ts │ │ │ ├── entity-registry-settings-editor.ts │ │ │ ├── entity-registry-settings.ts │ │ │ └── ha-config-entities.ts │ │ ├── ha-config-section.ts │ │ ├── ha-panel-config.ts │ │ ├── hardware │ │ │ ├── dialog-hardware-available.ts │ │ │ ├── ha-config-hardware.ts │ │ │ └── show-dialog-hardware-available.ts │ │ ├── helpers │ │ │ ├── const.ts │ │ │ ├── dialog-helper-detail.ts │ │ │ ├── forms │ │ │ │ ├── dialog-schedule-block-info.ts │ │ │ │ ├── ha-counter-form.ts │ │ │ │ ├── ha-input_boolean-form.ts │ │ │ │ ├── ha-input_button-form.ts │ │ │ │ ├── ha-input_datetime-form.ts │ │ │ │ ├── ha-input_number-form.ts │ │ │ │ ├── ha-input_select-form.ts │ │ │ │ ├── ha-input_text-form.ts │ │ │ │ ├── ha-schedule-form.ts │ │ │ │ ├── ha-timer-form.ts │ │ │ │ └── show-dialog-schedule-block-info.ts │ │ │ ├── ha-config-helpers.ts │ │ │ └── show-dialog-helper-detail.ts │ │ ├── info │ │ │ └── ha-config-info.ts │ │ ├── integrations │ │ │ ├── dialog-add-integration.ts │ │ │ ├── dialog-yaml-integration.ts │ │ │ ├── ha-config-flow-card.ts │ │ │ ├── ha-config-integration-page.ts │ │ │ ├── ha-config-integrations-dashboard.ts │ │ │ ├── ha-config-integrations.ts │ │ │ ├── ha-disabled-config-entry-card.ts │ │ │ ├── ha-domain-integrations.ts │ │ │ ├── ha-ignored-config-entry-card.ts │ │ │ ├── ha-integration-action-card.ts │ │ │ ├── ha-integration-card.ts │ │ │ ├── ha-integration-header.ts │ │ │ ├── ha-integration-list-item.ts │ │ │ ├── ha-integration-overflow-menu.ts │ │ │ ├── integration-panels │ │ │ │ ├── bluetooth │ │ │ │ │ ├── bluetooth-advertisement-monitor.ts │ │ │ │ │ ├── bluetooth-config-dashboard-router.ts │ │ │ │ │ ├── bluetooth-config-dashboard.ts │ │ │ │ │ ├── bluetooth-connection-monitor.ts │ │ │ │ │ ├── bluetooth-network-visualization.ts │ │ │ │ │ ├── dialog-bluetooth-device-info.ts │ │ │ │ │ └── show-dialog-bluetooth-device-info.ts │ │ │ │ ├── dhcp │ │ │ │ │ └── dhcp-config-panel.ts │ │ │ │ ├── matter │ │ │ │ │ ├── dialog-matter-add-device.ts │ │ │ │ │ ├── dialog-matter-manage-fabrics.ts │ │ │ │ │ ├── dialog-matter-open-commissioning-window.ts │ │ │ │ │ ├── dialog-matter-ping-node.ts │ │ │ │ │ ├── dialog-matter-reinterview-node.ts │ │ │ │ │ ├── matter-add-device.ts │ │ │ │ │ ├── matter-add-device │ │ │ │ │ │ ├── matter-add-device-apple-home.ts │ │ │ │ │ │ ├── matter-add-device-commissioning.ts │ │ │ │ │ │ ├── matter-add-device-existing.ts │ │ │ │ │ │ ├── matter-add-device-generic.ts │ │ │ │ │ │ ├── matter-add-device-google-home-fallback.ts │ │ │ │ │ │ ├── matter-add-device-google-home.ts │ │ │ │ │ │ ├── matter-add-device-main.ts │ │ │ │ │ │ ├── matter-add-device-new.ts │ │ │ │ │ │ └── matter-add-device-shared-styles.ts │ │ │ │ │ ├── matter-config-dashboard.ts │ │ │ │ │ ├── matter-config-panel.ts │ │ │ │ │ ├── show-dialog-add-matter-device.ts │ │ │ │ │ ├── show-dialog-matter-manage-fabrics.ts │ │ │ │ │ ├── show-dialog-matter-open-commissioning-window.ts │ │ │ │ │ ├── show-dialog-matter-ping-node.ts │ │ │ │ │ └── show-dialog-matter-reinterview-node.ts │ │ │ │ ├── mqtt │ │ │ │ │ ├── mqtt-config-panel.ts │ │ │ │ │ └── mqtt-subscribe-card.ts │ │ │ │ ├── ssdp │ │ │ │ │ ├── dialog-ssdp-discovery-info.ts │ │ │ │ │ ├── dialog-ssdp-raw-data.ts │ │ │ │ │ ├── show-dialog-ssdp-discovery-info.ts │ │ │ │ │ ├── show-dialog-ssdp-raw-data.ts │ │ │ │ │ └── ssdp-config-panel.ts │ │ │ │ ├── thread │ │ │ │ │ ├── dialog-thread-dataset.ts │ │ │ │ │ ├── show-dialog-thread-dataset.ts │ │ │ │ │ └── thread-config-panel.ts │ │ │ │ ├── zeroconf │ │ │ │ │ ├── dialog-zeroconf-discovery-info.ts │ │ │ │ │ ├── show-dialog-zeroconf-discovery-info.ts │ │ │ │ │ └── zeroconf-config-panel.ts │ │ │ │ ├── zha │ │ │ │ │ ├── dialog-zha-change-channel.ts │ │ │ │ │ ├── dialog-zha-manage-zigbee-device.ts │ │ │ │ │ ├── dialog-zha-reconfigure-device.ts │ │ │ │ │ ├── functions.ts │ │ │ │ │ ├── show-dialog-zha-change-channel.ts │ │ │ │ │ ├── show-dialog-zha-manage-zigbee-device.ts │ │ │ │ │ ├── show-dialog-zha-reconfigure-device.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── zha-add-devices-page.ts │ │ │ │ │ ├── zha-add-group-page.ts │ │ │ │ │ ├── zha-cluster-attributes.ts │ │ │ │ │ ├── zha-cluster-commands.ts │ │ │ │ │ ├── zha-clusters-data-table.ts │ │ │ │ │ ├── zha-config-dashboard-router.ts │ │ │ │ │ ├── zha-config-dashboard.ts │ │ │ │ │ ├── zha-device-binding.ts │ │ │ │ │ ├── zha-device-card.ts │ │ │ │ │ ├── zha-device-endpoint-data-table.ts │ │ │ │ │ ├── zha-device-neighbors.ts │ │ │ │ │ ├── zha-device-pairing-status-card.ts │ │ │ │ │ ├── zha-device-signature.ts │ │ │ │ │ ├── zha-group-binding.ts │ │ │ │ │ ├── zha-group-page.ts │ │ │ │ │ ├── zha-groups-dashboard.ts │ │ │ │ │ ├── zha-manage-clusters.ts │ │ │ │ │ └── zha-network-visualization-page.ts │ │ │ │ └── zwave_js │ │ │ │ │ ├── add-node │ │ │ │ │ ├── data.ts │ │ │ │ │ ├── dialog-zwave_js-add-node.ts │ │ │ │ │ ├── show-dialog-zwave_js-add-node.ts │ │ │ │ │ ├── zwave-js-add-node-added-insecure.ts │ │ │ │ │ ├── zwave-js-add-node-code-input.ts │ │ │ │ │ ├── zwave-js-add-node-configure-device.ts │ │ │ │ │ ├── zwave-js-add-node-failed.ts │ │ │ │ │ ├── zwave-js-add-node-grant-security-classes.ts │ │ │ │ │ ├── zwave-js-add-node-loading.ts │ │ │ │ │ ├── zwave-js-add-node-searching-devices.ts │ │ │ │ │ ├── zwave-js-add-node-select-method.ts │ │ │ │ │ ├── zwave-js-add-node-select-security-strategy.ts │ │ │ │ │ └── zwave_js-add-node.ts │ │ │ │ │ ├── capability-controls │ │ │ │ │ ├── zwave_js-capability-control-color-switch.ts │ │ │ │ │ ├── zwave_js-capability-control-door-lock.ts │ │ │ │ │ ├── zwave_js-capability-control-multilevel-switch.ts │ │ │ │ │ └── zwave_js-capability-control-thermostat-setback.ts │ │ │ │ │ ├── dialog-zwave_js-hard-reset-controller.ts │ │ │ │ │ ├── dialog-zwave_js-node-statistics.ts │ │ │ │ │ ├── dialog-zwave_js-rebuild-network-routes.ts │ │ │ │ │ ├── dialog-zwave_js-rebuild-node-routes.ts │ │ │ │ │ ├── dialog-zwave_js-reinterview-node.ts │ │ │ │ │ ├── dialog-zwave_js-remove-failed-node.ts │ │ │ │ │ ├── dialog-zwave_js-remove-node.ts │ │ │ │ │ ├── dialog-zwave_js-update-firmware-node.ts │ │ │ │ │ ├── show-dialog-zwave_js-hard-reset-controller.ts │ │ │ │ │ ├── show-dialog-zwave_js-node-statistics.ts │ │ │ │ │ ├── show-dialog-zwave_js-rebuild-network-routes.ts │ │ │ │ │ ├── show-dialog-zwave_js-rebuild-node-routes.ts │ │ │ │ │ ├── show-dialog-zwave_js-reinterview-node.ts │ │ │ │ │ ├── show-dialog-zwave_js-remove-failed-node.ts │ │ │ │ │ ├── show-dialog-zwave_js-remove-node.ts │ │ │ │ │ ├── show-dialog-zwave_js-update-firmware-node.ts │ │ │ │ │ ├── zwave_js-config-dashboard.ts │ │ │ │ │ ├── zwave_js-config-router.ts │ │ │ │ │ ├── zwave_js-custom-param.ts │ │ │ │ │ ├── zwave_js-logs.ts │ │ │ │ │ ├── zwave_js-node-config.ts │ │ │ │ │ ├── zwave_js-node-installer.ts │ │ │ │ │ └── zwave_js-provisioned.ts │ │ │ └── show-add-integration-dialog.ts │ │ ├── labels │ │ │ ├── dialog-label-detail.ts │ │ │ ├── ha-config-labels.ts │ │ │ └── show-dialog-label-detail.ts │ │ ├── logs │ │ │ ├── dialog-download-logs.ts │ │ │ ├── dialog-system-log-detail.ts │ │ │ ├── error-log-card.ts │ │ │ ├── ha-config-logs.ts │ │ │ ├── show-dialog-download-logs.ts │ │ │ ├── show-dialog-system-log-detail.ts │ │ │ ├── system-log-card.ts │ │ │ └── util.ts │ │ ├── lovelace │ │ │ ├── dashboards │ │ │ │ ├── dialog-lovelace-dashboard-configure-strategy.ts │ │ │ │ ├── dialog-lovelace-dashboard-detail.ts │ │ │ │ ├── ha-config-lovelace-dashboards.ts │ │ │ │ ├── show-dialog-lovelace-dashboard-configure-strategy.ts │ │ │ │ └── show-dialog-lovelace-dashboard-detail.ts │ │ │ ├── ha-config-lovelace.ts │ │ │ └── resources │ │ │ │ ├── dialog-lovelace-resource-detail.ts │ │ │ │ ├── ha-config-lovelace-resources.ts │ │ │ │ └── show-dialog-lovelace-resource-detail.ts │ │ ├── network │ │ │ ├── ha-config-network.ts │ │ │ ├── ha-config-section-network.ts │ │ │ ├── ha-config-url-form.ts │ │ │ ├── supervisor-hostname.ts │ │ │ └── supervisor-network.ts │ │ ├── person │ │ │ ├── dialog-person-detail.ts │ │ │ ├── ha-config-person.ts │ │ │ └── show-dialog-person-detail.ts │ │ ├── repairs │ │ │ ├── dialog-integration-startup.ts │ │ │ ├── dialog-repairs-issue-subtitle.ts │ │ │ ├── dialog-repairs-issue.ts │ │ │ ├── dialog-system-information.ts │ │ │ ├── ha-config-repairs-dashboard.ts │ │ │ ├── ha-config-repairs.ts │ │ │ ├── integrations-startup-time.ts │ │ │ ├── show-dialog-repair-flow.ts │ │ │ ├── show-integration-startup-dialog.ts │ │ │ ├── show-repair-issue-dialog.ts │ │ │ └── show-system-information-dialog.ts │ │ ├── scene │ │ │ ├── ha-config-scene.ts │ │ │ ├── ha-scene-dashboard.ts │ │ │ └── ha-scene-editor.ts │ │ ├── script │ │ │ ├── blueprint-script-editor.ts │ │ │ ├── ha-config-script.ts │ │ │ ├── ha-script-editor.ts │ │ │ ├── ha-script-field-row.ts │ │ │ ├── ha-script-fields.ts │ │ │ ├── ha-script-picker.ts │ │ │ ├── ha-script-trace.ts │ │ │ └── manual-script-editor.ts │ │ ├── storage │ │ │ ├── dialog-mount-view.ts │ │ │ ├── dialog-move-datadisk.ts │ │ │ ├── ha-config-section-storage.ts │ │ │ ├── show-dialog-move-datadisk.ts │ │ │ └── show-dialog-view-mount.ts │ │ ├── tags │ │ │ ├── dialog-tag-detail.ts │ │ │ ├── ha-config-tags.ts │ │ │ ├── show-dialog-tag-detail.ts │ │ │ └── tag-image.ts │ │ ├── users │ │ │ ├── dialog-add-user.ts │ │ │ ├── dialog-admin-change-password.ts │ │ │ ├── dialog-user-detail.ts │ │ │ ├── ha-config-users.ts │ │ │ ├── show-dialog-add-user.ts │ │ │ ├── show-dialog-admin-change-password.ts │ │ │ └── show-dialog-user-detail.ts │ │ ├── voice-assistants │ │ │ ├── assist-pipeline-detail │ │ │ │ ├── assist-pipeline-detail-config.ts │ │ │ │ ├── assist-pipeline-detail-conversation.ts │ │ │ │ ├── assist-pipeline-detail-stt.ts │ │ │ │ ├── assist-pipeline-detail-tts.ts │ │ │ │ └── assist-pipeline-detail-wakeword.ts │ │ │ ├── assist-pref.ts │ │ │ ├── assist │ │ │ │ └── ha-config-voice-assistants-assist-devices.ts │ │ │ ├── cloud-alexa-pref.ts │ │ │ ├── cloud-discover.ts │ │ │ ├── cloud-google-pref.ts │ │ │ ├── debug │ │ │ │ ├── assist-debug.ts │ │ │ │ ├── assist-pipeline-debug.ts │ │ │ │ ├── assist-pipeline-run-debug.ts │ │ │ │ ├── assist-render-pipeline-events.ts │ │ │ │ └── assist-render-pipeline-run.ts │ │ │ ├── dialog-expose-entity.ts │ │ │ ├── dialog-voice-assistant-pipeline-detail.ts │ │ │ ├── dialog-voice-settings.ts │ │ │ ├── entity-voice-settings.ts │ │ │ ├── expose │ │ │ │ └── expose-assistant-icon.ts │ │ │ ├── ha-config-voice-assistants-assistants.ts │ │ │ ├── ha-config-voice-assistants-expose.ts │ │ │ ├── ha-config-voice-assistants.ts │ │ │ ├── show-dialog-expose-entity.ts │ │ │ ├── show-dialog-voice-assistant-pipeline-detail.ts │ │ │ └── show-dialog-voice-settings.ts │ │ └── zone │ │ │ ├── dialog-home-zone-detail.ts │ │ │ ├── dialog-zone-detail.ts │ │ │ ├── ha-config-zone.ts │ │ │ ├── show-dialog-home-zone-detail.ts │ │ │ └── show-dialog-zone-detail.ts │ ├── custom │ │ └── ha-panel-custom.ts │ ├── developer-tools │ │ ├── action │ │ │ └── developer-tools-action.ts │ │ ├── assist │ │ │ └── developer-tools-assist.ts │ │ ├── debug │ │ │ ├── developer-tools-debug.ts │ │ │ └── ha-debug-connection-row.ts │ │ ├── developer-tools-router.ts │ │ ├── event │ │ │ ├── developer-tools-event.ts │ │ │ ├── event-subscribe-card.ts │ │ │ └── events-list.ts │ │ ├── ha-panel-developer-tools.ts │ │ ├── state │ │ │ └── developer-tools-state.ts │ │ ├── statistics │ │ │ ├── developer-tools-statistics.ts │ │ │ ├── dialog-statistics-adjust-sum.ts │ │ │ ├── dialog-statistics-fix-units-changed.ts │ │ │ ├── dialog-statistics-fix.ts │ │ │ ├── fix-statistics.ts │ │ │ ├── show-dialog-statistics-adjust-sum.ts │ │ │ ├── show-dialog-statistics-fix-units-changed.ts │ │ │ └── show-dialog-statistics-fix.ts │ │ ├── template │ │ │ └── developer-tools-template.ts │ │ └── yaml_configuration │ │ │ └── developer-yaml-config.ts │ ├── energy │ │ ├── cards │ │ │ └── energy-setup-wizard-card.ts │ │ ├── ha-panel-energy.ts │ │ └── strategies │ │ │ └── energy-view-strategy.ts │ ├── history │ │ └── ha-panel-history.ts │ ├── iframe │ │ └── ha-panel-iframe.ts │ ├── logbook │ │ ├── ha-logbook-renderer.ts │ │ ├── ha-logbook.ts │ │ └── ha-panel-logbook.ts │ ├── lovelace │ │ ├── badges │ │ │ ├── hui-badge.ts │ │ │ ├── hui-entity-badge.ts │ │ │ ├── hui-entity-filter-badge.ts │ │ │ ├── hui-error-badge.ts │ │ │ ├── hui-state-label-badge.ts │ │ │ ├── hui-view-badges.ts │ │ │ └── types.ts │ │ ├── card-features │ │ │ ├── common │ │ │ │ ├── card-feature-styles.ts │ │ │ │ └── filter-modes.ts │ │ │ ├── hui-alarm-modes-card-feature.ts │ │ │ ├── hui-card-feature.ts │ │ │ ├── hui-card-features.ts │ │ │ ├── hui-climate-fan-modes-card-feature.ts │ │ │ ├── hui-climate-hvac-modes-card-feature.ts │ │ │ ├── hui-climate-preset-modes-card-feature.ts │ │ │ ├── hui-climate-swing-horizontal-modes-card-feature.ts │ │ │ ├── hui-climate-swing-modes-card-feature.ts │ │ │ ├── hui-counter-actions-card-feature.ts │ │ │ ├── hui-cover-open-close-card-feature.ts │ │ │ ├── hui-cover-position-card-feature.ts │ │ │ ├── hui-cover-tilt-card-feature.ts │ │ │ ├── hui-cover-tilt-position-card-feature.ts │ │ │ ├── hui-fan-preset-modes-card-feature.ts │ │ │ ├── hui-fan-speed-card-feature.ts │ │ │ ├── hui-humidifier-modes-card-feature.ts │ │ │ ├── hui-humidifier-toggle-card-feature.ts │ │ │ ├── hui-lawn-mower-commands-card-feature.ts │ │ │ ├── hui-light-brightness-card-feature.ts │ │ │ ├── hui-light-color-temp-card-feature.ts │ │ │ ├── hui-lock-commands-card-feature.ts │ │ │ ├── hui-lock-open-door-card-feature.ts │ │ │ ├── hui-media-player-volume-slider-card-feature.ts │ │ │ ├── hui-numeric-input-card-feature.ts │ │ │ ├── hui-select-options-card-feature.ts │ │ │ ├── hui-target-humidity-card-feature.ts │ │ │ ├── hui-target-temperature-card-feature.ts │ │ │ ├── hui-toggle-card-feature.ts │ │ │ ├── hui-update-actions-card-feature.ts │ │ │ ├── hui-vacuum-commands-card-feature.ts │ │ │ ├── hui-water-heater-operation-modes-card-feature.ts │ │ │ └── types.ts │ │ ├── cards │ │ │ ├── energy │ │ │ │ ├── common │ │ │ │ │ ├── color.ts │ │ │ │ │ └── energy-chart-options.ts │ │ │ │ ├── hui-energy-carbon-consumed-gauge-card.ts │ │ │ │ ├── hui-energy-compare-card.ts │ │ │ │ ├── hui-energy-date-selection-card.ts │ │ │ │ ├── hui-energy-devices-detail-graph-card.ts │ │ │ │ ├── hui-energy-devices-graph-card.ts │ │ │ │ ├── hui-energy-distribution-card.ts │ │ │ │ ├── hui-energy-gas-graph-card.ts │ │ │ │ ├── hui-energy-grid-neutrality-gauge-card.ts │ │ │ │ ├── hui-energy-sankey-card.ts │ │ │ │ ├── hui-energy-self-sufficiency-gauge-card.ts │ │ │ │ ├── hui-energy-solar-consumed-gauge-card.ts │ │ │ │ ├── hui-energy-solar-graph-card.ts │ │ │ │ ├── hui-energy-sources-table-card.ts │ │ │ │ ├── hui-energy-usage-graph-card.ts │ │ │ │ └── hui-energy-water-graph-card.ts │ │ │ ├── hui-alarm-panel-card.ts │ │ │ ├── hui-area-card.ts │ │ │ ├── hui-button-card.ts │ │ │ ├── hui-calendar-card.ts │ │ │ ├── hui-card.ts │ │ │ ├── hui-clock-card.ts │ │ │ ├── hui-conditional-card.ts │ │ │ ├── hui-empty-state-card.ts │ │ │ ├── hui-entities-card.ts │ │ │ ├── hui-entity-button-card.ts │ │ │ ├── hui-entity-card.ts │ │ │ ├── hui-entity-filter-card.ts │ │ │ ├── hui-error-card.ts │ │ │ ├── hui-gauge-card.ts │ │ │ ├── hui-glance-card.ts │ │ │ ├── hui-grid-card.ts │ │ │ ├── hui-heading-card.ts │ │ │ ├── hui-history-graph-card.ts │ │ │ ├── hui-horizontal-stack-card.ts │ │ │ ├── hui-humidifier-card.ts │ │ │ ├── hui-iframe-card.ts │ │ │ ├── hui-light-card.ts │ │ │ ├── hui-logbook-card.ts │ │ │ ├── hui-map-card.ts │ │ │ ├── hui-markdown-card.ts │ │ │ ├── hui-media-control-card.ts │ │ │ ├── hui-picture-card.ts │ │ │ ├── hui-picture-elements-card.ts │ │ │ ├── hui-picture-entity-card.ts │ │ │ ├── hui-picture-glance-card.ts │ │ │ ├── hui-plant-status-card.ts │ │ │ ├── hui-recovery-mode-card.ts │ │ │ ├── hui-sensor-card.ts │ │ │ ├── hui-shopping-list-card.ts │ │ │ ├── hui-stack-card.ts │ │ │ ├── hui-starting-card.ts │ │ │ ├── hui-statistic-card.ts │ │ │ ├── hui-statistics-graph-card.ts │ │ │ ├── hui-thermostat-card.ts │ │ │ ├── hui-tile-card.ts │ │ │ ├── hui-todo-list-card.ts │ │ │ ├── hui-vertical-stack-card.ts │ │ │ ├── hui-weather-forecast-card.ts │ │ │ ├── picture-elements │ │ │ │ └── create-styled-hui-element.ts │ │ │ ├── tile │ │ │ │ └── badges │ │ │ │ │ ├── tile-badge-climate.ts │ │ │ │ │ ├── tile-badge-humidifier.ts │ │ │ │ │ ├── tile-badge-person.ts │ │ │ │ │ └── tile-badge.ts │ │ │ └── types.ts │ │ ├── common │ │ │ ├── check-lovelace-config.ts │ │ │ ├── compute-card-grid-size.ts │ │ │ ├── compute-card-size.ts │ │ │ ├── compute-tooltip.ts │ │ │ ├── compute-unused-entities.ts │ │ │ ├── confirm-action.ts │ │ │ ├── directives │ │ │ │ └── action-handler-directive.ts │ │ │ ├── entity │ │ │ │ ├── toggle-entity.ts │ │ │ │ ├── turn-on-off-entities.ts │ │ │ │ └── turn-on-off-entity.ts │ │ │ ├── evaluate-filter.ts │ │ │ ├── find-entities.ts │ │ │ ├── generate-lovelace-config.ts │ │ │ ├── graph │ │ │ │ ├── coordinates.ts │ │ │ │ └── get-path.ts │ │ │ ├── handle-action.ts │ │ │ ├── has-action.ts │ │ │ ├── has-changed.ts │ │ │ ├── icon-condition.ts │ │ │ ├── is-valid-object.ts │ │ │ ├── load-resources.ts │ │ │ ├── process-config-entities.ts │ │ │ └── validate-condition.ts │ │ ├── components │ │ │ ├── hui-action-editor.ts │ │ │ ├── hui-badge-edit-mode.ts │ │ │ ├── hui-buttons-base.ts │ │ │ ├── hui-card-edit-mode.ts │ │ │ ├── hui-card-options.ts │ │ │ ├── hui-conditional-base.ts │ │ │ ├── hui-energy-period-selector.ts │ │ │ ├── hui-entities-toggle.ts │ │ │ ├── hui-entity-editor.ts │ │ │ ├── hui-generic-entity-row.ts │ │ │ ├── hui-graph-base.ts │ │ │ ├── hui-image.ts │ │ │ ├── hui-marquee.ts │ │ │ ├── hui-timestamp-display.ts │ │ │ ├── hui-warning-element.ts │ │ │ ├── hui-warning.ts │ │ │ └── types.ts │ │ ├── create-element │ │ │ ├── create-badge-element.ts │ │ │ ├── create-card-element.ts │ │ │ ├── create-card-feature-element.ts │ │ │ ├── create-element-base.ts │ │ │ ├── create-header-footer-element.ts │ │ │ ├── create-heading-badge-element.ts │ │ │ ├── create-hui-element.ts │ │ │ ├── create-picture-element.ts │ │ │ ├── create-row-element.ts │ │ │ ├── create-section-element.ts │ │ │ └── create-view-element.ts │ │ ├── custom-card-helpers.ts │ │ ├── editor │ │ │ ├── add-entities-to-view.ts │ │ │ ├── badge-editor │ │ │ │ ├── hui-badge-element-editor.ts │ │ │ │ ├── hui-badge-picker.ts │ │ │ │ ├── hui-badge-visibility-editor.ts │ │ │ │ ├── hui-dialog-create-badge.ts │ │ │ │ ├── hui-dialog-edit-badge.ts │ │ │ │ ├── hui-dialog-suggest-badge.ts │ │ │ │ ├── show-create-badge-dialog.ts │ │ │ │ ├── show-edit-badge-dialog.ts │ │ │ │ └── show-suggest-badge-dialog.ts │ │ │ ├── card-editor │ │ │ │ ├── ha-grid-layout-slider.ts │ │ │ │ ├── hui-card-element-editor.ts │ │ │ │ ├── hui-card-layout-editor.ts │ │ │ │ ├── hui-card-picker.ts │ │ │ │ ├── hui-card-visibility-editor.ts │ │ │ │ ├── hui-dialog-create-card.ts │ │ │ │ ├── hui-dialog-delete-card.ts │ │ │ │ ├── hui-dialog-edit-card.ts │ │ │ │ ├── hui-dialog-suggest-card.ts │ │ │ │ ├── hui-entity-picker-table.ts │ │ │ │ ├── show-create-card-dialog.ts │ │ │ │ ├── show-delete-card-dialog.ts │ │ │ │ ├── show-edit-card-dialog.ts │ │ │ │ └── show-suggest-card-dialog.ts │ │ │ ├── conditions │ │ │ │ ├── ha-card-condition-editor.ts │ │ │ │ ├── ha-card-conditions-editor.ts │ │ │ │ ├── types.ts │ │ │ │ └── types │ │ │ │ │ ├── ha-card-condition-and.ts │ │ │ │ │ ├── ha-card-condition-numeric_state.ts │ │ │ │ │ ├── ha-card-condition-or.ts │ │ │ │ │ ├── ha-card-condition-screen.ts │ │ │ │ │ ├── ha-card-condition-state.ts │ │ │ │ │ └── ha-card-condition-user.ts │ │ │ ├── config-elements │ │ │ │ ├── config-elements-style.ts │ │ │ │ ├── elements │ │ │ │ │ ├── hui-conditional-element-editor.ts │ │ │ │ │ ├── hui-icon-element-editor.ts │ │ │ │ │ ├── hui-image-element-editor.ts │ │ │ │ │ ├── hui-service-button-element-editor.ts │ │ │ │ │ ├── hui-state-badge-element-editor.ts │ │ │ │ │ ├── hui-state-icon-element-editor.ts │ │ │ │ │ └── hui-state-label-element-editor.ts │ │ │ │ ├── hui-alarm-modes-card-feature-editor.ts │ │ │ │ ├── hui-alarm-panel-card-editor.ts │ │ │ │ ├── hui-area-card-editor.ts │ │ │ │ ├── hui-button-card-editor.ts │ │ │ │ ├── hui-calendar-card-editor.ts │ │ │ │ ├── hui-card-features-editor.ts │ │ │ │ ├── hui-climate-fan-modes-card-feature-editor.ts │ │ │ │ ├── hui-climate-hvac-modes-card-feature-editor.ts │ │ │ │ ├── hui-climate-preset-modes-card-feature-editor.ts │ │ │ │ ├── hui-climate-swing-horizontal-modes-card-feature-editor.ts │ │ │ │ ├── hui-climate-swing-modes-card-feature-editor.ts │ │ │ │ ├── hui-clock-card-editor.ts │ │ │ │ ├── hui-conditional-card-editor.ts │ │ │ │ ├── hui-counter-actions-card-feature-editor.ts │ │ │ │ ├── hui-entities-card-editor.ts │ │ │ │ ├── hui-entity-badge-editor.ts │ │ │ │ ├── hui-entity-card-editor.ts │ │ │ │ ├── hui-fan-preset-modes-card-feature-editor.ts │ │ │ │ ├── hui-form-editor.ts │ │ │ │ ├── hui-gauge-card-editor.ts │ │ │ │ ├── hui-generic-entity-row-editor.ts │ │ │ │ ├── hui-glance-card-editor.ts │ │ │ │ ├── hui-graph-footer-editor.ts │ │ │ │ ├── hui-grid-card-editor.ts │ │ │ │ ├── hui-heading-badges-editor.ts │ │ │ │ ├── hui-heading-card-editor.ts │ │ │ │ ├── hui-history-graph-card-editor.ts │ │ │ │ ├── hui-humidifier-card-editor.ts │ │ │ │ ├── hui-humidifier-modes-card-feature-editor.ts │ │ │ │ ├── hui-iframe-card-editor.ts │ │ │ │ ├── hui-lawn-mower-commands-card-feature-editor.ts │ │ │ │ ├── hui-light-card-editor.ts │ │ │ │ ├── hui-logbook-card-editor.ts │ │ │ │ ├── hui-map-card-editor.ts │ │ │ │ ├── hui-markdown-card-editor.ts │ │ │ │ ├── hui-media-control-card-editor.ts │ │ │ │ ├── hui-numeric-input-card-feature-editor.ts │ │ │ │ ├── hui-picture-card-editor.ts │ │ │ │ ├── hui-picture-elements-card-editor.ts │ │ │ │ ├── hui-picture-entity-card-editor.ts │ │ │ │ ├── hui-picture-glance-card-editor.ts │ │ │ │ ├── hui-plant-status-card-editor.ts │ │ │ │ ├── hui-select-options-card-feature-editor.ts │ │ │ │ ├── hui-sensor-card-editor.ts │ │ │ │ ├── hui-stack-card-editor.ts │ │ │ │ ├── hui-state-label-badge-editor.ts │ │ │ │ ├── hui-statistic-card-editor.ts │ │ │ │ ├── hui-statistics-graph-card-editor.ts │ │ │ │ ├── hui-thermostat-card-editor.ts │ │ │ │ ├── hui-tile-card-editor.ts │ │ │ │ ├── hui-todo-list-editor.ts │ │ │ │ ├── hui-update-actions-card-feature-editor.ts │ │ │ │ ├── hui-vacuum-commands-card-feature-editor.ts │ │ │ │ ├── hui-water-heater-operation-modes-card-feature-editor.ts │ │ │ │ └── hui-weather-forecast-card-editor.ts │ │ │ ├── config-util.ts │ │ │ ├── dashboard-strategy-editor │ │ │ │ ├── dialogs │ │ │ │ │ ├── dialog-dashboard-strategy-editor.ts │ │ │ │ │ └── show-dialog-dashboard-strategy-editor.ts │ │ │ │ ├── hui-dashboard-strategy-element-editor.ts │ │ │ │ ├── hui-iframe-dashboard-strategy-editor.ts │ │ │ │ └── hui-original-states-dashboard-strategy-editor.ts │ │ │ ├── delete-badge.ts │ │ │ ├── delete-card.ts │ │ │ ├── entity-row-editor │ │ │ │ └── hui-row-element-editor.ts │ │ │ ├── feature-editor │ │ │ │ └── hui-card-feature-element-editor.ts │ │ │ ├── get-badge-stub-config.ts │ │ │ ├── get-card-stub-config.ts │ │ │ ├── get-dashboard-documentation-url.ts │ │ │ ├── get-element-stub-config.ts │ │ │ ├── gui-support-error.ts │ │ │ ├── header-footer-editor │ │ │ │ ├── get-headerfooter-stub-config.ts │ │ │ │ ├── hui-dialog-create-headerfooter.ts │ │ │ │ ├── hui-header-footer-editor.ts │ │ │ │ ├── hui-header-footer-element-editor.ts │ │ │ │ └── show-create-headerfooter-dialog.ts │ │ │ ├── heading-badge-editor │ │ │ │ ├── hui-entity-heading-badge-editor.ts │ │ │ │ └── hui-heading-badge-element-editor.ts │ │ │ ├── hui-dialog-save-config.ts │ │ │ ├── hui-element-editor.ts │ │ │ ├── hui-entities-card-row-editor.ts │ │ │ ├── hui-picture-elements-card-row-editor.ts │ │ │ ├── hui-sub-element-editor.ts │ │ │ ├── hui-typed-element-editor.ts │ │ │ ├── lovelace-badges.ts │ │ │ ├── lovelace-cards.ts │ │ │ ├── lovelace-headerfooters.ts │ │ │ ├── lovelace-path.ts │ │ │ ├── picture-element-editor │ │ │ │ └── hui-picture-element-element-editor.ts │ │ │ ├── process-editor-entities.ts │ │ │ ├── section-editor │ │ │ │ ├── hui-dialog-edit-section.ts │ │ │ │ ├── hui-section-settings-editor.ts │ │ │ │ ├── hui-section-visibility-editor.ts │ │ │ │ └── show-edit-section-dialog.ts │ │ │ ├── select-dashboard │ │ │ │ ├── hui-dialog-select-dashboard.ts │ │ │ │ └── show-select-dashboard-dialog.ts │ │ │ ├── select-view │ │ │ │ ├── hui-dialog-select-view.ts │ │ │ │ └── show-select-view-dialog.ts │ │ │ ├── show-save-config-dialog.ts │ │ │ ├── structs │ │ │ │ ├── action-struct.ts │ │ │ │ ├── base-badge-struct.ts │ │ │ │ ├── base-card-struct.ts │ │ │ │ ├── button-entity-struct.ts │ │ │ │ └── entities-struct.ts │ │ │ ├── types.ts │ │ │ ├── unused-entities │ │ │ │ └── hui-unused-entities.ts │ │ │ ├── view-editor │ │ │ │ ├── hui-dialog-edit-view.ts │ │ │ │ ├── hui-view-background-editor.ts │ │ │ │ ├── hui-view-editor.ts │ │ │ │ ├── hui-view-visibility-editor.ts │ │ │ │ └── show-edit-view-dialog.ts │ │ │ └── view-header │ │ │ │ ├── hui-dialog-edit-view-header.ts │ │ │ │ ├── hui-view-header-settings-editor.ts │ │ │ │ └── show-edit-view-header-dialog.ts │ │ ├── elements │ │ │ ├── hui-conditional-element.ts │ │ │ ├── hui-icon-element.ts │ │ │ ├── hui-image-element.ts │ │ │ ├── hui-service-button-element.ts │ │ │ ├── hui-state-badge-element.ts │ │ │ ├── hui-state-icon-element.ts │ │ │ ├── hui-state-label-element.ts │ │ │ └── types.ts │ │ ├── entity-rows │ │ │ ├── hui-button-entity-row.ts │ │ │ ├── hui-climate-entity-row.ts │ │ │ ├── hui-cover-entity-row.ts │ │ │ ├── hui-date-entity-row.ts │ │ │ ├── hui-datetime-entity-row.ts │ │ │ ├── hui-event-entity-row.ts │ │ │ ├── hui-group-entity-row.ts │ │ │ ├── hui-humidifier-entity-row.ts │ │ │ ├── hui-input-button-entity-row.ts │ │ │ ├── hui-input-datetime-entity-row.ts │ │ │ ├── hui-input-number-entity-row.ts │ │ │ ├── hui-input-select-entity-row.ts │ │ │ ├── hui-input-text-entity-row.ts │ │ │ ├── hui-lock-entity-row.ts │ │ │ ├── hui-media-player-entity-row.ts │ │ │ ├── hui-number-entity-row.ts │ │ │ ├── hui-scene-entity-row.ts │ │ │ ├── hui-script-entity-row.ts │ │ │ ├── hui-select-entity-row.ts │ │ │ ├── hui-sensor-entity-row.ts │ │ │ ├── hui-simple-entity-row.ts │ │ │ ├── hui-text-entity-row.ts │ │ │ ├── hui-time-entity-row.ts │ │ │ ├── hui-timer-entity-row.ts │ │ │ ├── hui-toggle-entity-row.ts │ │ │ ├── hui-update-entity-row.ts │ │ │ ├── hui-valve-entity-row.ts │ │ │ ├── hui-weather-entity-row.ts │ │ │ └── types.ts │ │ ├── ha-panel-lovelace.ts │ │ ├── header-footer │ │ │ ├── hui-buttons-header-footer.ts │ │ │ ├── hui-graph-header-footer.ts │ │ │ ├── hui-picture-header-footer.ts │ │ │ ├── structs.ts │ │ │ └── types.ts │ │ ├── heading-badges │ │ │ ├── hui-entity-heading-badge.ts │ │ │ ├── hui-error-heading-badge.ts │ │ │ ├── hui-heading-badge.ts │ │ │ └── types.ts │ │ ├── hui-editor.ts │ │ ├── hui-root.ts │ │ ├── sections │ │ │ ├── const.ts │ │ │ ├── hui-error-section.ts │ │ │ ├── hui-grid-section.ts │ │ │ └── hui-section.ts │ │ ├── special-rows │ │ │ ├── hui-attribute-row.ts │ │ │ ├── hui-button-row.ts │ │ │ ├── hui-buttons-row.ts │ │ │ ├── hui-call-service-row.ts │ │ │ ├── hui-cast-row.ts │ │ │ ├── hui-conditional-row.ts │ │ │ ├── hui-divider-row.ts │ │ │ ├── hui-section-row.ts │ │ │ ├── hui-text-row.ts │ │ │ └── hui-weblink-row.ts │ │ ├── strategies │ │ │ ├── areas │ │ │ │ ├── area-view-strategy.ts │ │ │ │ ├── areas-dashboard-strategy.ts │ │ │ │ ├── areas-overview-view-strategy.ts │ │ │ │ ├── editor │ │ │ │ │ └── hui-areas-dashboard-strategy-editor.ts │ │ │ │ └── helpers │ │ │ │ │ └── areas-strategy-helper.ts │ │ │ ├── get-strategy.ts │ │ │ ├── iframe │ │ │ │ ├── iframe-dashboard-strategy.ts │ │ │ │ └── iframe-view-strategy.ts │ │ │ ├── legacy-strategy.ts │ │ │ ├── map │ │ │ │ ├── map-dashboard-strategy.ts │ │ │ │ └── map-view-strategy.ts │ │ │ ├── original-states │ │ │ │ ├── original-states-dashboard-strategy.ts │ │ │ │ └── original-states-view-strategy.ts │ │ │ └── types.ts │ │ ├── types.ts │ │ └── views │ │ │ ├── const.ts │ │ │ ├── default-section.ts │ │ │ ├── default-view-editable.ts │ │ │ ├── get-view-type.ts │ │ │ ├── hui-masonry-view.ts │ │ │ ├── hui-panel-view.ts │ │ │ ├── hui-sections-view.ts │ │ │ ├── hui-sidebar-view.ts │ │ │ ├── hui-view-background.ts │ │ │ ├── hui-view-container.ts │ │ │ ├── hui-view-header.ts │ │ │ └── hui-view.ts │ ├── map │ │ └── ha-panel-map.ts │ ├── media-browser │ │ ├── browser-media-player.ts │ │ ├── ha-bar-media-player.ts │ │ ├── ha-panel-media-browser.ts │ │ ├── hui-dialog-web-browser-play-media.ts │ │ └── show-media-player-dialog.ts │ ├── my │ │ └── ha-panel-my.ts │ ├── profile │ │ ├── dialog-ha-mfa-module-setup-flow.ts │ │ ├── ha-advanced-mode-row.ts │ │ ├── ha-change-password-card.ts │ │ ├── ha-enable-shortcuts-row.ts │ │ ├── ha-entity-id-picker-row.ts │ │ ├── ha-force-narrow-row.ts │ │ ├── ha-long-lived-access-token-dialog.ts │ │ ├── ha-long-lived-access-tokens-card.ts │ │ ├── ha-mfa-modules-card.ts │ │ ├── ha-panel-profile.ts │ │ ├── ha-pick-dashboard-row.ts │ │ ├── ha-pick-date-format-row.ts │ │ ├── ha-pick-first-weekday-row.ts │ │ ├── ha-pick-language-row.ts │ │ ├── ha-pick-number-format-row.ts │ │ ├── ha-pick-theme-row.ts │ │ ├── ha-pick-time-format-row.ts │ │ ├── ha-pick-time-zone-row.ts │ │ ├── ha-profile-section-general.ts │ │ ├── ha-profile-section-security.ts │ │ ├── ha-push-notifications-row.ts │ │ ├── ha-refresh-tokens-card.ts │ │ ├── ha-set-suspend-row.ts │ │ ├── ha-set-vibrate-row.ts │ │ ├── show-ha-mfa-module-setup-flow-dialog.ts │ │ └── show-long-lived-access-token-dialog.ts │ └── todo │ │ ├── dialog-todo-item-editor.ts │ │ ├── ha-panel-todo.ts │ │ └── show-dialog-todo-item-editor.ts ├── resources │ ├── append-ha-style.ts │ ├── codemirror.ts │ ├── css-variables.ts │ ├── custom-card-support.ts │ ├── echarts.ts │ ├── fuse.ts │ ├── hammer.ts │ ├── home-assistant-logo-svg.ts │ ├── icon-metadata.ts │ ├── log-message.ts │ ├── markdown-worker.ts │ ├── particles.ts │ ├── polyfills │ │ ├── element-getattributenames.ts │ │ ├── element-toggleattribute.ts │ │ ├── intl-polyfill.ts │ │ ├── locale-data-polyfill.ts │ │ └── resize-observer.ts │ ├── render-markdown.ts │ ├── roboto.ts │ ├── sortable.ts │ ├── styles.ts │ ├── svg-arc.ts │ ├── theme │ │ ├── color.globals.ts │ │ ├── main.globals.ts │ │ ├── theme.ts │ │ └── typography.globals.ts │ ├── translations-metadata.ts │ └── virtualizer.ts ├── state-control │ ├── alarm_control_panel │ │ └── ha-state-control-alarm_control_panel-modes.ts │ ├── climate │ │ ├── ha-state-control-climate-humidity.ts │ │ └── ha-state-control-climate-temperature.ts │ ├── cover │ │ ├── ha-state-control-cover-buttons.ts │ │ ├── ha-state-control-cover-position.ts │ │ ├── ha-state-control-cover-tilt-position.ts │ │ └── ha-state-control-cover-toggle.ts │ ├── fan │ │ └── ha-state-control-fan-speed.ts │ ├── ha-state-control-toggle.ts │ ├── humidifier │ │ └── ha-state-control-humidifier-humidity.ts │ ├── light │ │ └── ha-state-control-light-brightness.ts │ ├── lock │ │ └── ha-state-control-lock-toggle.ts │ ├── state-control-circular-slider-style.ts │ ├── valve │ │ ├── ha-state-control-valve-buttons.ts │ │ ├── ha-state-control-valve-position.ts │ │ └── ha-state-control-valve-toggle.ts │ └── water_heater │ │ └── ha-state-control-water_heater-temperature.ts ├── state-display │ ├── ha-timer-remaining-time.ts │ └── state-display.ts ├── state-summary │ ├── state-card-alert.ts │ ├── state-card-button.ts │ ├── state-card-climate.ts │ ├── state-card-configurator.ts │ ├── state-card-content.ts │ ├── state-card-cover.ts │ ├── state-card-display.ts │ ├── state-card-event.ts │ ├── state-card-humidifier.ts │ ├── state-card-input_button.ts │ ├── state-card-input_number.ts │ ├── state-card-input_select.ts │ ├── state-card-input_text.ts │ ├── state-card-lawn_mower.ts │ ├── state-card-lock.ts │ ├── state-card-media_player.ts │ ├── state-card-number.ts │ ├── state-card-scene.ts │ ├── state-card-script.ts │ ├── state-card-select.ts │ ├── state-card-text.ts │ ├── state-card-timer.ts │ ├── state-card-toggle.ts │ ├── state-card-update.ts │ ├── state-card-vacuum.ts │ └── state-card-water_heater.ts ├── state │ ├── action-mixin.ts │ ├── auth-mixin.ts │ ├── connection-mixin.ts │ ├── context-mixin.ts │ ├── dialog-manager-mixin.ts │ ├── disconnect-toast-mixin.ts │ ├── haptic-mixin.ts │ ├── hass-base-mixin.ts │ ├── hass-element.ts │ ├── logging-mixin.ts │ ├── more-info-mixin.ts │ ├── notification-mixin.ts │ ├── panel-title-mixin.ts │ ├── quick-bar-mixin.ts │ ├── sidebar-mixin.ts │ ├── state-display-mixin.ts │ ├── themes-mixin.ts │ ├── translations-mixin.ts │ └── url-sync-mixin.ts ├── translations │ ├── en.json │ └── translationMetadata.json ├── types.ts ├── types │ ├── audio.d.ts │ ├── echarts.d.ts │ ├── node-vibrant.d.ts │ └── service-worker.d.ts └── util │ ├── audio-recorder.ts │ ├── brands-url.ts │ ├── bytes-to-string.ts │ ├── cache-manager.ts │ ├── calculate.ts │ ├── common-translation.ts │ ├── custom-panel │ ├── create-custom-panel-element.ts │ ├── load-custom-panel.ts │ └── set-custom-panel-properties.ts │ ├── documentation-url.ts │ ├── empty.js │ ├── fetch-with-auth.ts │ ├── file_download.ts │ ├── ha-pref-storage.ts │ ├── hass-call-api.ts │ ├── hass-media-player-model.ts │ ├── iframe.ts │ ├── is_ios.ts │ ├── is_mac.ts │ ├── is_mobile.ts │ ├── is_safari.ts │ ├── is_touch.ts │ ├── launch-screen.ts │ ├── recorder-worklet.js │ ├── register-service-worker.ts │ ├── text.ts │ ├── toast-saved-success.ts │ ├── toast.ts │ └── url.ts ├── test ├── common │ ├── array │ │ ├── combination.test.ts │ │ ├── ensure-array.test.ts │ │ └── literal-includes.test.ts │ ├── auth │ │ └── token_storage │ │ │ ├── askWrite.test.ts │ │ │ ├── saveTokens.test.ts │ │ │ └── token_storage.test.ts │ ├── color │ │ ├── colors.test.ts │ │ ├── compute-color.test.ts │ │ ├── convert-color.test.ts │ │ ├── convert-light-color.test.ts │ │ ├── hex.test.ts │ │ ├── lab.test.ts │ │ └── rgb.test.ts │ ├── config │ │ ├── can_show_page.test.ts │ │ ├── components_with_service.test.ts │ │ ├── is_component_loaded.test.ts │ │ ├── is_pwa.test.ts │ │ ├── is_service_loaded.test.ts │ │ ├── location_name.test.ts │ │ └── version.test.ts │ ├── datetime │ │ ├── absolute_time.test.ts │ │ ├── calc_date.test.ts │ │ ├── check_valid_date.test.ts │ │ ├── create_duration_data.test.ts │ │ ├── duration_to_seconds.test.ts │ │ ├── first_weekday.test.ts │ │ ├── format_date.test.ts │ │ ├── format_date_time.test.ts │ │ ├── format_duration.test.ts │ │ ├── format_time.test.ts │ │ ├── localize_date.test.ts │ │ ├── milliseconds_to_duration.test.ts │ │ ├── relative_time.test.ts │ │ ├── resolve-time-zone.test.ts │ │ ├── seconds_to_duration.test.ts │ │ ├── shift_date_range.test.ts │ │ └── use_am_pm.test.ts │ ├── entity │ │ ├── attribute_class_names.test.ts │ │ ├── battery_icon.test.ts │ │ ├── can_toggle_domain.test.ts │ │ ├── can_toggle_state.test.ts │ │ ├── color │ │ │ └── battery_color.test.ts │ │ ├── compute_area_name.test.ts │ │ ├── compute_attribute_display.test.ts │ │ ├── compute_device_name.test.ts │ │ ├── compute_domain.test.ts │ │ ├── compute_entity_name.test.ts │ │ ├── compute_floor_name.test.ts │ │ ├── compute_state_display.test.ts │ │ ├── compute_state_domain.test.ts │ │ ├── compute_state_name.test.ts │ │ ├── context │ │ │ ├── context-mock.ts │ │ │ ├── get_area_context.test.ts │ │ │ ├── get_device_context.test.ts │ │ │ └── get_entity_context.test.ts │ │ ├── cover_icon.test.ts │ │ ├── delete_entity.test.ts │ │ ├── entity_domain_filter.test.ts │ │ ├── extract_views.test.ts │ │ ├── feature_class_names.test.ts │ │ ├── get_group_entities.test.ts │ │ ├── get_view_entities.test.ts │ │ ├── has_location.test.ts │ │ ├── split_by_groups.test.ts │ │ ├── state_card_type.test.ts │ │ ├── state_color.ts │ │ ├── state_more_info_type.test.ts │ │ ├── test_util.ts │ │ └── timer_time_remaining.test.ts │ ├── string │ │ ├── format_number.test.ts │ │ ├── get_duplicate.test.ts │ │ ├── is_date.test.ts │ │ ├── sequence_matching.test.ts │ │ └── slugify.test.ts │ └── util │ │ └── parse_aspect_ratio.test.ts ├── data │ ├── energy.test.ts │ └── image_upload.test.ts ├── external_app │ ├── external_app_entrypoint.test.ts │ └── external_messaging.test.ts ├── hassio │ └── create_session.test.ts ├── panels │ └── lovelace │ │ └── editor │ │ └── config-util.test.ts ├── setup.ts ├── test_helper │ ├── local-storage-fallback.test.ts │ └── local-storage-fallback.ts ├── util │ ├── cache-manager.test.ts │ ├── calculate.test.ts │ ├── generate-brands-url.test.ts │ ├── generate-documentation-url.test.ts │ └── ha-pref-storage.test.ts └── vitest.config.ts ├── tsconfig.json └── yarn.lock /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/python:1-3.13 2 | 3 | ENV \ 4 | DEBIAN_FRONTEND=noninteractive \ 5 | DEVCONTAINER=true \ 6 | PATH=$PATH:./node_modules/.bin 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Ensure Docker script files uses LF to support Docker for Windows. 2 | # Ensure "git config --global core.autocrlf input" before you clone 3 | * text eol=lf 4 | *.ts whitespace=error 5 | *.js whitespace=error 6 | 7 | *.ico binary 8 | *.jpg binary 9 | *.png binary 10 | *.zip binary 11 | *.mp3 binary 12 | 13 | demo/public/api/camera_proxy_stream/* binary 14 | demo/public/api/media_player_proxy/* binary 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | time: "06:00" 8 | open-pull-requests-limit: 10 9 | labels: 10 | - Dependencies 11 | - GitHub Actions 12 | -------------------------------------------------------------------------------- /.github/move.yml: -------------------------------------------------------------------------------- 1 | # Configuration for move-issues - https://github.com/dessant/move-issues 2 | 3 | # Delete the command comment. Ignored when the comment also contains other content 4 | deleteCommand: true 5 | # Close the source issue after moving 6 | closeSourceIssue: true 7 | # Lock the source issue after moving 8 | lockSourceIssue: false 9 | # Set custom aliases for targets 10 | # aliases: 11 | # r: repo 12 | # or: owner/repo 13 | 14 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | categories: 2 | - title: "Dependency updates" 3 | collapse-after: 3 4 | labels: 5 | - "Dependencies" 6 | template: | 7 | ## What's Changed 8 | 9 | $CHANGES 10 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yaml: -------------------------------------------------------------------------------- 1 | name: "Pull Request Labeler" 2 | 3 | on: pull_request_target 4 | 5 | jobs: 6 | triage: 7 | permissions: 8 | contents: read 9 | pull-requests: write 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Apply labels 13 | uses: actions/labeler@v5.0.0 14 | with: 15 | sync-labels: true 16 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: Lock 2 | 3 | # yamllint disable-line rule:truthy 4 | on: 5 | schedule: 6 | - cron: "0 * * * *" 7 | 8 | jobs: 9 | lock: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: dessant/lock-threads@v5.0.1 13 | with: 14 | github-token: ${{ github.token }} 15 | process-only: "issues, prs" 16 | issue-lock-inactive-days: "30" 17 | issue-exclude-created-before: "2020-10-01T00:00:00Z" 18 | issue-lock-reason: "" 19 | pr-lock-inactive-days: "1" 20 | pr-exclude-created-before: "2020-11-01T00:00:00Z" 21 | pr-lock-reason: "" 22 | -------------------------------------------------------------------------------- /.github/workflows/translations.yaml: -------------------------------------------------------------------------------- 1 | name: Translations 2 | 3 | on: 4 | push: 5 | branches: 6 | - dev 7 | paths: 8 | - src/translations/en.json 9 | 10 | jobs: 11 | upload: 12 | name: Upload 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout the repository 16 | uses: actions/checkout@v4.2.2 17 | 18 | - name: Upload Translations 19 | run: | 20 | export LOKALISE_TOKEN="${{ secrets.LOKALISE_TOKEN }}" 21 | ./script/translations_upload_base 22 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/.gitmodules -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | yarn run lint-staged --relative 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/iron 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | CLA.md 2 | CODE_OF_CONDUCT.md 3 | LICENSE.md 4 | PULL_REQUEST_TEMPLATE.md -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "runem.lit-plugin", 6 | "github.vscode-pull-request-github", 7 | "eamodio.gitlens", 8 | "vitest.explorer", 9 | "yeion7.styled-global-variables-autocomplete" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | defaultSemverRangePrefix: "" 4 | 5 | enableGlobalCache: false 6 | 7 | nodeLinker: node-modules 8 | 9 | yarnPath: .yarn/releases/yarn-4.9.1.cjs 10 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | graft hass_frontend 3 | graft hass_frontend_es5 4 | recursive-exclude * *.py[co] 5 | -------------------------------------------------------------------------------- /build-scripts/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import tseslint from "typescript-eslint"; 4 | import rootConfig from "../eslint.config.mjs"; 5 | 6 | export default tseslint.config(...rootConfig, { 7 | rules: { 8 | "no-console": "off", 9 | "import/no-extraneous-dependencies": "off", 10 | "import/extensions": "off", 11 | "import/no-dynamic-require": "off", 12 | "global-require": "off", 13 | "@typescript-eslint/no-require-imports": "off", 14 | "prefer-arrow-callback": "off", 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /build-scripts/gulp/index.mjs: -------------------------------------------------------------------------------- 1 | import "./app.js"; 2 | import "./cast.js"; 3 | import "./clean.js"; 4 | import "./compress.js"; 5 | import "./demo.js"; 6 | import "./download-translations.js"; 7 | import "./entry-html.js"; 8 | import "./fetch-nightly-translations.js"; 9 | import "./gallery.js"; 10 | import "./gather-static.js"; 11 | import "./gen-icons-json.js"; 12 | import "./hassio.js"; 13 | import "./landing-page.js"; 14 | import "./locale-data.js"; 15 | import "./rspack.js"; 16 | import "./service-worker.js"; 17 | import "./translations.js"; 18 | -------------------------------------------------------------------------------- /build-scripts/removedIcons.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /cast/public/_redirects: -------------------------------------------------------------------------------- 1 | # These redirects are handled by Netlify 2 | # 3 | 4 | # Some custom cards are not prefixing the instance URL when fetching data 5 | # and can end up fetching the data from the Cast domain instead of HA. 6 | # This will make sure that some common ones are replaced with a placeholder. 7 | /api/camera_proxy/* /images/google-nest-hub.png 8 | /api/camera_proxy_stream/* /images/google-nest-hub.png 9 | /api/media_player_proxy/* /images/google-nest-hub.png 10 | -------------------------------------------------------------------------------- /cast/public/images/arsaboo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/cast/public/images/arsaboo.jpg -------------------------------------------------------------------------------- /cast/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/cast/public/images/favicon.ico -------------------------------------------------------------------------------- /cast/public/images/google-nest-hub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/cast/public/images/google-nest-hub.png -------------------------------------------------------------------------------- /cast/public/images/ha-cast-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/cast/public/images/ha-cast-icon.png -------------------------------------------------------------------------------- /cast/public/images/melody.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/cast/public/images/melody.jpg -------------------------------------------------------------------------------- /cast/public/images/nabu-loves-hass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/cast/public/images/nabu-loves-hass.png -------------------------------------------------------------------------------- /cast/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "background_color": "#FFFFFF", 3 | "description": "Show Home Assistant on your Chromecast or Google Assistant devices with a screen.", 4 | "dir": "ltr", 5 | "display": "standalone", 6 | "icons": [ 7 | { 8 | "src": "/images/ha-cast-icon.png", 9 | "sizes": "512x512", 10 | "type": "image/png" 11 | } 12 | ], 13 | "lang": "en-US", 14 | "name": "Home Assistant Cast", 15 | "short_name": "HA Cast", 16 | "start_url": "/?homescreen=1", 17 | "theme_color": "#03A9F4" 18 | } 19 | -------------------------------------------------------------------------------- /cast/public/sw-legacy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | self.addEventListener("fetch", (event) => { 4 | event.respondWith(fetch(event.request)); 5 | }); 6 | -------------------------------------------------------------------------------- /cast/public/sw-modern.js: -------------------------------------------------------------------------------- 1 | self.addEventListener("fetch", (event) => { 2 | event.respondWith(fetch(event.request)); 3 | }); 4 | -------------------------------------------------------------------------------- /cast/script/build_cast: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Build the cast receiver 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp build-cast 10 | -------------------------------------------------------------------------------- /cast/script/develop_cast: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Develop the cast receiver 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp develop-cast 10 | -------------------------------------------------------------------------------- /cast/script/upload: -------------------------------------------------------------------------------- 1 | # Run it twice, second time we just delete. 2 | aws s3 sync dist s3://cast.home-assistant.io --acl public-read 3 | # Don't delete as it might break open sites that need to load code splitted things. 4 | # aws s3 sync dist s3://cast.home-assistant.io --acl public-read --delete 5 | # Todo : update JS first, HTML last. 6 | -------------------------------------------------------------------------------- /cast/src/html/receiver.html.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% for (const entry of latestEntryJS) { %> 5 | 6 | <% } %> 7 | <%= renderTemplate("../../../src/html/_style_base.html.template") %> 8 | 13 | 14 | -------------------------------------------------------------------------------- /cast/src/launcher/entrypoint.ts: -------------------------------------------------------------------------------- 1 | import "./layout/hc-connect"; 2 | 3 | import("../../../src/resources/append-ha-style"); 4 | -------------------------------------------------------------------------------- /cast/src/receiver/cast_context.ts: -------------------------------------------------------------------------------- 1 | import { framework } from "./cast_framework"; 2 | 3 | export const castContext = framework.CastReceiverContext.getInstance(); 4 | -------------------------------------------------------------------------------- /cast/src/receiver/cast_framework.ts: -------------------------------------------------------------------------------- 1 | import type { cast as ReceiverCast } from "chromecast-caf-receiver"; 2 | 3 | export const framework = (cast as unknown as typeof ReceiverCast).framework; 4 | -------------------------------------------------------------------------------- /cast/src/receiver/types.ts: -------------------------------------------------------------------------------- 1 | export interface ReceivedMessage { 2 | gj: boolean; 3 | data: T; 4 | senderId: string; 5 | type: "message"; 6 | } 7 | -------------------------------------------------------------------------------- /demo/public/_headers: -------------------------------------------------------------------------------- 1 | /* 2 | Cache-Control: public, max-age: 0, s-maxage=3600, must-revalidate 3 | Content-Security-Policy: form-action https: 4 | Referrer-Policy: no-referrer-when-downgrade 5 | X-Content-Type-Options: nosniff 6 | X-XSS-Protection: 1; mode=block 7 | 8 | /api/* 9 | Cache-Control: public, max-age: 604800, s-maxage=604800 10 | 11 | /assets/* 12 | Cache-Control: public, max-age: 604800, s-maxage=604800 13 | 14 | /frontend_es5/* 15 | Cache-Control: public, max-age: 604800, s-maxage=604800 16 | 17 | /frontend_latest/* 18 | Cache-Control: public, max-age: 604800, s-maxage=604800 19 | -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/floorplans/ecobee_blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/floorplans/ecobee_blank.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/floorplans/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/floorplans/main.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/floorplans/second.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/floorplans/second.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/Harmony.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/Harmony.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/abode_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/abode_disabled.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/abode_enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/abode_enabled.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/automation_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/automation_disabled.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/automation_enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/automation_enabled.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/camera_backyard_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/camera_backyard_recording.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/camera_backyard_streaming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/camera_backyard_streaming.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/camera_driveway_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/camera_driveway_recording.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/camera_driveway_streaming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/camera_driveway_streaming.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/camera_patio_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/camera_patio_recording.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/camera_patio_streaming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/camera_patio_streaming.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/camera_porch_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/camera_porch_recording.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/camera_porch_streaming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/camera_porch_streaming.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/ecobee_blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/ecobee_blank.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/garage_door_closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/garage_door_closed.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/garage_door_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/garage_door_open.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/light_bulb_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/light_bulb_off.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/light_bulb_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/light_bulb_on.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/light_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/light_off.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/light_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/light_on.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/security_armed_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/security_armed_red.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/security_disarmed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/security_disarmed.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/tv_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/tv_disabled.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/tv_enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/tv_enabled.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/tv_off2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/tv_off2.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/icons/tv_on2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/icons/tv_on2.png -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/images/arsaboo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/images/arsaboo.jpg -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/images/camera.backyard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/images/camera.backyard.jpg -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/images/camera.driveway.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/images/camera.driveway.jpg -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/images/camera.patio.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/images/camera.patio.jpg -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/images/camera.porch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/images/camera.porch.jpg -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/images/media_player_family_room.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/images/media_player_family_room.jpg -------------------------------------------------------------------------------- /demo/public/assets/arsaboo/images/melody.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/arsaboo/images/melody.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/background-15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/background-15.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/cardbackK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/cardbackK.png -------------------------------------------------------------------------------- /demo/public/assets/jimpower/home/bus_10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/home/bus_10.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/home/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/home/git.png -------------------------------------------------------------------------------- /demo/public/assets/jimpower/home/house_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/home/house_4.png -------------------------------------------------------------------------------- /demo/public/assets/jimpower/home/james_10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/home/james_10.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/home/tina_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/home/tina_4.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/security/air_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/security/air_8.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/security/alarm_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/security/alarm_3.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/security/door_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/security/door_3.png -------------------------------------------------------------------------------- /demo/public/assets/jimpower/security/leak_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/security/leak_2.png -------------------------------------------------------------------------------- /demo/public/assets/jimpower/security/motion_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/security/motion_3.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/security/smoke_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/security/smoke_4.jpg -------------------------------------------------------------------------------- /demo/public/assets/jimpower/security/window_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/jimpower/security/window_2.jpg -------------------------------------------------------------------------------- /demo/public/assets/kernehed/bella.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/kernehed/bella.jpg -------------------------------------------------------------------------------- /demo/public/assets/kernehed/camera.entre.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/kernehed/camera.entre.jpg -------------------------------------------------------------------------------- /demo/public/assets/kernehed/oscar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/kernehed/oscar.jpg -------------------------------------------------------------------------------- /demo/public/assets/sections/images/media_player_family_room.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/sections/images/media_player_family_room.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/House_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/House_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/Stefan_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/Stefan_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/background_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/background_square.png -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/cleaning_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/cleaning_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/clothes_drying_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/clothes_drying_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/dryer_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/dryer_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/folded_clothes_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/folded_clothes_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/guests_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/guests_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/isa_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/isa_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/laundry_clean_2_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/laundry_clean_2_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/laundry_running_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/laundry_running_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/mailbox_bw_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/mailbox_bw_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/mailbox_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/mailbox_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/meteogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/meteogram.png -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/plants.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/plants.png -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/radiator_off.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/radiator_off.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/radiator_on.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/radiator_on.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/roomba_bw_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/roomba_bw_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/roomba_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/roomba_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/trash_bear_bw_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/trash_bear_bw_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/trash_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/trash_square.jpg -------------------------------------------------------------------------------- /demo/public/assets/teachingbirds/washer_square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/assets/teachingbirds/washer_square.jpg -------------------------------------------------------------------------------- /demo/public/stub_config/bedroom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/stub_config/bedroom.png -------------------------------------------------------------------------------- /demo/public/stub_config/floorplan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/stub_config/floorplan.png -------------------------------------------------------------------------------- /demo/public/stub_config/kitchen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/stub_config/kitchen.png -------------------------------------------------------------------------------- /demo/public/stub_config/t-shirt-promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/demo/public/stub_config/t-shirt-promo.png -------------------------------------------------------------------------------- /demo/public/sw-legacy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | self.addEventListener("fetch", (event) => { 4 | event.respondWith(fetch(event.request)); 5 | }); 6 | -------------------------------------------------------------------------------- /demo/public/sw-modern.js: -------------------------------------------------------------------------------- 1 | self.addEventListener("fetch", (event) => { 2 | event.respondWith(fetch(event.request)); 3 | }); 4 | -------------------------------------------------------------------------------- /demo/script/build_demo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Build the demo 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp build-demo 10 | -------------------------------------------------------------------------------- /demo/script/develop_demo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Develop the demo 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp develop-demo 10 | -------------------------------------------------------------------------------- /demo/script/size_stats: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Analyze stats 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp analyze-demo -------------------------------------------------------------------------------- /demo/src/configs/arsaboo/index.ts: -------------------------------------------------------------------------------- 1 | import type { DemoConfig } from "../types"; 2 | import { demoEntitiesArsaboo } from "./entities"; 3 | import { demoLovelaceArsaboo } from "./lovelace"; 4 | import { demoThemeArsaboo } from "./theme"; 5 | 6 | export const demoArsaboo: DemoConfig = { 7 | authorName: "Arsaboo", 8 | authorUrl: "https://github.com/arsaboo/homeassistant-config/", 9 | name: "ARS Home", 10 | lovelace: demoLovelaceArsaboo, 11 | entities: demoEntitiesArsaboo, 12 | theme: demoThemeArsaboo, 13 | }; 14 | -------------------------------------------------------------------------------- /demo/src/configs/arsaboo/theme.ts: -------------------------------------------------------------------------------- 1 | export const demoThemeArsaboo = () => ({}); 2 | -------------------------------------------------------------------------------- /demo/src/configs/jimpower/index.ts: -------------------------------------------------------------------------------- 1 | import type { DemoConfig } from "../types"; 2 | import { demoEntitiesJimpower } from "./entities"; 3 | import { demoLovelaceJimpower } from "./lovelace"; 4 | import { demoThemeJimpower } from "./theme"; 5 | 6 | export const demoJimpower: DemoConfig = { 7 | authorName: "Jimpower", 8 | authorUrl: "https://github.com/JamesMcCarthy79/Home-Assistant-Config", 9 | name: "Kingia Castle", 10 | lovelace: demoLovelaceJimpower, 11 | entities: demoEntitiesJimpower, 12 | theme: demoThemeJimpower, 13 | }; 14 | -------------------------------------------------------------------------------- /demo/src/configs/kernehed/index.ts: -------------------------------------------------------------------------------- 1 | import type { DemoConfig } from "../types"; 2 | import { demoEntitiesKernehed } from "./entities"; 3 | import { demoLovelaceKernehed } from "./lovelace"; 4 | import { demoThemeKernehed } from "./theme"; 5 | 6 | export const demoKernehed: DemoConfig = { 7 | authorName: "Kernehed", 8 | authorUrl: "https://github.com/kernehed", 9 | name: "Hem", 10 | lovelace: demoLovelaceKernehed, 11 | entities: demoEntitiesKernehed, 12 | theme: demoThemeKernehed, 13 | }; 14 | -------------------------------------------------------------------------------- /demo/src/configs/sections/index.ts: -------------------------------------------------------------------------------- 1 | import type { DemoConfig } from "../types"; 2 | import { demoEntitiesSections } from "./entities"; 3 | import { demoLovelaceSections } from "./lovelace"; 4 | 5 | export const demoSections: DemoConfig = { 6 | authorName: "Home Assistant", 7 | authorUrl: "https://github.com/home-assistant/frontend/", 8 | name: "Home Demo", 9 | lovelace: demoLovelaceSections, 10 | entities: demoEntitiesSections, 11 | theme: () => ({}), 12 | }; 13 | -------------------------------------------------------------------------------- /demo/src/configs/teachingbirds/index.ts: -------------------------------------------------------------------------------- 1 | import type { DemoConfig } from "../types"; 2 | import { demoEntitiesTeachingbirds } from "./entities"; 3 | import { demoLovelaceTeachingbirds } from "./lovelace"; 4 | import { demoThemeTeachingbirds } from "./theme"; 5 | 6 | export const demoTeachingbirds: DemoConfig = { 7 | authorName: "Isabella Gross Alström", 8 | authorUrl: "https://github.com/isabellaalstrom/", 9 | name: "Isa's mobile friendly LL", 10 | lovelace: demoLovelaceTeachingbirds, 11 | entities: demoEntitiesTeachingbirds, 12 | theme: demoThemeTeachingbirds, 13 | }; 14 | -------------------------------------------------------------------------------- /demo/src/entrypoint.ts: -------------------------------------------------------------------------------- 1 | import "./util/is_frontpage"; 2 | import "./ha-demo"; 3 | 4 | import("../../src/resources/append-ha-style"); 5 | -------------------------------------------------------------------------------- /demo/src/stubs/area_registry.ts: -------------------------------------------------------------------------------- 1 | import type { AreaRegistryEntry } from "../../../src/data/area_registry"; 2 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 3 | 4 | export const mockAreaRegistry = ( 5 | hass: MockHomeAssistant, 6 | data: AreaRegistryEntry[] = [] 7 | ) => { 8 | hass.mockWS("config/area_registry/list", () => data); 9 | const areas = {}; 10 | data.forEach((area) => { 11 | areas[area.area_id] = area; 12 | }); 13 | hass.updateHass({ areas }); 14 | }; 15 | -------------------------------------------------------------------------------- /demo/src/stubs/auth.ts: -------------------------------------------------------------------------------- 1 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 2 | 3 | export const mockAuth = (hass: MockHomeAssistant) => { 4 | hass.mockWS("config/auth/list", () => []); 5 | hass.mockWS("auth/refresh_tokens", () => []); 6 | }; 7 | -------------------------------------------------------------------------------- /demo/src/stubs/config.ts: -------------------------------------------------------------------------------- 1 | import type { validateConfig } from "../../../src/data/config"; 2 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 3 | 4 | export const mockConfig = (hass: MockHomeAssistant) => { 5 | hass.mockWS("validate_config", () => ({ 6 | actions: { valid: true, error: null }, 7 | conditions: { valid: true, error: null }, 8 | triggers: { valid: true, error: null }, 9 | })); 10 | }; 11 | -------------------------------------------------------------------------------- /demo/src/stubs/device_registry.ts: -------------------------------------------------------------------------------- 1 | import type { DeviceRegistryEntry } from "../../../src/data/device_registry"; 2 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 3 | 4 | export const mockDeviceRegistry = ( 5 | hass: MockHomeAssistant, 6 | data: DeviceRegistryEntry[] = [] 7 | ) => { 8 | hass.mockWS("config/device_registry/list", () => data); 9 | const devices = {}; 10 | data.forEach((device) => { 11 | devices[device.id] = device; 12 | }); 13 | hass.updateHass({ devices }); 14 | }; 15 | -------------------------------------------------------------------------------- /demo/src/stubs/entity_registry.ts: -------------------------------------------------------------------------------- 1 | import type { EntityRegistryEntry } from "../../../src/data/entity_registry"; 2 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 3 | 4 | export const mockEntityRegistry = ( 5 | hass: MockHomeAssistant, 6 | data: EntityRegistryEntry[] = [] 7 | ) => { 8 | hass.mockWS("config/entity_registry/list", () => data); 9 | }; 10 | -------------------------------------------------------------------------------- /demo/src/stubs/events.ts: -------------------------------------------------------------------------------- 1 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 2 | 3 | export const mockEvents = (hass: MockHomeAssistant) => { 4 | hass.mockAPI("events", () => []); 5 | }; 6 | -------------------------------------------------------------------------------- /demo/src/stubs/floor_registry.ts: -------------------------------------------------------------------------------- 1 | import type { FloorRegistryEntry } from "../../../src/data/floor_registry"; 2 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 3 | 4 | export const mockFloorRegistry = ( 5 | hass: MockHomeAssistant, 6 | data: FloorRegistryEntry[] = [] 7 | ) => hass.mockWS("config/floor_registry/list", () => data); 8 | -------------------------------------------------------------------------------- /demo/src/stubs/label_registry.ts: -------------------------------------------------------------------------------- 1 | import type { LabelRegistryEntry } from "../../../src/data/label_registry"; 2 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 3 | 4 | export const mockLabelRegistry = ( 5 | hass: MockHomeAssistant, 6 | data: LabelRegistryEntry[] = [] 7 | ) => hass.mockWS("config/label_registry/list", () => data); 8 | -------------------------------------------------------------------------------- /demo/src/stubs/media_player.ts: -------------------------------------------------------------------------------- 1 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 2 | 3 | export const mockMediaPlayer = (hass: MockHomeAssistant) => { 4 | hass.mockWS("media_player_thumbnail", () => Promise.reject()); 5 | }; 6 | -------------------------------------------------------------------------------- /demo/src/stubs/system_log.ts: -------------------------------------------------------------------------------- 1 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 2 | 3 | export const mockSystemLog = (hass: MockHomeAssistant) => { 4 | hass.mockAPI("error/all", () => []); 5 | }; 6 | -------------------------------------------------------------------------------- /demo/src/stubs/tags.ts: -------------------------------------------------------------------------------- 1 | import type { Tag } from "../../../src/data/tag"; 2 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 3 | 4 | export const mockTags = (hass: MockHomeAssistant) => { 5 | hass.mockWS("tag/list", () => [{ id: "my-tag", name: "My Tag" }] as Tag[]); 6 | }; 7 | -------------------------------------------------------------------------------- /demo/src/stubs/template.ts: -------------------------------------------------------------------------------- 1 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 2 | 3 | export const mockTemplate = (hass: MockHomeAssistant) => { 4 | hass.mockAPI("template", () => 5 | Promise.reject({ 6 | body: { message: "Template dev tool does not work in the demo." }, 7 | }) 8 | ); 9 | hass.mockWS("render_template", (msg, _hass, onChange) => { 10 | onChange!({ 11 | result: msg.template, 12 | listeners: { all: false, domains: [], entities: [], time: false }, 13 | }); 14 | // eslint-disable-next-line @typescript-eslint/no-empty-function 15 | return () => {}; 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /demo/src/stubs/translations.ts: -------------------------------------------------------------------------------- 1 | import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; 2 | 3 | export const mockTranslations = (hass: MockHomeAssistant) => { 4 | hass.mockWS( 5 | "frontend/get_translations", 6 | (/* msg: {language: string, category: string} */) => ({ resources: {} }) 7 | ); 8 | }; 9 | -------------------------------------------------------------------------------- /demo/src/util/is_frontpage.ts: -------------------------------------------------------------------------------- 1 | export const isFrontpageEmbed = document.location.search === "?frontpage"; 2 | -------------------------------------------------------------------------------- /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/docs/screenshot.png -------------------------------------------------------------------------------- /gallery/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import tseslint from "typescript-eslint"; 4 | import rootConfig from "../eslint.config.mjs"; 5 | 6 | export default tseslint.config(...rootConfig, { 7 | rules: { 8 | "no-console": "off", 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /gallery/public/api/hassio/addons/core_zwave_js/icon: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/api/hassio/addons/core_zwave_js/icon -------------------------------------------------------------------------------- /gallery/public/api/media_player_proxy/media_player.bedroom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/api/media_player_proxy/media_player.bedroom -------------------------------------------------------------------------------- /gallery/public/api/media_player_proxy/media_player.living_room: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/api/media_player_proxy/media_player.living_room -------------------------------------------------------------------------------- /gallery/public/api/media_player_proxy/media_player.walkman: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/api/media_player_proxy/media_player.walkman -------------------------------------------------------------------------------- /gallery/public/images/album_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/album_cover.jpg -------------------------------------------------------------------------------- /gallery/public/images/album_cover_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/album_cover_2.jpg -------------------------------------------------------------------------------- /gallery/public/images/bed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/bed.png -------------------------------------------------------------------------------- /gallery/public/images/brand/README.md: -------------------------------------------------------------------------------- 1 | # Note! 2 | 3 | Note, the assets in this folder, are not part of the CC license this repository is shipped in. 4 | All rights reserved. 5 | -------------------------------------------------------------------------------- /gallery/public/images/brand/logo-exclusion-zone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/brand/logo-exclusion-zone.png -------------------------------------------------------------------------------- /gallery/public/images/brand/logo-layout-variants.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/brand/logo-layout-variants.png -------------------------------------------------------------------------------- /gallery/public/images/brand/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/brand/logo.png -------------------------------------------------------------------------------- /gallery/public/images/clearspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/clearspace.png -------------------------------------------------------------------------------- /gallery/public/images/divider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/divider.png -------------------------------------------------------------------------------- /gallery/public/images/floorplan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/floorplan.png -------------------------------------------------------------------------------- /gallery/public/images/frenck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/frenck.jpg -------------------------------------------------------------------------------- /gallery/public/images/kitchen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/kitchen.png -------------------------------------------------------------------------------- /gallery/public/images/light_bulb_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/light_bulb_off.png -------------------------------------------------------------------------------- /gallery/public/images/light_bulb_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/light_bulb_on.png -------------------------------------------------------------------------------- /gallery/public/images/living_room.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/living_room.png -------------------------------------------------------------------------------- /gallery/public/images/logo-variants.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/logo-variants.png -------------------------------------------------------------------------------- /gallery/public/images/logo-with-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/logo-with-text.png -------------------------------------------------------------------------------- /gallery/public/images/netflix.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/netflix.jpg -------------------------------------------------------------------------------- /gallery/public/images/office.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/office.jpg -------------------------------------------------------------------------------- /gallery/public/images/paulus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/paulus.jpg -------------------------------------------------------------------------------- /gallery/public/images/sunflowers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/gallery/public/images/sunflowers.jpg -------------------------------------------------------------------------------- /gallery/script/build_gallery: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run the gallery 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp build-gallery 10 | -------------------------------------------------------------------------------- /gallery/script/develop_gallery: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run the gallery 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp develop-gallery 10 | -------------------------------------------------------------------------------- /gallery/src/data/date-options.ts: -------------------------------------------------------------------------------- 1 | import type { ControlSelectOption } from "../../../src/components/ha-control-select"; 2 | 3 | export const timeOptions: ControlSelectOption[] = [ 4 | { 5 | value: "now", 6 | label: "Now", 7 | }, 8 | { 9 | value: "00:15:30", 10 | label: "12:15:30 AM", 11 | }, 12 | { 13 | value: "06:15:30", 14 | label: "06:15:30 AM", 15 | }, 16 | { 17 | value: "12:15:30", 18 | label: "12:15:30 PM", 19 | }, 20 | { 21 | value: "18:15:30", 22 | label: "06:15:30 PM", 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /gallery/src/data/traces/types.ts: -------------------------------------------------------------------------------- 1 | import type { AutomationTraceExtended } from "../../../../src/data/trace"; 2 | import type { LogbookEntry } from "../../../../src/data/logbook"; 3 | 4 | export interface DemoTrace { 5 | trace: AutomationTraceExtended; 6 | logbookEntries: LogbookEntry[]; 7 | } 8 | -------------------------------------------------------------------------------- /gallery/src/entrypoint.js: -------------------------------------------------------------------------------- 1 | import "./ha-gallery"; 2 | 3 | import("../../src/resources/append-ha-style"); 4 | 5 | document.body.appendChild(document.createElement("ha-gallery")); 6 | -------------------------------------------------------------------------------- /gallery/src/pages/automation/describe-action.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Describe Action 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/automation/describe-condition.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Describe Condition 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/automation/describe-trigger.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Describe Trigger 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/automation/editor-action.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Actions 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/automation/editor-condition.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Conditions 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/automation/editor-trigger.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Triggers 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/automation/trace-timeline.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Trace Timelines 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/automation/trace.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Trace Graphs 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-bar.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bar 3 | subtitle: Can be used to communicate progress of a task. 4 | --- 5 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-chips.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Chip 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-control-button.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Control Button 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-control-circular-slider.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Control Circular Slider 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-control-number-buttons.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Control Number Buttons 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-control-select-menu.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Control Select Menu 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-control-select.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Control Select 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-control-slider.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Control Slider 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-control-switch.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Control Switch 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-expansion-panel.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Expansion Panel 3 | --- 4 | 5 | Expansion panel following all the ARIA guidelines. 6 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-faded.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Faded Content 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-form.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Forms 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-gauge.ts: -------------------------------------------------------------------------------- 1 | import "../../../../src/components/ha-gauge"; 2 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-hs-color-picker.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: HS Color Picker 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-label-badge.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Label Badge 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-select-box.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Select box 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-selector.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Selector 3 | --- 4 | 5 | See the website for [list of available selectors](https://www.home-assistant.io/docs/blueprint/selectors/). 6 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-spinner.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spinner 3 | subtitle: Can be used to indicate an ongoing task. 4 | --- 5 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-switch.ts: -------------------------------------------------------------------------------- 1 | import "../../../../src/components/ha-switch"; 2 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-tip.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tip 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/components/ha-tooltip.ts: -------------------------------------------------------------------------------- 1 | import "../../../../src/components/ha-tooltip"; 2 | import "../../../../src/components/ha-button"; 3 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/date-time-numeric.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Date-Time Format (Numeric) 3 | --- 4 | 5 | This pages lists all supported languages with their available date-time formats. 6 | 7 | Formatting function: `const formatDateTimeNumeric: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/date-time-seconds.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Date-Time Format (Seconds) 3 | --- 4 | 5 | This pages lists all supported languages with their available date-time formats. 6 | 7 | Formatting function: `const formatDateTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/date-time-short-year.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Date-Time Format (Short w/ Year) 3 | --- 4 | 5 | This pages lists all supported languages with their available date-time formats. 6 | 7 | Formatting function: `const formatShortDateTimeWithYear: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/date-time-short.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Date-Time Format (Short) 3 | --- 4 | 5 | This pages lists all supported languages with their available date-time formats. 6 | 7 | Formatting function: `const formatShortDateTime: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/date-time.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Date-Time Format 3 | --- 4 | 5 | This pages lists all supported languages with their available date-time formats. 6 | 7 | Formatting function: `const formatDateTime: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/date.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Date Format (Numeric) 3 | --- 4 | 5 | This pages lists all supported languages with their available (numeric) date formats. 6 | 7 | Formatting function: `const formatDateNumeric: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/time-seconds.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Time Format (Seconds) 3 | --- 4 | 5 | This pages lists all supported languages with their available time formats. 6 | 7 | Formatting function: `const formatTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/time-weekday.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Time Format (Weekday) 3 | --- 4 | 5 | This pages lists all supported languages with their available time formats. 6 | 7 | Formatting function: `const formatTimeWeekday: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/date-time/time.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Time Format 3 | --- 4 | 5 | This pages lists all supported languages with their available time formats. 6 | 7 | Formatting function: `const formatTime: (dateObj: Date, locale: FrontendLocaleData) => string` 8 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/alarm-panel-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Alarm Panel Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/area-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Area Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/conditional-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Conditional Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/entities-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Entities Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/entity-button-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Entity Button Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/entity-filter-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Entity Filter Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/gauge-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Gauge Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/glance-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Glance Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/grid-and-stack-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Grid and Stack Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/iframe-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Website Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/introduction.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | --- 4 | 5 | Dashboards have many different cards. Each card allows the user to tell 6 | a different story about what is going on in their house. These cards 7 | are very customizable, as no household is the same. 8 | 9 | This gallery helps our developers and designers to see all the 10 | different states that each card can be in. 11 | 12 | Check [the Dashboards documentation](https://www.home-assistant.io/dashboards/) for instructions on how to get started with Dashboards. 13 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/light-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Light Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/map-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Map Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/markdown-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/media-control-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Media Control Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/media-player-row.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Media Player Row 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/picture-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Picture Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/picture-elements-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Picture Elements Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/picture-entity-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Picture Entity Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/picture-glance-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Picture Glance Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/plant-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Plant Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/thermostat-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Thermostat Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/tile-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tile Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/lovelace/todo-list-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Todo List Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/misc/entity-state.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Entity State 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/misc/ha-markdown.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/misc/integration-card.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Integration Card 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/misc/util-long-press.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Long Press Utility 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/climate.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Climate 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/cover.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cover 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/humidifier.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Humidifier 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/input-number.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Input Number 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/input-text.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Input Text 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/light.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Light 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/lock.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Lock 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/media-player.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Media Player 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/number.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Number 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/scene.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Scene 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/timer.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Timer 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/update.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Update 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/vacuum.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Vacuum 3 | --- 4 | -------------------------------------------------------------------------------- /gallery/src/pages/more-info/water-heater.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Water Heater 3 | --- 4 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | import { availableParallelism } from "node:os"; 2 | import "./build-scripts/gulp/index.mjs"; 3 | 4 | process.env.UV_THREADPOOL_SIZE = availableParallelism(); 5 | -------------------------------------------------------------------------------- /hassio/config.cjs: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | // Target directory for the build. 5 | buildDir: path.resolve(__dirname, "build"), 6 | nodeDir: path.resolve(__dirname, "../node_modules"), 7 | // Path where the Hass.io frontend will be publicly available. 8 | publicPath: "/api/hassio/app", 9 | }; 10 | -------------------------------------------------------------------------------- /hassio/script/build_hassio: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Builds the Hass.io app for production 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp build-hassio 10 | -------------------------------------------------------------------------------- /hassio/script/develop: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run the Hass.io development server 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp develop-hassio 10 | -------------------------------------------------------------------------------- /hassio/src/components/hassio-filter-addons.ts: -------------------------------------------------------------------------------- 1 | import type { IFuseOptions } from "fuse.js"; 2 | import Fuse from "fuse.js"; 3 | import type { StoreAddon } from "../../../src/data/supervisor/store"; 4 | 5 | export function filterAndSort(addons: StoreAddon[], filter: string) { 6 | const options: IFuseOptions = { 7 | keys: ["name", "description", "slug"], 8 | isCaseSensitive: false, 9 | minMatchCharLength: Math.min(filter.length, 2), 10 | threshold: 0.2, 11 | ignoreDiacritics: true, 12 | }; 13 | const fuse = new Fuse(addons, options); 14 | return fuse.search(filter).map((result) => result.item); 15 | } 16 | -------------------------------------------------------------------------------- /hassio/src/dialogs/datadisk/show-dialog-hassio-datadisk.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../src/common/dom/fire_event"; 2 | import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; 3 | 4 | export interface HassioDatatiskDialogParams { 5 | supervisor: Supervisor; 6 | } 7 | 8 | export const showHassioDatadiskDialog = ( 9 | element: HTMLElement, 10 | dialogParams: HassioDatatiskDialogParams 11 | ): void => { 12 | fireEvent(element, "show-dialog", { 13 | dialogTag: "dialog-hassio-datadisk", 14 | dialogImport: () => import("./dialog-hassio-datadisk"), 15 | dialogParams, 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /hassio/src/dialogs/markdown/show-dialog-hassio-markdown.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../src/common/dom/fire_event"; 2 | 3 | export interface HassioMarkdownDialogParams { 4 | title: string; 5 | content: string; 6 | } 7 | 8 | export const showHassioMarkdownDialog = ( 9 | element: HTMLElement, 10 | dialogParams: HassioMarkdownDialogParams 11 | ): void => { 12 | fireEvent(element, "show-dialog", { 13 | dialogTag: "dialog-hassio-markdown", 14 | dialogImport: () => import("./dialog-hassio-markdown"), 15 | dialogParams, 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /landing-page/eslintrc.config.mjs: -------------------------------------------------------------------------------- 1 | import rootConfig from "../eslint.config.mjs"; 2 | 3 | export default [ 4 | ...rootConfig, 5 | { 6 | rules: {}, 7 | }, 8 | ]; 9 | -------------------------------------------------------------------------------- /landing-page/public/static/icons/favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/landing-page/public/static/icons/favicon-192x192.png -------------------------------------------------------------------------------- /landing-page/public/static/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/landing-page/public/static/icons/favicon.ico -------------------------------------------------------------------------------- /landing-page/public/static/images/logo_discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/landing-page/public/static/images/logo_discord.png -------------------------------------------------------------------------------- /landing-page/public/static/images/logo_x.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /landing-page/script/build_landing_page: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run the landing-page 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp build-landing-page 10 | -------------------------------------------------------------------------------- /landing-page/script/develop: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run the landing-page 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/../.." 8 | 9 | ./node_modules/.bin/gulp develop-landing-page 10 | -------------------------------------------------------------------------------- /landing-page/src/data/observer.ts: -------------------------------------------------------------------------------- 1 | export async function getObserverLogs() { 2 | return fetch("/observer/logs"); 3 | } 4 | 5 | export const downloadUrl = "/observer/logs"; 6 | -------------------------------------------------------------------------------- /landing-page/src/entrypoint.js: -------------------------------------------------------------------------------- 1 | import "./ha-landing-page"; 2 | 3 | import("../../src/resources/append-ha-style"); 4 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build.environment] 2 | YARN_VERSION = "1.22.11" 3 | NODE_OPTIONS = "--max_old_space_size=6144" 4 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | trailingComma: "es5", 3 | }; 4 | -------------------------------------------------------------------------------- /public/__init__.py: -------------------------------------------------------------------------------- 1 | """Frontend for Home Assistant.""" 2 | from pathlib import Path 3 | 4 | 5 | def where() -> Path: 6 | """Return path to the frontend.""" 7 | return Path(__file__).parent 8 | -------------------------------------------------------------------------------- /public/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/py.typed -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / -------------------------------------------------------------------------------- /public/static/icons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #18bcf2 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/static/icons/favicon-1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/favicon-1024x1024.png -------------------------------------------------------------------------------- /public/static/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/favicon-16x16.png -------------------------------------------------------------------------------- /public/static/icons/favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/favicon-192x192.png -------------------------------------------------------------------------------- /public/static/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/favicon-32x32.png -------------------------------------------------------------------------------- /public/static/icons/favicon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/favicon-384x384.png -------------------------------------------------------------------------------- /public/static/icons/favicon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/favicon-512x512.png -------------------------------------------------------------------------------- /public/static/icons/favicon-apple-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/favicon-apple-180x180.png -------------------------------------------------------------------------------- /public/static/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/favicon.ico -------------------------------------------------------------------------------- /public/static/icons/maskable_icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/maskable_icon-128x128.png -------------------------------------------------------------------------------- /public/static/icons/maskable_icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/maskable_icon-192x192.png -------------------------------------------------------------------------------- /public/static/icons/maskable_icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/maskable_icon-384x384.png -------------------------------------------------------------------------------- /public/static/icons/maskable_icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/maskable_icon-48x48.png -------------------------------------------------------------------------------- /public/static/icons/maskable_icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/maskable_icon-512x512.png -------------------------------------------------------------------------------- /public/static/icons/maskable_icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/maskable_icon-72x72.png -------------------------------------------------------------------------------- /public/static/icons/maskable_icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/maskable_icon-96x96.png -------------------------------------------------------------------------------- /public/static/icons/tile-win-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/tile-win-150x150.png -------------------------------------------------------------------------------- /public/static/icons/tile-win-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/tile-win-310x150.png -------------------------------------------------------------------------------- /public/static/icons/tile-win-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/tile-win-310x310.png -------------------------------------------------------------------------------- /public/static/icons/tile-win-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/icons/tile-win-70x70.png -------------------------------------------------------------------------------- /public/static/images/card_media_player_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/card_media_player_bg.png -------------------------------------------------------------------------------- /public/static/images/color_wheel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/color_wheel.png -------------------------------------------------------------------------------- /public/static/images/config_ecobee_thermostat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_ecobee_thermostat.png -------------------------------------------------------------------------------- /public/static/images/config_fitbit_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_fitbit_app.png -------------------------------------------------------------------------------- /public/static/images/config_flows/config_homematicip_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_flows/config_homematicip_cloud.png -------------------------------------------------------------------------------- /public/static/images/config_freebox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_freebox.png -------------------------------------------------------------------------------- /public/static/images/config_icloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_icloud.png -------------------------------------------------------------------------------- /public/static/images/config_insteon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_insteon.png -------------------------------------------------------------------------------- /public/static/images/config_philips_hue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_philips_hue.jpg -------------------------------------------------------------------------------- /public/static/images/config_webos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_webos.png -------------------------------------------------------------------------------- /public/static/images/config_wink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/config_wink.png -------------------------------------------------------------------------------- /public/static/images/darksky/weather-cloudy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/form/tile_features_position_bottom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/static/images/form/tile_features_position_bottom_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/static/images/form/tile_features_position_inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/static/images/form/tile_features_position_inline_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/static/images/image-broken.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/logo_apple_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_apple_home.png -------------------------------------------------------------------------------- /public/static/images/logo_automatic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_automatic.png -------------------------------------------------------------------------------- /public/static/images/logo_axis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_axis.png -------------------------------------------------------------------------------- /public/static/images/logo_deconz.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_deconz.jpeg -------------------------------------------------------------------------------- /public/static/images/logo_discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_discord.png -------------------------------------------------------------------------------- /public/static/images/logo_google_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_google_home.png -------------------------------------------------------------------------------- /public/static/images/logo_nabu_casa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_nabu_casa.png -------------------------------------------------------------------------------- /public/static/images/logo_nabu_casa_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_nabu_casa_dark.png -------------------------------------------------------------------------------- /public/static/images/logo_philips_hue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_philips_hue.png -------------------------------------------------------------------------------- /public/static/images/logo_plex_mediaserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/logo_plex_mediaserver.png -------------------------------------------------------------------------------- /public/static/images/logo_x.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/static/images/notification-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/notification-badge.png -------------------------------------------------------------------------------- /public/static/images/screenshots/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/screenshots/screenshot-1.png -------------------------------------------------------------------------------- /public/static/images/smart-tv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/smart-tv.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/area.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/change-wake-word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/change-wake-word.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/error.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/great-job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/great-job.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/heart.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/hi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/hi.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/ok-nabu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/ok-nabu.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/sleep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/sleep.png -------------------------------------------------------------------------------- /public/static/images/voice-assistant/update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/home-assistant/frontend/02bb7086e7206f053d94953935afde678ba378a0/public/static/images/voice-assistant/update.png -------------------------------------------------------------------------------- /script/build_frontend: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Builds the frontend for production 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/.." 8 | 9 | ./node_modules/.bin/gulp build-app 10 | -------------------------------------------------------------------------------- /script/develop: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run the frontend development server 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/.." 8 | 9 | ./node_modules/.bin/gulp develop-app 10 | -------------------------------------------------------------------------------- /script/release: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Pushes a new version to PyPi. 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/.." 8 | 9 | # Install node modules 10 | yarn install 11 | 12 | script/build_frontend 13 | 14 | rm -rf dist home_assistant_frontend.egg-info 15 | python3 -m build 16 | python3 -m twine upload dist/*.whl --skip-existing 17 | -------------------------------------------------------------------------------- /script/serve-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "cleanUrls": false 3 | } 4 | -------------------------------------------------------------------------------- /script/setup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Resolve all frontend dependencies that the application requires to develop. 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/.." 8 | 9 | script/bootstrap 10 | 11 | -------------------------------------------------------------------------------- /script/setup_translations: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Setup translation fetching during development 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/.." 8 | 9 | ./node_modules/.bin/gulp setup-and-fetch-nightly-translations -------------------------------------------------------------------------------- /script/size_stats: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Analyze stats 3 | 4 | # Stop on errors 5 | set -e 6 | 7 | cd "$(dirname "$0")/.." 8 | 9 | ./node_modules/.bin/gulp analyze-app 10 | -------------------------------------------------------------------------------- /script/translations_download: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Safe bash settings 4 | # -e Exit on command fail 5 | # -u Exit on unset variable 6 | # -o pipefail Exit if piped command has error code 7 | set -eu -o pipefail 8 | 9 | cd "$(dirname "$0")/.." 10 | 11 | ./node_modules/.bin/gulp download-translations -------------------------------------------------------------------------------- /src/cast/const.ts: -------------------------------------------------------------------------------- 1 | import { CAST_DEV_APP_ID } from "./dev_const"; 2 | 3 | // Guard dev mode with `__dev__` so it can only ever be enabled in dev mode. 4 | export const CAST_DEV = __DEV__ && true; 5 | 6 | export const CAST_APP_ID = CAST_DEV ? CAST_DEV_APP_ID : "A078F6B0"; 7 | export const CAST_NS = "urn:x-cast:com.nabucasa.hast"; 8 | -------------------------------------------------------------------------------- /src/cast/dev_const.ts: -------------------------------------------------------------------------------- 1 | // Replace this with your own unpublished cast app that points at your local dev 2 | export const CAST_DEV_APP_ID = "5FE44367"; 3 | 4 | // Chromecast SDK will only load on localhost and HTTPS 5 | // So during local development we have to send our dev IP address, 6 | // but then run the UI on localhost. 7 | export const CAST_DEV_HASS_URL = "http://192.168.1.234:8123"; 8 | -------------------------------------------------------------------------------- /src/cast/types.ts: -------------------------------------------------------------------------------- 1 | export interface BaseCastMessage { 2 | type: string; 3 | senderId?: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/array/combinations.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Get all possible combinations of an array 3 | * @param arr - The array to get combinations of 4 | * @returns A multidimensional array of all possible combinations 5 | */ 6 | export function getAllCombinations(arr: T[]) { 7 | return arr.reduce( 8 | (combinations, element) => 9 | combinations.concat( 10 | combinations.map((combination) => [...combination, element]) 11 | ), 12 | [[]] 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/common/array/literal-includes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Creates a type predicate function for determining if an array literal includes a given value 3 | * @param array - The array to check 4 | * @returns A type predicate function 5 | */ 6 | export const arrayLiteralIncludes = 7 | (array: T) => 8 | (searchElement: unknown, fromIndex?: number): searchElement is T[number] => 9 | array.includes(searchElement as T[number], fromIndex); 10 | -------------------------------------------------------------------------------- /src/common/color/lab.ts: -------------------------------------------------------------------------------- 1 | // From https://github.com/gka/chroma.js 2 | // Copyright (c) 2011-2019, Gregor Aisch 3 | 4 | export type LabColor = [number, number, number]; 5 | 6 | export const labDarken = (lab: LabColor, amount = 1): LabColor => [ 7 | lab[0] - 18 * amount, 8 | lab[1], 9 | lab[2], 10 | ]; 11 | 12 | export const labBrighten = (lab: LabColor, amount = 1): LabColor => 13 | labDarken(lab, -amount); 14 | -------------------------------------------------------------------------------- /src/common/config/components_with_service.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../../types"; 2 | 3 | /** Return an array of domains with the service. */ 4 | export const componentsWithService = ( 5 | hass: HomeAssistant, 6 | service: string 7 | ): string[] => 8 | hass && 9 | Object.keys(hass.services).filter((key) => service in hass.services[key]); 10 | -------------------------------------------------------------------------------- /src/common/config/is_component_loaded.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../../types"; 2 | 3 | /** Return if a component is loaded. */ 4 | export const isComponentLoaded = ( 5 | hass: HomeAssistant, 6 | component: string 7 | ): boolean => hass && hass.config.components.includes(component); 8 | -------------------------------------------------------------------------------- /src/common/config/is_pwa.ts: -------------------------------------------------------------------------------- 1 | /** Return if the displaymode is in standalone mode (PWA). */ 2 | export default function isPwa(): boolean { 3 | return window.matchMedia("(display-mode: standalone)").matches; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/config/is_service_loaded.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../../types"; 2 | 3 | /** Return if a service is loaded. */ 4 | export const isServiceLoaded = ( 5 | hass: HomeAssistant, 6 | domain: string, 7 | service: string 8 | ): boolean => 9 | hass && domain in hass.services && service in hass.services[domain]; 10 | -------------------------------------------------------------------------------- /src/common/config/location_name.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../../types"; 2 | 3 | /** Get the location name from a hass object. */ 4 | export default function computeLocationName(hass: HomeAssistant): string { 5 | return hass && hass.config.location_name; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/datetime/check_valid_date.ts: -------------------------------------------------------------------------------- 1 | export default function checkValidDate(date?: Date): boolean { 2 | if (!date) { 3 | return false; 4 | } 5 | 6 | return date instanceof Date && !isNaN(date.valueOf()); 7 | } 8 | -------------------------------------------------------------------------------- /src/common/datetime/duration_to_seconds.ts: -------------------------------------------------------------------------------- 1 | export default function durationToSeconds(duration: string): number { 2 | const parts = duration.split(":").map(Number); 3 | return parts[0] * 3600 + parts[1] * 60 + parts[2]; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/datetime/resolve-time-zone.ts: -------------------------------------------------------------------------------- 1 | import { TimeZone } from "../../data/translation"; 2 | 3 | const RESOLVED_TIME_ZONE = Intl.DateTimeFormat?.().resolvedOptions?.().timeZone; 4 | 5 | // Browser time zone can be determined from Intl, with fallback to UTC for polyfill or no support. 6 | export const LOCAL_TIME_ZONE = RESOLVED_TIME_ZONE ?? "UTC"; 7 | 8 | // Pick time zone based on user profile option. Core zone is used when local cannot be determined. 9 | export const resolveTimeZone = (option: TimeZone, serverTimeZone: string) => 10 | option === TimeZone.local && RESOLVED_TIME_ZONE 11 | ? LOCAL_TIME_ZONE 12 | : serverTimeZone; 13 | -------------------------------------------------------------------------------- /src/common/datetime/seconds_to_duration.ts: -------------------------------------------------------------------------------- 1 | const leftPad = (num: number) => (num < 10 ? `0${num}` : num); 2 | 3 | export default function secondsToDuration(d: number) { 4 | const h = Math.floor(d / 3600); 5 | const m = Math.floor((d % 3600) / 60); 6 | const s = Math.floor((d % 3600) % 60); 7 | 8 | if (h > 0) { 9 | return `${h}:${leftPad(m)}:${leftPad(s)}`; 10 | } 11 | if (m > 0) { 12 | return `${m}:${leftPad(s)}`; 13 | } 14 | if (s > 0) { 15 | return "" + s; 16 | } 17 | return null; 18 | } 19 | -------------------------------------------------------------------------------- /src/common/dom/deep-active-element.ts: -------------------------------------------------------------------------------- 1 | export const deepActiveElement = ( 2 | root: DocumentOrShadowRoot = document 3 | ): Element | null => { 4 | if (root.activeElement?.shadowRoot?.activeElement) { 5 | return deepActiveElement(root.activeElement.shadowRoot); 6 | } 7 | return root.activeElement; 8 | }; 9 | -------------------------------------------------------------------------------- /src/common/dom/get_main_window.ts: -------------------------------------------------------------------------------- 1 | import { MAIN_WINDOW_NAME } from "../../data/main_window"; 2 | 3 | export const mainWindow = (() => { 4 | try { 5 | return window.name === MAIN_WINDOW_NAME 6 | ? window 7 | : parent.name === MAIN_WINDOW_NAME 8 | ? parent 9 | : top!; 10 | } catch { 11 | return window; 12 | } 13 | })(); 14 | -------------------------------------------------------------------------------- /src/common/dom/prevent_default.ts: -------------------------------------------------------------------------------- 1 | export const preventDefault = (ev) => ev.preventDefault(); 2 | -------------------------------------------------------------------------------- /src/common/dom/stop_propagation.ts: -------------------------------------------------------------------------------- 1 | export const stopPropagation = (ev) => ev.stopPropagation(); 2 | -------------------------------------------------------------------------------- /src/common/dom/toggle_attribute.ts: -------------------------------------------------------------------------------- 1 | // Toggle Attribute Polyfill because it's too new for some browsers 2 | export const toggleAttribute = ( 3 | el: HTMLElement, 4 | name: string, 5 | force?: boolean 6 | ) => { 7 | if (force !== undefined) { 8 | force = !!force; 9 | } 10 | 11 | if (el.hasAttribute(name)) { 12 | if (force) { 13 | return true; 14 | } 15 | 16 | el.removeAttribute(name); 17 | return false; 18 | } 19 | if (force === false) { 20 | return false; 21 | } 22 | 23 | el.setAttribute(name, ""); 24 | return true; 25 | }; 26 | -------------------------------------------------------------------------------- /src/common/empty_image_base64.ts: -------------------------------------------------------------------------------- 1 | /** An empty image which can be set as src of an img element. */ 2 | export const emptyImageBase64 = 3 | "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 4 | -------------------------------------------------------------------------------- /src/common/entity/attribute_class_names.ts: -------------------------------------------------------------------------------- 1 | import type { HassEntity } from "home-assistant-js-websocket"; 2 | 3 | export const attributeClassNames = ( 4 | stateObj: HassEntity, 5 | attributes: string[] 6 | ): string => { 7 | if (!stateObj) { 8 | return ""; 9 | } 10 | return attributes 11 | .map((attribute) => 12 | attribute in stateObj.attributes ? "has-" + attribute : "" 13 | ) 14 | .filter((attr) => attr !== "") 15 | .join(" "); 16 | }; 17 | -------------------------------------------------------------------------------- /src/common/entity/can_toggle_domain.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../../types"; 2 | 3 | export const canToggleDomain = (hass: HomeAssistant, domain: string) => { 4 | const services = hass.services[domain]; 5 | if (!services) { 6 | return false; 7 | } 8 | 9 | if (domain === "lock") { 10 | return "lock" in services; 11 | } 12 | if (domain === "cover") { 13 | return "open_cover" in services; 14 | } 15 | return "turn_on" in services; 16 | }; 17 | -------------------------------------------------------------------------------- /src/common/entity/color/battery_color.ts: -------------------------------------------------------------------------------- 1 | export const batteryStateColorProperty = ( 2 | state: string 3 | ): string | undefined => { 4 | const value = Number(state); 5 | if (isNaN(value)) { 6 | return undefined; 7 | } 8 | if (value >= 70) { 9 | return "--state-sensor-battery-high-color"; 10 | } 11 | if (value >= 30) { 12 | return "--state-sensor-battery-medium-color"; 13 | } 14 | return "--state-sensor-battery-low-color"; 15 | }; 16 | -------------------------------------------------------------------------------- /src/common/entity/compute_area_name.ts: -------------------------------------------------------------------------------- 1 | import type { AreaRegistryEntry } from "../../data/area_registry"; 2 | 3 | export const computeAreaName = (area: AreaRegistryEntry): string | undefined => 4 | area.name?.trim(); 5 | -------------------------------------------------------------------------------- /src/common/entity/compute_domain.ts: -------------------------------------------------------------------------------- 1 | export const computeDomain = (entityId: string): string => 2 | entityId.substring(0, entityId.indexOf(".")); 3 | -------------------------------------------------------------------------------- /src/common/entity/compute_floor_name.ts: -------------------------------------------------------------------------------- 1 | import type { FloorRegistryEntry } from "../../data/floor_registry"; 2 | 3 | export const computeFloorName = (floor: FloorRegistryEntry): string => 4 | floor.name?.trim(); 5 | -------------------------------------------------------------------------------- /src/common/entity/compute_object_id.ts: -------------------------------------------------------------------------------- 1 | /** Compute the object ID of a state. */ 2 | export const computeObjectId = (entityId: string): string => 3 | entityId.substr(entityId.indexOf(".") + 1); 4 | -------------------------------------------------------------------------------- /src/common/entity/compute_state_domain.ts: -------------------------------------------------------------------------------- 1 | import type { HassEntity } from "home-assistant-js-websocket"; 2 | import { computeDomain } from "./compute_domain"; 3 | 4 | export const computeStateDomain = (stateObj: HassEntity) => 5 | computeDomain(stateObj.entity_id); 6 | -------------------------------------------------------------------------------- /src/common/entity/compute_state_name.ts: -------------------------------------------------------------------------------- 1 | import type { HassEntity } from "home-assistant-js-websocket"; 2 | import { computeObjectId } from "./compute_object_id"; 3 | 4 | export const computeStateNameFromEntityAttributes = ( 5 | entityId: string, 6 | attributes: Record 7 | ): string => 8 | attributes.friendly_name === undefined 9 | ? computeObjectId(entityId).replace(/_/g, " ") 10 | : (attributes.friendly_name ?? "").toString(); 11 | 12 | export const computeStateName = (stateObj: HassEntity): string => 13 | computeStateNameFromEntityAttributes(stateObj.entity_id, stateObj.attributes); 14 | -------------------------------------------------------------------------------- /src/common/entity/get_group_entities.ts: -------------------------------------------------------------------------------- 1 | import type { HassEntities } from "home-assistant-js-websocket"; 2 | import type { GroupEntity } from "../../data/group"; 3 | 4 | export const getGroupEntities = ( 5 | entities: HassEntities, 6 | group: GroupEntity 7 | ) => { 8 | const result = {}; 9 | 10 | group.attributes.entity_id.forEach((entityId) => { 11 | const entity = entities[entityId]; 12 | 13 | if (entity) { 14 | result[entity.entity_id] = entity; 15 | } 16 | }); 17 | 18 | return result; 19 | }; 20 | -------------------------------------------------------------------------------- /src/common/entity/has_location.ts: -------------------------------------------------------------------------------- 1 | import type { HassEntity } from "home-assistant-js-websocket"; 2 | 3 | export const hasLocation = (stateObj: HassEntity) => 4 | "latitude" in stateObj.attributes && "longitude" in stateObj.attributes; 5 | -------------------------------------------------------------------------------- /src/common/entity/states_sort_by_name.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Sort function to help sort states by name 3 | * 4 | * Usage: 5 | * const states = [state1, state2] 6 | * states.sort(statessortStatesByName); 7 | */ 8 | import type { HassEntity } from "home-assistant-js-websocket"; 9 | import { computeStateName } from "./compute_state_name"; 10 | 11 | export const sortStatesByName = (entityA: HassEntity, entityB: HassEntity) => { 12 | const nameA = computeStateName(entityA); 13 | const nameB = computeStateName(entityB); 14 | if (nameA < nameB) { 15 | return -1; 16 | } 17 | if (nameA > nameB) { 18 | return 1; 19 | } 20 | return 0; 21 | }; 22 | -------------------------------------------------------------------------------- /src/common/entity/supports-feature.ts: -------------------------------------------------------------------------------- 1 | import type { HassEntity } from "home-assistant-js-websocket"; 2 | 3 | export const supportsFeature = ( 4 | stateObj: HassEntity, 5 | feature: number 6 | ): boolean => supportsFeatureFromAttributes(stateObj.attributes, feature); 7 | 8 | export const supportsFeatureFromAttributes = ( 9 | attributes: Record, 10 | feature: number 11 | ): boolean => 12 | // eslint-disable-next-line no-bitwise 13 | (attributes.supported_features! & feature) !== 0; 14 | -------------------------------------------------------------------------------- /src/common/entity/update_icon.ts: -------------------------------------------------------------------------------- 1 | import type { HassEntity } from "home-assistant-js-websocket"; 2 | import type { UpdateEntity } from "../../data/update"; 3 | import { updateIsInstalling } from "../../data/update"; 4 | 5 | export const updateIcon = (stateObj: HassEntity, state?: string) => { 6 | const compareState = state ?? stateObj.state; 7 | return compareState === "on" 8 | ? updateIsInstalling(stateObj as UpdateEntity) 9 | ? "mdi:package-down" 10 | : "mdi:package-up" 11 | : "mdi:package"; 12 | }; 13 | -------------------------------------------------------------------------------- /src/common/entity/valid_entity_id.ts: -------------------------------------------------------------------------------- 1 | const validEntityId = /^(\w+)\.(\w+)$/; 2 | 3 | export const isValidEntityId = (entityId: string) => 4 | validEntityId.test(entityId); 5 | -------------------------------------------------------------------------------- /src/common/entity/valid_service_id.ts: -------------------------------------------------------------------------------- 1 | const validServiceId = /^(\w+)\.(\w+)$/; 2 | 3 | export const isValidServiceId = (actionId: string) => 4 | validServiceId.test(actionId); 5 | -------------------------------------------------------------------------------- /src/common/feature-detect/support-web-components.ts: -------------------------------------------------------------------------------- 1 | export const webComponentsSupported = "attachShadow" in Element.prototype; 2 | -------------------------------------------------------------------------------- /src/common/language/format_language.ts: -------------------------------------------------------------------------------- 1 | import memoizeOne from "memoize-one"; 2 | import type { FrontendLocaleData } from "../../data/translation"; 3 | 4 | export const formatLanguageCode = ( 5 | languageCode: string, 6 | locale: FrontendLocaleData 7 | ) => { 8 | try { 9 | return formatLanguageCodeMem(locale)?.of(languageCode) ?? languageCode; 10 | } catch { 11 | return languageCode; 12 | } 13 | }; 14 | 15 | const formatLanguageCodeMem = memoizeOne( 16 | (locale: FrontendLocaleData) => 17 | new Intl.DisplayNames(locale.language, { 18 | type: "language", 19 | fallback: "code", 20 | }) 21 | ); 22 | -------------------------------------------------------------------------------- /src/common/location/add_distance_to_coord.ts: -------------------------------------------------------------------------------- 1 | export const addDistanceToCoord = ( 2 | location: [number, number], 3 | dx: number, 4 | dy: number 5 | ): [number, number] => { 6 | const rEarth = 6378000; 7 | const newLatitude = location[0] + (dy / rEarth) * (180 / Math.PI); 8 | const newLongitude = 9 | location[1] + 10 | ((dx / rEarth) * (180 / Math.PI)) / Math.cos((location[0] * Math.PI) / 180); 11 | return [newLatitude, newLongitude]; 12 | }; 13 | -------------------------------------------------------------------------------- /src/common/mwc/handle-request-selected-event.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ListItem, 3 | RequestSelectedDetail, 4 | } from "@material/mwc-list/mwc-list-item"; 5 | 6 | export const shouldHandleRequestSelectedEvent = ( 7 | ev: CustomEvent 8 | ): boolean => { 9 | if (!ev.detail.selected || ev.detail.source !== "property") { 10 | return false; 11 | } 12 | (ev.currentTarget as ListItem).selected = false; 13 | return true; 14 | }; 15 | -------------------------------------------------------------------------------- /src/common/number/clamp.ts: -------------------------------------------------------------------------------- 1 | export const clamp = (value: number, min: number, max: number) => 2 | Math.min(Math.max(value, min), max); 3 | 4 | // Variant that only applies the clamping to a border if the border is defined 5 | export const conditionalClamp = (value: number, min?: number, max?: number) => { 6 | let result: number; 7 | result = min != null ? Math.max(value, min) : value; 8 | result = max != null ? Math.min(result, max) : result; 9 | return result; 10 | }; 11 | -------------------------------------------------------------------------------- /src/common/number/round.ts: -------------------------------------------------------------------------------- 1 | export const round = (value: number, precision = 2): number => 2 | Math.round(value * 10 ** precision) / 10 ** precision; 3 | -------------------------------------------------------------------------------- /src/common/string/capitalize-first-letter.ts: -------------------------------------------------------------------------------- 1 | export const capitalizeFirstLetter = (str: string) => 2 | str.charAt(0).toUpperCase() + str.slice(1); 3 | -------------------------------------------------------------------------------- /src/common/string/escape_regexp.ts: -------------------------------------------------------------------------------- 1 | export const escapeRegExp = (text: string): string => 2 | text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 3 | -------------------------------------------------------------------------------- /src/common/string/get_duplicates.ts: -------------------------------------------------------------------------------- 1 | export function getDuplicates(array: string[]): Set { 2 | const duplicates = new Set(); 3 | const seen = new Set(); 4 | 5 | for (const item of array) { 6 | if (seen.has(item)) { 7 | duplicates.add(item); 8 | } else { 9 | seen.add(item); 10 | } 11 | } 12 | 13 | return duplicates; 14 | } 15 | -------------------------------------------------------------------------------- /src/common/string/has-template.ts: -------------------------------------------------------------------------------- 1 | const isTemplateRegex = /{%|{{/; 2 | 3 | export const isTemplate = (value: string): boolean => 4 | isTemplateRegex.test(value); 5 | 6 | export const hasTemplate = (value: unknown): boolean => { 7 | if (!value) { 8 | return false; 9 | } 10 | if (typeof value === "string") { 11 | return isTemplate(value); 12 | } 13 | if (typeof value === "object") { 14 | const values = Array.isArray(value) ? value : Object.values(value!); 15 | return values.some((val) => val && hasTemplate(val)); 16 | } 17 | return false; 18 | }; 19 | -------------------------------------------------------------------------------- /src/common/string/is_date.ts: -------------------------------------------------------------------------------- 1 | // https://regex101.com/r/kc5C14/2 2 | const regExpString = "^\\d{4}-(0[1-9]|1[0-2])-([12]\\d|0[1-9]|3[01])"; 3 | 4 | const regExp = new RegExp(regExpString + "$"); 5 | // 2nd expression without the "end of string" enforced, so it can be used 6 | // to just verify the start of a string and then based on that result e.g. 7 | // check for a full timestamp string efficiently. 8 | const regExpNoStringEnd = new RegExp(regExpString); 9 | 10 | export const isDate = (input: string, allowCharsAfterDate = false): boolean => 11 | allowCharsAfterDate ? regExpNoStringEnd.test(input) : regExp.test(input); 12 | -------------------------------------------------------------------------------- /src/common/string/is_ip_address.ts: -------------------------------------------------------------------------------- 1 | const regexp = 2 | /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; 3 | 4 | export const isIPAddress = (input: string): boolean => regexp.test(input); 5 | -------------------------------------------------------------------------------- /src/common/string/starts-with.ts: -------------------------------------------------------------------------------- 1 | export const strStartsWith = (value: string, search: string) => 2 | value.substring(0, search.length) === search; 3 | -------------------------------------------------------------------------------- /src/common/string/strip-diacritics.ts: -------------------------------------------------------------------------------- 1 | export const stripDiacritics = (str: string) => 2 | str.normalize("NFD").replace(/[\u0300-\u036F]/g, ""); 3 | -------------------------------------------------------------------------------- /src/common/string/title-case.ts: -------------------------------------------------------------------------------- 1 | export const titleCase = (s) => 2 | s.replace(/^_*(.)|_+(.)/g, (_s, c, d) => 3 | c ? c.toUpperCase() : " " + d.toUpperCase() 4 | ); 5 | -------------------------------------------------------------------------------- /src/common/structs/is-custom-type.ts: -------------------------------------------------------------------------------- 1 | import { refine, string } from "superstruct"; 2 | import { isCustomType } from "../../data/lovelace_custom_cards"; 3 | 4 | export const customType = () => 5 | refine(string(), "custom element type", isCustomType); 6 | -------------------------------------------------------------------------------- /src/common/structs/is-icon.ts: -------------------------------------------------------------------------------- 1 | import { refine, string } from "superstruct"; 2 | 3 | const isIcon = (value: string) => value.includes(":"); 4 | 5 | export const icon = () => refine(string(), "icon (mdi:icon-name)", isIcon); 6 | -------------------------------------------------------------------------------- /src/common/translations/blank_before_percent.ts: -------------------------------------------------------------------------------- 1 | import type { FrontendLocaleData } from "../../data/translation"; 2 | 3 | // Logic based on https://en.wikipedia.org/wiki/Percent_sign#Form_and_spacing 4 | export const blankBeforePercent = ( 5 | localeOptions: FrontendLocaleData 6 | ): string => { 7 | switch (localeOptions.language) { 8 | case "cs": 9 | case "de": 10 | case "fi": 11 | case "fr": 12 | case "sk": 13 | case "sv": 14 | return " "; 15 | default: 16 | return ""; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/common/translations/blank_before_unit.ts: -------------------------------------------------------------------------------- 1 | import type { FrontendLocaleData } from "../../data/translation"; 2 | import { blankBeforePercent } from "./blank_before_percent"; 3 | 4 | export const blankBeforeUnit = ( 5 | unit: string, 6 | localeOptions: FrontendLocaleData | undefined 7 | ): string => { 8 | if (unit === "°") { 9 | return ""; 10 | } 11 | if (localeOptions && unit === "%") { 12 | return blankBeforePercent(localeOptions); 13 | } 14 | return " "; 15 | }; 16 | -------------------------------------------------------------------------------- /src/common/translations/day_names.ts: -------------------------------------------------------------------------------- 1 | import { addDays, startOfWeek } from "date-fns"; 2 | import type { HassConfig } from "home-assistant-js-websocket"; 3 | import memoizeOne from "memoize-one"; 4 | import type { FrontendLocaleData } from "../../data/translation"; 5 | import { formatDateWeekday } from "../datetime/format_date"; 6 | 7 | export const dayNames = memoizeOne( 8 | (locale: FrontendLocaleData, config: HassConfig): string[] => 9 | Array.from({ length: 7 }, (_, d) => 10 | formatDateWeekday(addDays(startOfWeek(new Date()), d), locale, config) 11 | ) 12 | ); 13 | -------------------------------------------------------------------------------- /src/common/translations/markdown_support.ts: -------------------------------------------------------------------------------- 1 | import { html } from "lit"; 2 | import type { LocalizeFunc } from "./localize"; 3 | 4 | const MARKDOWN_SUPPORT_URL = "https://commonmark.org/help/"; 5 | 6 | export const supportsMarkdownHelper = (localize: LocalizeFunc) => 7 | localize("ui.common.supports_markdown", { 8 | markdown_help_link: html`${localize("ui.common.markdown")}`, 14 | }); 15 | -------------------------------------------------------------------------------- /src/common/translations/month_names.ts: -------------------------------------------------------------------------------- 1 | import { addMonths, startOfYear } from "date-fns"; 2 | import type { HassConfig } from "home-assistant-js-websocket"; 3 | import memoizeOne from "memoize-one"; 4 | import type { FrontendLocaleData } from "../../data/translation"; 5 | import { formatDateMonth } from "../datetime/format_date"; 6 | 7 | export const monthNames = memoizeOne( 8 | (locale: FrontendLocaleData, config: HassConfig): string[] => 9 | Array.from({ length: 12 }, (_, m) => 10 | formatDateMonth(addMonths(startOfYear(new Date()), m), locale, config) 11 | ) 12 | ); 13 | -------------------------------------------------------------------------------- /src/common/url/construct-url.ts: -------------------------------------------------------------------------------- 1 | export const constructUrlCurrentPath = (searchParams: string): string => { 2 | const base = window.location.pathname; 3 | // Prevent trailing "?" if no parameters exist 4 | return searchParams ? base + "?" + searchParams : base; 5 | }; 6 | -------------------------------------------------------------------------------- /src/common/util/copy-clipboard.ts: -------------------------------------------------------------------------------- 1 | export const copyToClipboard = async (str, rootEl?: HTMLElement) => { 2 | if (navigator.clipboard) { 3 | try { 4 | await navigator.clipboard.writeText(str); 5 | return; 6 | } catch { 7 | // just continue with the fallback coding below 8 | } 9 | } 10 | 11 | const root = rootEl ?? document.body; 12 | 13 | const el = document.createElement("textarea"); 14 | el.value = str; 15 | root.appendChild(el); 16 | el.select(); 17 | document.execCommand("copy"); 18 | root.removeChild(el); 19 | }; 20 | -------------------------------------------------------------------------------- /src/common/util/group-by.ts: -------------------------------------------------------------------------------- 1 | export const groupBy = ( 2 | list: T[], 3 | keySelector: (item: T) => string 4 | ): Record => { 5 | const result = {}; 6 | for (const item of list) { 7 | const key = keySelector(item); 8 | if (key in result) { 9 | result[key].push(item); 10 | } else { 11 | result[key] = [item]; 12 | } 13 | } 14 | return result; 15 | }; 16 | -------------------------------------------------------------------------------- /src/common/util/patch.ts: -------------------------------------------------------------------------------- 1 | export const applyPatch = (data, path, value): void => { 2 | if (path.length === 1) { 3 | data[path[0]] = value; 4 | return; 5 | } 6 | if (!data[path[0]]) { 7 | data[path[0]] = {}; 8 | } 9 | // eslint-disable-next-line consistent-return 10 | return applyPatch(data[path[0]], path.slice(1), value); 11 | }; 12 | 13 | export const getPath = (data, path): any | undefined => { 14 | if (path.length === 1) { 15 | return data[path[0]]; 16 | } 17 | if (data[path[0]] === undefined) { 18 | return undefined; 19 | } 20 | return getPath(data[path[0]], path.slice(1)); 21 | }; 22 | -------------------------------------------------------------------------------- /src/common/util/promise-all-settled-results.ts: -------------------------------------------------------------------------------- 1 | export const hasRejectedItems = (results: PromiseSettledResult[]) => 2 | results.some((result) => result.status === "rejected"); 3 | 4 | export const rejectedItems = ( 5 | results: PromiseSettledResult[] 6 | ): PromiseRejectedResult[] => 7 | results.filter( 8 | (result) => result.status === "rejected" 9 | ) as PromiseRejectedResult[]; 10 | -------------------------------------------------------------------------------- /src/common/util/render-status.ts: -------------------------------------------------------------------------------- 1 | export const afterNextRender = (cb: (value: unknown) => void): void => { 2 | requestAnimationFrame(() => setTimeout(cb, 0)); 3 | }; 4 | 5 | export const nextRender = () => 6 | new Promise((resolve) => { 7 | afterNextRender(resolve); 8 | }); 9 | -------------------------------------------------------------------------------- /src/common/util/subscribe-one.ts: -------------------------------------------------------------------------------- 1 | import type { Connection, UnsubscribeFunc } from "home-assistant-js-websocket"; 2 | 3 | export const subscribeOne = async ( 4 | conn: Connection, 5 | subscribe: ( 6 | conn2: Connection, 7 | onChange: (items: T) => void 8 | ) => UnsubscribeFunc 9 | ) => 10 | new Promise((resolve) => { 11 | const unsub = subscribe(conn, (items) => { 12 | unsub(); 13 | resolve(items); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/common/util/subscribe-polling.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../../types"; 2 | 3 | export const subscribePollingCollection = ( 4 | hass: HomeAssistant, 5 | updateData: (hass: HomeAssistant) => void, 6 | interval: number 7 | ) => { 8 | let timeout; 9 | const fetchData = async () => { 10 | try { 11 | await updateData(hass); 12 | } finally { 13 | timeout = setTimeout(() => fetchData(), interval); 14 | } 15 | }; 16 | fetchData(); 17 | return () => clearTimeout(timeout); 18 | }; 19 | -------------------------------------------------------------------------------- /src/common/util/uid.ts: -------------------------------------------------------------------------------- 1 | function s4() { 2 | return Math.floor((1 + Math.random()) * 0x10000) 3 | .toString(16) 4 | .substring(1); 5 | } 6 | 7 | export function uid() { 8 | return s4() + s4() + s4() + s4() + s4(); 9 | } 10 | -------------------------------------------------------------------------------- /src/common/util/wait.ts: -------------------------------------------------------------------------------- 1 | export const waitForMs = (ms: number) => 2 | new Promise((resolve) => { 3 | setTimeout(resolve, ms); 4 | }); 5 | 6 | export const waitForSeconds = (seconds: number) => waitForMs(seconds * 1000); 7 | -------------------------------------------------------------------------------- /src/components/chips/ha-chip-set.ts: -------------------------------------------------------------------------------- 1 | import { MdChipSet } from "@material/web/chips/chip-set"; 2 | import { customElement } from "lit/decorators"; 3 | 4 | @customElement("ha-chip-set") 5 | export class HaChipSet extends MdChipSet {} 6 | 7 | declare global { 8 | interface HTMLElementTagNameMap { 9 | "ha-chip-set": HaChipSet; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/components/ha-checkbox.ts: -------------------------------------------------------------------------------- 1 | import { CheckboxBase } from "@material/mwc-checkbox/mwc-checkbox-base"; 2 | import { styles } from "@material/mwc-checkbox/mwc-checkbox.css"; 3 | import { css } from "lit"; 4 | import { customElement } from "lit/decorators"; 5 | 6 | @customElement("ha-checkbox") 7 | export class HaCheckbox extends CheckboxBase { 8 | static override styles = [ 9 | styles, 10 | css` 11 | :host { 12 | --mdc-theme-secondary: var(--primary-color); 13 | } 14 | `, 15 | ]; 16 | } 17 | 18 | declare global { 19 | interface HTMLElementTagNameMap { 20 | "ha-checkbox": HaCheckbox; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/ha-fade-in.ts: -------------------------------------------------------------------------------- 1 | import SlAnimation from "@shoelace-style/shoelace/dist/components/animation/animation.component"; 2 | import { customElement, property } from "lit/decorators"; 3 | 4 | @customElement("ha-fade-in") 5 | export class HaFadeIn extends SlAnimation { 6 | @property() public name = "fadeIn"; 7 | 8 | @property() public fill: FillMode = "both"; 9 | 10 | @property({ type: Boolean }) public play = true; 11 | 12 | @property({ type: Number }) public iterations = 1; 13 | } 14 | 15 | declare global { 16 | interface HTMLElementTagNameMap { 17 | "ha-fade-in": HaFadeIn; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/ha-icon-next.ts: -------------------------------------------------------------------------------- 1 | import { mdiChevronLeft, mdiChevronRight } from "@mdi/js"; 2 | import { customElement, property } from "lit/decorators"; 3 | import { mainWindow } from "../common/dom/get_main_window"; 4 | import { HaSvgIcon } from "./ha-svg-icon"; 5 | 6 | @customElement("ha-icon-next") 7 | export class HaIconNext extends HaSvgIcon { 8 | @property() public override path = 9 | mainWindow.document.dir === "rtl" ? mdiChevronLeft : mdiChevronRight; 10 | } 11 | 12 | declare global { 13 | interface HTMLElementTagNameMap { 14 | "ha-icon-next": HaIconNext; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/ha-icon-prev.ts: -------------------------------------------------------------------------------- 1 | import { mdiChevronLeft, mdiChevronRight } from "@mdi/js"; 2 | import { customElement, property } from "lit/decorators"; 3 | import { mainWindow } from "../common/dom/get_main_window"; 4 | import { HaSvgIcon } from "./ha-svg-icon"; 5 | 6 | @customElement("ha-icon-prev") 7 | export class HaIconPrev extends HaSvgIcon { 8 | @property() public override path = 9 | mainWindow.document.dir === "rtl" ? mdiChevronRight : mdiChevronLeft; 10 | } 11 | 12 | declare global { 13 | interface HTMLElementTagNameMap { 14 | "ha-icon-prev": HaIconPrev; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/ha-list.ts: -------------------------------------------------------------------------------- 1 | import { ListBase } from "@material/mwc-list/mwc-list-base"; 2 | import { styles } from "@material/mwc-list/mwc-list.css"; 3 | import { customElement } from "lit/decorators"; 4 | 5 | @customElement("ha-list") 6 | export class HaList extends ListBase { 7 | static styles = styles; 8 | } 9 | 10 | declare global { 11 | interface HTMLElementTagNameMap { 12 | "ha-list": HaList; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/components/ha-md-divider.ts: -------------------------------------------------------------------------------- 1 | import { Divider } from "@material/web/divider/internal/divider"; 2 | import { styles } from "@material/web/divider/internal/divider-styles"; 3 | import { css } from "lit"; 4 | import { customElement } from "lit/decorators"; 5 | 6 | @customElement("ha-md-divider") 7 | export class HaMdDivider extends Divider { 8 | static override styles = [ 9 | styles, 10 | css` 11 | :host { 12 | --md-divider-color: var(--divider-color); 13 | } 14 | `, 15 | ]; 16 | } 17 | 18 | declare global { 19 | interface HTMLElementTagNameMap { 20 | "ha-md-divider": HaMdDivider; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/ha-md-list.ts: -------------------------------------------------------------------------------- 1 | import { List } from "@material/web/list/internal/list"; 2 | import { styles } from "@material/web/list/internal/list-styles"; 3 | import { css } from "lit"; 4 | import { customElement } from "lit/decorators"; 5 | 6 | @customElement("ha-md-list") 7 | export class HaMdList extends List { 8 | static override styles = [ 9 | styles, 10 | css` 11 | :host { 12 | --md-sys-color-surface: var(--card-background-color); 13 | } 14 | `, 15 | ]; 16 | } 17 | 18 | declare global { 19 | interface HTMLElementTagNameMap { 20 | "ha-md-list": HaMdList; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/ha-radio.ts: -------------------------------------------------------------------------------- 1 | import { RadioBase } from "@material/mwc-radio/mwc-radio-base"; 2 | import { styles } from "@material/mwc-radio/mwc-radio.css"; 3 | import { css } from "lit"; 4 | import { customElement } from "lit/decorators"; 5 | 6 | @customElement("ha-radio") 7 | export class HaRadio extends RadioBase { 8 | static override styles = [ 9 | styles, 10 | css` 11 | :host { 12 | --mdc-theme-secondary: var(--primary-color); 13 | } 14 | `, 15 | ]; 16 | } 17 | 18 | declare global { 19 | interface HTMLElementTagNameMap { 20 | "ha-radio": HaRadio; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/media-player/show-join-media-players-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | 3 | export interface JoinMediaPlayersDialogParams { 4 | entityId: string; 5 | } 6 | 7 | export const showJoinMediaPlayersDialog = ( 8 | element: HTMLElement, 9 | dialogParams: JoinMediaPlayersDialogParams 10 | ): void => { 11 | fireEvent(element, "show-dialog", { 12 | dialogTag: "dialog-join-media-players", 13 | dialogImport: () => import("./dialog-join-media-players"), 14 | dialogParams, 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/media-player/show-media-manage-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | import type { MediaPlayerItem } from "../../data/media-player"; 3 | 4 | export interface MediaManageDialogParams { 5 | currentItem: MediaPlayerItem; 6 | onClose?: () => void; 7 | } 8 | 9 | export const showMediaManageDialog = ( 10 | element: HTMLElement, 11 | dialogParams: MediaManageDialogParams 12 | ): void => { 13 | fireEvent(element, "show-dialog", { 14 | dialogTag: "dialog-media-manage", 15 | dialogImport: () => import("./dialog-media-manage"), 16 | dialogParams, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/timezone-datalist.ts: -------------------------------------------------------------------------------- 1 | import timezones from "google-timezones-json"; 2 | 3 | export const createTimezoneListEl = () => { 4 | const list = document.createElement("datalist"); 5 | list.id = "timezones"; 6 | Object.keys(timezones).forEach((key) => { 7 | const option = document.createElement("option"); 8 | option.value = key; 9 | option.innerText = timezones[key]; 10 | list.appendChild(option); 11 | }); 12 | return list; 13 | }; 14 | -------------------------------------------------------------------------------- /src/components/trace/hat-graph-const.ts: -------------------------------------------------------------------------------- 1 | export const SPACING = 10; 2 | export const NODE_SIZE = 30; 3 | export const BRANCH_HEIGHT = 20; 4 | -------------------------------------------------------------------------------- /src/data/bootstrap_integrations.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export type BootstrapIntegrationsTimings = Record; 4 | 5 | export const subscribeBootstrapIntegrations = ( 6 | hass: HomeAssistant, 7 | callback: (message: BootstrapIntegrationsTimings) => void 8 | ) => { 9 | const unsubProm = 10 | hass.connection.subscribeMessage( 11 | (message) => callback(message), 12 | { 13 | type: "subscribe_bootstrap_integrations", 14 | } 15 | ); 16 | 17 | return unsubProm; 18 | }; 19 | -------------------------------------------------------------------------------- /src/data/config.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | interface ValidConfig { 4 | valid: true; 5 | error: null; 6 | } 7 | 8 | interface InvalidConfig { 9 | valid: false; 10 | error: string; 11 | } 12 | 13 | type ValidKeys = "triggers" | "actions" | "conditions"; 14 | 15 | export const validateConfig = >>( 16 | hass: HomeAssistant, 17 | config: T 18 | ): Promise> => 19 | hass.callWS({ 20 | type: "validate_config", 21 | ...config, 22 | }); 23 | -------------------------------------------------------------------------------- /src/data/custom_iconsets.ts: -------------------------------------------------------------------------------- 1 | import type { CustomIcon } from "./custom_icons"; 2 | 3 | interface CustomIconsetsWindow { 4 | customIconsets?: Record Promise>; 5 | } 6 | 7 | const customIconsetsWindow = window as CustomIconsetsWindow; 8 | 9 | if (!("customIconsets" in customIconsetsWindow)) { 10 | customIconsetsWindow.customIconsets = {}; 11 | } 12 | 13 | export const customIconsets = customIconsetsWindow.customIconsets!; 14 | -------------------------------------------------------------------------------- /src/data/date.ts: -------------------------------------------------------------------------------- 1 | import type { HassEntityBase } from "home-assistant-js-websocket"; 2 | import type { HomeAssistant } from "../types"; 3 | 4 | export const stateToIsoDateString = (entityState: HassEntityBase) => 5 | `${entityState}T00:00:00`; 6 | 7 | export const setDateValue = ( 8 | hass: HomeAssistant, 9 | entityId: string, 10 | date: string | undefined = undefined 11 | ) => { 12 | const param = { entity_id: entityId, date }; 13 | hass.callService("date", "set_value", param); 14 | }; 15 | -------------------------------------------------------------------------------- /src/data/datetime.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export const setDateTimeValue = ( 4 | hass: HomeAssistant, 5 | entityId: string, 6 | datetime: Date 7 | ) => { 8 | hass.callService("datetime", "set_value", { 9 | entity_id: entityId, 10 | datetime: datetime.toISOString(), 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /src/data/entity.ts: -------------------------------------------------------------------------------- 1 | import { arrayLiteralIncludes } from "../common/array/literal-includes"; 2 | 3 | export const UNAVAILABLE = "unavailable"; 4 | export const UNKNOWN = "unknown"; 5 | export const ON = "on"; 6 | export const OFF = "off"; 7 | 8 | export const UNAVAILABLE_STATES = [UNAVAILABLE, UNKNOWN] as const; 9 | export const OFF_STATES = [UNAVAILABLE, UNKNOWN, OFF] as const; 10 | 11 | export const isUnavailableState = arrayLiteralIncludes(UNAVAILABLE_STATES); 12 | export const isOffState = arrayLiteralIncludes(OFF_STATES); 13 | -------------------------------------------------------------------------------- /src/data/error_log.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export interface LogProvider { 4 | key: string; 5 | name: string; 6 | } 7 | 8 | export const fetchErrorLog = (hass: HomeAssistant) => 9 | hass.callApi("GET", "error_log"); 10 | 11 | export const getErrorLogDownloadUrl = "/api/error_log"; 12 | -------------------------------------------------------------------------------- /src/data/external.ts: -------------------------------------------------------------------------------- 1 | export const isExternal = 2 | window.externalApp || 3 | window.webkit?.messageHandlers?.getExternalAuth || 4 | location.search.includes("external_auth=1"); 5 | -------------------------------------------------------------------------------- /src/data/graph.ts: -------------------------------------------------------------------------------- 1 | export const strokeWidth = 5; 2 | -------------------------------------------------------------------------------- /src/data/image.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | HassEntityAttributeBase, 3 | HassEntityBase, 4 | } from "home-assistant-js-websocket"; 5 | 6 | interface ImageEntityAttributes extends HassEntityAttributeBase { 7 | access_token: string; 8 | } 9 | 10 | export interface ImageEntity extends HassEntityBase { 11 | attributes: ImageEntityAttributes; 12 | } 13 | 14 | export const computeImageUrl = (entity: ImageEntity): string => 15 | `/api/image_proxy/${entity.entity_id}?token=${entity.attributes.access_token}&state=${entity.state}`; 16 | -------------------------------------------------------------------------------- /src/data/lovelace/action_handler.ts: -------------------------------------------------------------------------------- 1 | import type { HASSDomEvent } from "../../common/dom/fire_event"; 2 | 3 | export interface ActionHandlerOptions { 4 | hasHold?: boolean; 5 | hasDoubleClick?: boolean; 6 | disabled?: boolean; 7 | } 8 | 9 | export interface ActionHandlerDetail { 10 | action: "hold" | "tap" | "double_tap"; 11 | } 12 | 13 | export type ActionHandlerEvent = HASSDomEvent; 14 | -------------------------------------------------------------------------------- /src/data/lovelace/config/card.ts: -------------------------------------------------------------------------------- 1 | import type { Condition } from "../../../panels/lovelace/common/validate-condition"; 2 | import type { 3 | LovelaceGridOptions, 4 | LovelaceLayoutOptions, 5 | } from "../../../panels/lovelace/types"; 6 | 7 | export interface LovelaceCardConfig { 8 | index?: number; 9 | view_index?: number; 10 | view_layout?: any; 11 | /** @deprecated Use `grid_options` instead */ 12 | layout_options?: LovelaceLayoutOptions; 13 | grid_options?: LovelaceGridOptions; 14 | type: string; 15 | [key: string]: any; 16 | visibility?: Condition[]; 17 | } 18 | -------------------------------------------------------------------------------- /src/data/lovelace/config/strategy.ts: -------------------------------------------------------------------------------- 1 | export interface LovelaceStrategyConfig { 2 | type: string; 3 | [key: string]: any; 4 | } 5 | -------------------------------------------------------------------------------- /src/data/main_window.ts: -------------------------------------------------------------------------------- 1 | export const MAIN_WINDOW_NAME = "ha-main-window"; 2 | -------------------------------------------------------------------------------- /src/data/number.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export interface NumberDeviceClassUnits { 4 | units: string[]; 5 | } 6 | 7 | export const getNumberDeviceClassConvertibleUnits = ( 8 | hass: HomeAssistant, 9 | deviceClass: string 10 | ): Promise => 11 | hass.callWS({ 12 | type: "number/device_class_convertible_units", 13 | device_class: deviceClass, 14 | }); 15 | -------------------------------------------------------------------------------- /src/data/panel_custom.ts: -------------------------------------------------------------------------------- 1 | import type { PanelInfo } from "../types"; 2 | 3 | export interface CustomPanelConfig { 4 | name: string; 5 | embed_iframe: boolean; 6 | trust_external: boolean; 7 | js_url?: string; 8 | module_url?: string; 9 | html_url?: string; 10 | } 11 | 12 | export type CustomPanelInfo> = PanelInfo< 13 | T & { _panel_custom: CustomPanelConfig } 14 | >; 15 | -------------------------------------------------------------------------------- /src/data/preloads.ts: -------------------------------------------------------------------------------- 1 | import type { LovelaceRawConfig } from "./lovelace/config/types"; 2 | import type { LovelaceResource } from "./lovelace/resource"; 3 | import type { RecorderInfo } from "./recorder"; 4 | 5 | export interface WindowWithPreloads extends Window { 6 | llConfProm?: Promise; 7 | llResProm?: Promise; 8 | recorderInfoProm?: Promise; 9 | } 10 | -------------------------------------------------------------------------------- /src/data/refresh_token.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | interface HASSDomEvents { 3 | "hass-refresh-tokens": undefined; 4 | } 5 | } 6 | 7 | export type RefreshTokenType = "normal" | "long_lived_access_token"; 8 | 9 | export interface RefreshToken { 10 | client_icon?: string; 11 | client_id: string; 12 | client_name?: string; 13 | created_at: string; 14 | expire_at?: string; 15 | id: string; 16 | is_current: boolean; 17 | last_used_at?: string; 18 | last_used_ip?: string; 19 | type: RefreshTokenType; 20 | } 21 | -------------------------------------------------------------------------------- /src/data/registry.ts: -------------------------------------------------------------------------------- 1 | export interface RegistryEntry { 2 | created_at: number; 3 | modified_at: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/data/remote.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | HassEntityAttributeBase, 3 | HassEntityBase, 4 | } from "home-assistant-js-websocket"; 5 | 6 | export const REMOTE_SUPPORT_LEARN_COMMAND = 1; 7 | export const REMOTE_SUPPORT_DELETE_COMMAND = 2; 8 | export const REMOTE_SUPPORT_ACTIVITY = 4; 9 | 10 | export type RemoteEntity = HassEntityBase & { 11 | attributes: HassEntityAttributeBase & { 12 | current_activity: string | null; 13 | activity_list: string[] | null; 14 | [key: string]: any; 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /src/data/select.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | HassEntityAttributeBase, 3 | HassEntityBase, 4 | } from "home-assistant-js-websocket"; 5 | import type { HomeAssistant } from "../types"; 6 | 7 | interface SelectEntityAttributes extends HassEntityAttributeBase { 8 | options: string[]; 9 | } 10 | 11 | export interface SelectEntity extends HassEntityBase { 12 | attributes: SelectEntityAttributes; 13 | } 14 | 15 | export const setSelectOption = ( 16 | hass: HomeAssistant, 17 | entity: string, 18 | option: string 19 | ) => 20 | hass.callService( 21 | "select", 22 | "select_option", 23 | { option }, 24 | { entity_id: entity } 25 | ); 26 | -------------------------------------------------------------------------------- /src/data/siren.ts: -------------------------------------------------------------------------------- 1 | export const SirenEntityFeature = { 2 | TURN_ON: 1, 3 | TURN_OFF: 2, 4 | TONES: 4, 5 | VOLUME_SET: 8, 6 | DURATION: 16, 7 | }; 8 | -------------------------------------------------------------------------------- /src/data/text.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | HassEntityAttributeBase, 3 | HassEntityBase, 4 | } from "home-assistant-js-websocket"; 5 | import type { HomeAssistant } from "../types"; 6 | 7 | interface TextEntityAttributes extends HassEntityAttributeBase { 8 | min?: number; 9 | max?: number; 10 | pattern?: string; 11 | mode?: "text" | "password"; 12 | } 13 | 14 | export interface TextEntity extends HassEntityBase { 15 | attributes: TextEntityAttributes; 16 | } 17 | 18 | export const setValue = (hass: HomeAssistant, entity: string, value: string) => 19 | hass.callService("text", "set_value", { value }, { entity_id: entity }); 20 | -------------------------------------------------------------------------------- /src/data/time.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export const setTimeValue = ( 4 | hass: HomeAssistant, 5 | entityId: string, 6 | time: string | undefined = undefined 7 | ) => { 8 | const param = { entity_id: entityId, time: time }; 9 | hass.callService("time", "set_value", param); 10 | }; 11 | -------------------------------------------------------------------------------- /src/data/usb.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export const scanUSBDevices = (hass: HomeAssistant) => 4 | hass.callWS({ type: "usb/scan" }); 5 | -------------------------------------------------------------------------------- /src/data/wake_word.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export interface WakeWord { 4 | id: string; 5 | name: string; 6 | } 7 | 8 | export const fetchWakeWordInfo = (hass: HomeAssistant, entity_id: string) => 9 | hass.callWS<{ wake_words: WakeWord[] }>({ 10 | type: "wake_word/info", 11 | entity_id, 12 | }); 13 | -------------------------------------------------------------------------------- /src/data/webhook.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export interface Webhook { 4 | webhook_id: string; 5 | domain: string; 6 | name: string; 7 | local_only: boolean; 8 | } 9 | export interface WebhookError { 10 | code: number; 11 | message: string; 12 | } 13 | 14 | export const fetchWebhooks = (hass: HomeAssistant): Promise => 15 | hass.callWS({ 16 | type: "webhook/list", 17 | }); 18 | -------------------------------------------------------------------------------- /src/data/websocket_api.ts: -------------------------------------------------------------------------------- 1 | export const ERR_ID_REUSE = "id_reuse"; 2 | export const ERR_INVALID_FORMAT = "invalid_format"; 3 | export const ERR_NOT_FOUND = "not_found"; 4 | export const ERR_UNKNOWN_COMMAND = "unknown_command"; 5 | export const ERR_UNKNOWN_ERROR = "unknown_error"; 6 | export const ERR_UNAUTHORIZED = "unauthorized"; 7 | -------------------------------------------------------------------------------- /src/data/ws-user.ts: -------------------------------------------------------------------------------- 1 | import type { Connection } from "home-assistant-js-websocket"; 2 | import { getCollection, getUser } from "home-assistant-js-websocket"; 3 | import type { CurrentUser } from "../types"; 4 | 5 | export const userCollection = (conn: Connection) => 6 | getCollection( 7 | conn, 8 | "_usr", 9 | () => getUser(conn) as Promise, 10 | undefined 11 | ); 12 | 13 | export const subscribeUser = ( 14 | conn: Connection, 15 | onChange: (user: CurrentUser) => void 16 | ) => userCollection(conn).subscribe(onChange); 17 | -------------------------------------------------------------------------------- /src/data/wyoming.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export interface WyomingInfo { 4 | asr: WyomingAsrInfo[]; 5 | handle: []; 6 | intent: []; 7 | tts: WyomingTtsInfo[]; 8 | wake: []; 9 | } 10 | 11 | interface WyomingBaseInfo { 12 | name: string; 13 | version: string; 14 | attribution: Record; 15 | } 16 | 17 | interface WyomingTtsInfo extends WyomingBaseInfo {} 18 | 19 | interface WyomingAsrInfo extends WyomingBaseInfo {} 20 | 21 | export const fetchWyomingInfo = (hass: HomeAssistant) => 22 | hass.callWS<{ info: Record }>({ type: "wyoming/info" }); 23 | -------------------------------------------------------------------------------- /src/dialogs/more-info/components/voice/show-view-voice-assistants.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../common/dom/fire_event"; 2 | 3 | export const loadVoiceAssistantsView = () => 4 | import("./ha-more-info-view-voice-assistants"); 5 | 6 | export const showVoiceAssistantsView = ( 7 | element: HTMLElement, 8 | title: string 9 | ): void => { 10 | fireEvent(element, "show-child-view", { 11 | viewTag: "ha-more-info-view-voice-assistants", 12 | viewImport: loadVoiceAssistantsView, 13 | viewTitle: title, 14 | viewParams: {}, 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /src/dialogs/more-info/show-ha-more-info-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | import type { MoreInfoDialogParams } from "./ha-more-info-dialog"; 3 | 4 | export const showMoreInfoDialog = ( 5 | element: HTMLElement, 6 | params: MoreInfoDialogParams 7 | ) => fireEvent(element, "hass-more-info", params); 8 | -------------------------------------------------------------------------------- /src/dialogs/notifications/show-notification-drawer.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | 3 | export interface NotificationDrawerParams { 4 | narrow: boolean; 5 | } 6 | 7 | export const showNotificationDrawer = ( 8 | element: HTMLElement, 9 | dialogParams: NotificationDrawerParams 10 | ): void => { 11 | fireEvent(element, "show-dialog", { 12 | dialogTag: "notification-drawer", 13 | dialogImport: () => import("./notification-drawer"), 14 | dialogParams, 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /src/dialogs/shortcuts/show-shortcuts-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | 3 | export const showShortcutsDialog = (element: HTMLElement) => 4 | fireEvent(element, "show-dialog", { 5 | dialogTag: "dialog-shortcuts", 6 | dialogImport: () => import("./dialog-shortcuts"), 7 | dialogParams: {}, 8 | }); 9 | -------------------------------------------------------------------------------- /src/dialogs/sidebar/show-dialog-edit-sidebar.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | 3 | export const loadEditSidebarDialog = () => import("./dialog-edit-sidebar"); 4 | 5 | export const showEditSidebarDialog = (element: HTMLElement): void => { 6 | fireEvent(element, "show-dialog", { 7 | dialogTag: "dialog-edit-sidebar", 8 | dialogImport: loadEditSidebarDialog, 9 | dialogParams: {}, 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/dialogs/tts-try/show-dialog-tts-try.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | 3 | export interface TTSTryDialogParams { 4 | engine: string; 5 | language?: string; 6 | voice?: string; 7 | } 8 | 9 | export const loadTTSTryDialog = () => import("./dialog-tts-try"); 10 | 11 | export const showTTSTryDialog = ( 12 | element: HTMLElement, 13 | dialogParams: TTSTryDialogParams 14 | ): void => { 15 | fireEvent(element, "show-dialog", { 16 | addHistory: false, 17 | dialogTag: "dialog-tts-try", 18 | dialogImport: loadTTSTryDialog, 19 | dialogParams, 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /src/entrypoints/app.ts: -------------------------------------------------------------------------------- 1 | import "@webcomponents/scoped-custom-element-registry/scoped-custom-element-registry.min"; 2 | import "../layouts/home-assistant"; 3 | 4 | import("../resources/append-ha-style"); 5 | -------------------------------------------------------------------------------- /src/entrypoints/authorize.ts: -------------------------------------------------------------------------------- 1 | import "../auth/ha-authorize"; 2 | 3 | import("../resources/append-ha-style"); 4 | -------------------------------------------------------------------------------- /src/entrypoints/onboarding.ts: -------------------------------------------------------------------------------- 1 | import "../onboarding/ha-onboarding"; 2 | 3 | import("../resources/append-ha-style"); 4 | 5 | declare global { 6 | interface Window { 7 | stepsPromise: Promise; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/html/_header.html.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% for (const entry of latestEntryJS) { %> 5 | 6 | <% } %> 7 | -------------------------------------------------------------------------------- /src/html/_preload_roboto.html.template: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/html/_script_loader.html.template: -------------------------------------------------------------------------------- 1 | 9 | 18 | -------------------------------------------------------------------------------- /src/html/_style_base.html.template: -------------------------------------------------------------------------------- 1 | 2 | 13 | -------------------------------------------------------------------------------- /src/onboarding/dialogs/show-app-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | import type { LocalizeFunc } from "../../common/translations/localize"; 3 | 4 | export const loadAppDialog = () => import("./app-dialog"); 5 | 6 | export const showAppDialog = ( 7 | element: HTMLElement, 8 | params: { localize: LocalizeFunc } 9 | ): void => { 10 | fireEvent(element, "show-dialog", { 11 | dialogTag: "app-dialog", 12 | dialogImport: loadAppDialog, 13 | dialogParams: params, 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /src/onboarding/dialogs/show-community-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | import type { LocalizeFunc } from "../../common/translations/localize"; 3 | 4 | export const loadCommunityDialog = () => import("./community-dialog"); 5 | 6 | export const showCommunityDialog = ( 7 | element: HTMLElement, 8 | params: { localize: LocalizeFunc } 9 | ): void => { 10 | fireEvent(element, "show-dialog", { 11 | dialogTag: "community-dialog", 12 | dialogImport: loadCommunityDialog, 13 | dialogParams: params, 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /src/panels/config/automation/structs.ts: -------------------------------------------------------------------------------- 1 | import { object, optional, number, string, boolean } from "superstruct"; 2 | 3 | export const baseTriggerStruct = object({ 4 | trigger: string(), 5 | id: optional(string()), 6 | enabled: optional(boolean()), 7 | }); 8 | 9 | export const forDictStruct = object({ 10 | days: optional(number()), 11 | hours: optional(number()), 12 | minutes: optional(number()), 13 | seconds: optional(number()), 14 | }); 15 | -------------------------------------------------------------------------------- /src/panels/config/backup/dialogs/show-dialog-local-backup-location.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../common/dom/fire_event"; 2 | 3 | export interface LocalBackupLocationDialogParams {} 4 | 5 | export const showLocalBackupLocationDialog = ( 6 | element: HTMLElement, 7 | dialogParams: LocalBackupLocationDialogParams 8 | ): void => { 9 | fireEvent(element, "show-dialog", { 10 | dialogTag: "dialog-local-backup-location", 11 | dialogImport: () => import("./dialog-local-backup-location"), 12 | dialogParams, 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /src/panels/config/backup/dialogs/show-dialog-show-backup-encryption-key.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../common/dom/fire_event"; 2 | 3 | export interface ShowBackupEncryptionKeyDialogParams { 4 | currentKey: string; 5 | } 6 | 7 | const loadDialog = () => import("./dialog-show-backup-encryption-key"); 8 | 9 | export const showShowBackupEncryptionKeyDialog = ( 10 | element: HTMLElement, 11 | params?: ShowBackupEncryptionKeyDialogParams 12 | ) => 13 | fireEvent(element, "show-dialog", { 14 | dialogTag: "ha-dialog-show-backup-encryption-key", 15 | dialogImport: loadDialog, 16 | dialogParams: params, 17 | }); 18 | -------------------------------------------------------------------------------- /src/panels/config/blueprint/show-dialog-import-blueprint.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | 3 | export const loadImportBlueprintDialog = () => 4 | import("./dialog-import-blueprint"); 5 | 6 | export const showAddBlueprintDialog = ( 7 | element: HTMLElement, 8 | dialogParams 9 | ): void => { 10 | fireEvent(element, "show-dialog", { 11 | dialogTag: "ha-dialog-import-blueprint", 12 | dialogImport: loadImportBlueprintDialog, 13 | dialogParams, 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /src/panels/config/cloud/account/show-dialog-cloud-support-package.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../common/dom/fire_event"; 2 | 3 | export const loadSupportPackageDialog = () => 4 | import("./dialog-cloud-support-package"); 5 | 6 | export const showSupportPackageDialog = (element: HTMLElement): void => { 7 | fireEvent(element, "show-dialog", { 8 | dialogTag: "dialog-cloud-support-package", 9 | dialogImport: loadSupportPackageDialog, 10 | dialogParams: {}, 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /src/panels/config/cloud/account/show-dialog-cloud-tts-try.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../common/dom/fire_event"; 2 | 3 | export interface TryTtsDialogParams { 4 | defaultVoice: [string, string]; 5 | } 6 | 7 | export const loadTryTtsDialog = () => import("./dialog-cloud-tts-try"); 8 | 9 | export const showTryTtsDialog = ( 10 | element: HTMLElement, 11 | dialogParams: TryTtsDialogParams 12 | ): void => { 13 | fireEvent(element, "show-dialog", { 14 | dialogTag: "dialog-cloud-try-tts", 15 | dialogImport: loadTryTtsDialog, 16 | dialogParams, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /src/panels/config/core/updates/show-dialog-join-beta.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../common/dom/fire_event"; 2 | import "./dialog-join-beta"; 3 | 4 | export interface JoinBetaDialogParams { 5 | join?: () => any; 6 | cancel?: () => any; 7 | } 8 | 9 | export const showJoinBetaDialog = ( 10 | element: HTMLElement, 11 | dialogParams: JoinBetaDialogParams 12 | ): void => { 13 | fireEvent(element, "show-dialog", { 14 | dialogTag: "dialog-join-beta", 15 | dialogImport: () => import("./dialog-join-beta"), 16 | dialogParams, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /src/panels/config/entities/const.ts: -------------------------------------------------------------------------------- 1 | /** Platforms that have a settings tab. */ 2 | export const PLATFORMS_WITH_SETTINGS_TAB = { 3 | input_number: "entity-settings-helper-tab", 4 | input_select: "entity-settings-helper-tab", 5 | input_text: "entity-settings-helper-tab", 6 | input_boolean: "entity-settings-helper-tab", 7 | input_datetime: "entity-settings-helper-tab", 8 | counter: "entity-settings-helper-tab", 9 | timer: "entity-settings-helper-tab", 10 | input_button: "entity-settings-helper-tab", 11 | schedule: "entity-settings-helper-tab", 12 | }; 13 | -------------------------------------------------------------------------------- /src/panels/config/hardware/show-dialog-hardware-available.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | 3 | export const loadHardwareAvailableDialog = () => 4 | import("./dialog-hardware-available"); 5 | 6 | export const showhardwareAvailableDialog = (element: HTMLElement): void => { 7 | fireEvent(element, "show-dialog", { 8 | dialogTag: "ha-dialog-hardware-available", 9 | dialogImport: loadHardwareAvailableDialog, 10 | dialogParams: {}, 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /src/panels/config/integrations/integration-panels/matter/show-dialog-add-matter-device.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../../../common/dom/fire_event"; 2 | 3 | export const loadAddDeviceDialog = () => import("./dialog-matter-add-device"); 4 | 5 | export const showMatterAddDeviceDialog = (element: HTMLElement): void => { 6 | fireEvent(element, "show-dialog", { 7 | dialogTag: "dialog-matter-add-device", 8 | dialogImport: loadAddDeviceDialog, 9 | dialogParams: {}, 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/panels/config/logs/show-dialog-download-logs.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | 3 | export interface DownloadLogsDialogParams { 4 | header?: string; 5 | provider: string; 6 | defaultLineCount?: number; 7 | boot: number; 8 | } 9 | 10 | export const showDownloadLogsDialog = ( 11 | element: HTMLElement, 12 | dialogParams: DownloadLogsDialogParams 13 | ): void => { 14 | fireEvent(element, "show-dialog", { 15 | dialogTag: "dialog-download-logs", 16 | dialogImport: () => import("./dialog-download-logs"), 17 | dialogParams, 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /src/panels/config/repairs/show-integration-startup-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | 3 | export const loadIntegrationStartupDialog = () => 4 | import("./dialog-integration-startup"); 5 | 6 | export const showIntegrationStartupDialog = (element: HTMLElement): void => { 7 | fireEvent(element, "show-dialog", { 8 | dialogTag: "dialog-integration-startup", 9 | dialogImport: loadIntegrationStartupDialog, 10 | dialogParams: {}, 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /src/panels/config/repairs/show-system-information-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | 3 | export const loadSystemInformationDialog = () => 4 | import("./dialog-system-information"); 5 | 6 | export const showSystemInformationDialog = (element: HTMLElement): void => { 7 | fireEvent(element, "show-dialog", { 8 | dialogTag: "dialog-system-information", 9 | dialogImport: loadSystemInformationDialog, 10 | dialogParams: undefined, 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /src/panels/config/storage/show-dialog-move-datadisk.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | import type { HassioHostInfo } from "../../../data/hassio/host"; 3 | 4 | export interface MoveDatadiskDialogParams { 5 | hostInfo: HassioHostInfo; 6 | } 7 | 8 | export const showMoveDatadiskDialog = ( 9 | element: HTMLElement, 10 | dialogParams: MoveDatadiskDialogParams 11 | ): void => { 12 | fireEvent(element, "show-dialog", { 13 | dialogTag: "dialog-move-datadisk", 14 | dialogImport: () => import("./dialog-move-datadisk"), 15 | dialogParams, 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /src/panels/config/storage/show-dialog-view-mount.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | import type { SupervisorMount } from "../../../data/supervisor/mounts"; 3 | 4 | export interface MountViewDialogParams { 5 | mount?: SupervisorMount; 6 | reloadMounts: () => void; 7 | } 8 | 9 | export const showMountViewDialog = ( 10 | element: HTMLElement, 11 | dialogParams: MountViewDialogParams 12 | ): void => { 13 | fireEvent(element, "show-dialog", { 14 | dialogTag: "dialog-mount-view", 15 | dialogImport: () => import("./dialog-mount-view"), 16 | dialogParams, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /src/panels/config/users/show-dialog-add-user.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | import type { User } from "../../../data/user"; 3 | 4 | export interface AddUserDialogParams { 5 | userAddedCallback: (user: User) => void; 6 | name?: string; 7 | } 8 | 9 | export const loadAddUserDialog = () => import("./dialog-add-user"); 10 | 11 | export const showAddUserDialog = ( 12 | element: HTMLElement, 13 | dialogParams: AddUserDialogParams 14 | ): void => { 15 | fireEvent(element, "show-dialog", { 16 | dialogTag: "dialog-add-user", 17 | dialogImport: loadAddUserDialog, 18 | dialogParams, 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /src/panels/config/users/show-dialog-admin-change-password.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../../common/dom/fire_event"; 2 | 3 | export interface AdminChangePasswordDialogParams { 4 | userId: string; 5 | } 6 | 7 | export const loadAdminChangePasswordDialog = () => 8 | import("./dialog-admin-change-password"); 9 | 10 | export const showAdminChangePasswordDialog = ( 11 | element: HTMLElement, 12 | dialogParams: AdminChangePasswordDialogParams 13 | ): void => { 14 | fireEvent(element, "show-dialog", { 15 | dialogTag: "dialog-admin-change-password", 16 | dialogImport: loadAdminChangePasswordDialog, 17 | dialogParams, 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /src/panels/lovelace/card-features/common/filter-modes.ts: -------------------------------------------------------------------------------- 1 | export const filterModes = ( 2 | supportedModes: T[] | undefined, 3 | selectedModes: T[] | undefined 4 | ): T[] => 5 | selectedModes 6 | ? selectedModes.filter((mode) => (supportedModes || []).includes(mode)) 7 | : supportedModes || []; 8 | -------------------------------------------------------------------------------- /src/panels/lovelace/cards/hui-entity-button-card.ts: -------------------------------------------------------------------------------- 1 | import { customElement } from "lit/decorators"; 2 | import { HuiButtonCard } from "./hui-button-card"; 3 | 4 | @customElement("hui-entity-button-card") 5 | class HuiEntityButtonCard extends HuiButtonCard { 6 | public setConfig(config): void { 7 | if (!config.entity) { 8 | throw new Error("Entity must be specified"); 9 | } 10 | super.setConfig(config); 11 | } 12 | } 13 | 14 | declare global { 15 | interface HTMLElementTagNameMap { 16 | "hui-entity-button-card": HuiEntityButtonCard; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/panels/lovelace/common/entity/toggle-entity.ts: -------------------------------------------------------------------------------- 1 | import { STATES_OFF } from "../../../../common/const"; 2 | import type { HomeAssistant, ServiceCallResponse } from "../../../../types"; 3 | import { turnOnOffEntity } from "./turn-on-off-entity"; 4 | 5 | export const toggleEntity = ( 6 | hass: HomeAssistant, 7 | entityId: string 8 | ): Promise => { 9 | const turnOn = STATES_OFF.includes(hass.states[entityId].state); 10 | return turnOnOffEntity(hass, entityId, turnOn); 11 | }; 12 | -------------------------------------------------------------------------------- /src/panels/lovelace/common/has-action.ts: -------------------------------------------------------------------------------- 1 | import type { ActionConfig } from "../../../data/lovelace/config/action"; 2 | import type { ConfigEntity } from "../cards/types"; 3 | 4 | export function hasAction(config?: ActionConfig): boolean { 5 | return config !== undefined && config.action !== "none"; 6 | } 7 | 8 | export function hasAnyAction(config: ConfigEntity): boolean { 9 | return ( 10 | !config.tap_action || 11 | hasAction(config.tap_action) || 12 | hasAction(config.hold_action) || 13 | hasAction(config.double_tap_action) 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /src/panels/lovelace/common/icon-condition.ts: -------------------------------------------------------------------------------- 1 | import { 2 | mdiAccount, 3 | mdiAmpersand, 4 | mdiGateOr, 5 | mdiNumeric, 6 | mdiResponsive, 7 | mdiStateMachine, 8 | } from "@mdi/js"; 9 | import type { Condition } from "./validate-condition"; 10 | 11 | export const ICON_CONDITION: Record = { 12 | numeric_state: mdiNumeric, 13 | state: mdiStateMachine, 14 | screen: mdiResponsive, 15 | user: mdiAccount, 16 | and: mdiAmpersand, 17 | or: mdiGateOr, 18 | }; 19 | -------------------------------------------------------------------------------- /src/panels/lovelace/common/is-valid-object.ts: -------------------------------------------------------------------------------- 1 | // Check if given obj is a JS object and optionally contains all required keys 2 | export default function isValidObject(obj, requiredKeys = []) { 3 | return ( 4 | obj && 5 | typeof obj === "object" && 6 | !Array.isArray(obj) && 7 | requiredKeys.every((k) => k in obj) 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/panels/lovelace/editor/conditions/types.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../../../../types"; 2 | import type { Condition } from "../../common/validate-condition"; 3 | 4 | export interface LovelaceConditionEditorConstructor { 5 | defaultConfig?: Condition; 6 | validateUIConfig?: (condition: Condition, hass: HomeAssistant) => void; 7 | } 8 | -------------------------------------------------------------------------------- /src/panels/lovelace/editor/gui-support-error.ts: -------------------------------------------------------------------------------- 1 | export class GUISupportError extends Error { 2 | public warnings?: string[]; 3 | 4 | public errors?: string[]; 5 | 6 | constructor(message: string, warnings?: string[], errors?: string[]) { 7 | super(message); 8 | this.name = "GUISupportError"; 9 | this.warnings = warnings; 10 | this.errors = errors; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/panels/lovelace/editor/lovelace-badges.ts: -------------------------------------------------------------------------------- 1 | import type { Badge } from "./types"; 2 | 3 | export const coreBadges: Badge[] = [ 4 | { 5 | type: "entity", 6 | showElement: true, 7 | }, 8 | ]; 9 | -------------------------------------------------------------------------------- /src/panels/lovelace/editor/lovelace-headerfooters.ts: -------------------------------------------------------------------------------- 1 | import { 2 | mdiChartBellCurveCumulative, 3 | mdiGestureTapButton, 4 | mdiImageArea, 5 | } from "@mdi/js"; 6 | import type { HeaderFooter } from "./types"; 7 | 8 | export const headerFooterElements: HeaderFooter[] = [ 9 | { type: "graph", icon: mdiChartBellCurveCumulative }, 10 | { type: "buttons", icon: mdiGestureTapButton }, 11 | { type: "picture", icon: mdiImageArea }, 12 | ]; 13 | -------------------------------------------------------------------------------- /src/panels/lovelace/editor/process-editor-entities.ts: -------------------------------------------------------------------------------- 1 | import type { EntityConfig } from "../entity-rows/types"; 2 | 3 | export function processEditorEntities( 4 | entities: (any | string)[] 5 | ): EntityConfig[] { 6 | return entities.map((entityConf) => { 7 | if (typeof entityConf === "string") { 8 | return { entity: entityConf }; 9 | } 10 | return entityConf; 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /src/panels/lovelace/editor/structs/base-badge-struct.ts: -------------------------------------------------------------------------------- 1 | import { object, string, any } from "superstruct"; 2 | 3 | export const baseLovelaceBadgeConfig = object({ 4 | type: string(), 5 | visibility: any(), 6 | }); 7 | -------------------------------------------------------------------------------- /src/panels/lovelace/editor/structs/base-card-struct.ts: -------------------------------------------------------------------------------- 1 | import { object, string, any } from "superstruct"; 2 | 3 | export const baseLovelaceCardConfig = object({ 4 | type: string(), 5 | view_layout: any(), 6 | layout_options: any(), 7 | grid_options: any(), 8 | visibility: any(), 9 | }); 10 | -------------------------------------------------------------------------------- /src/panels/lovelace/editor/structs/button-entity-struct.ts: -------------------------------------------------------------------------------- 1 | import { boolean, object, optional, string } from "superstruct"; 2 | import { actionConfigStruct } from "./action-struct"; 3 | 4 | export const buttonEntityConfigStruct = object({ 5 | entity: string(), 6 | name: optional(string()), 7 | icon: optional(string()), 8 | image: optional(string()), 9 | show_name: optional(boolean()), 10 | show_icon: optional(boolean()), 11 | tap_action: optional(actionConfigStruct), 12 | hold_action: optional(actionConfigStruct), 13 | double_tap_action: optional(actionConfigStruct), 14 | }); 15 | -------------------------------------------------------------------------------- /src/panels/lovelace/sections/const.ts: -------------------------------------------------------------------------------- 1 | export const GRID_SECTION_LAYOUT = "grid"; 2 | export const DEFAULT_SECTION_LAYOUT = GRID_SECTION_LAYOUT; 3 | -------------------------------------------------------------------------------- /src/panels/lovelace/views/const.ts: -------------------------------------------------------------------------------- 1 | export const MASONRY_VIEW_LAYOUT = "masonry"; 2 | export const PANEL_VIEW_LAYOUT = "panel"; 3 | export const SIDEBAR_VIEW_LAYOUT = "sidebar"; 4 | export const SECTIONS_VIEW_LAYOUT = "sections"; 5 | 6 | export const CARD_LAYOUTS = [ 7 | MASONRY_VIEW_LAYOUT, 8 | PANEL_VIEW_LAYOUT, 9 | SIDEBAR_VIEW_LAYOUT, 10 | ]; 11 | export const SECTION_VIEW_LAYOUTS = [SECTIONS_VIEW_LAYOUT]; 12 | -------------------------------------------------------------------------------- /src/panels/lovelace/views/default-section.ts: -------------------------------------------------------------------------------- 1 | import type { LocalizeFunc } from "../../../common/translations/localize"; 2 | 3 | export const generateDefaultSection = (localize: LocalizeFunc) => ({ 4 | type: "grid", 5 | cards: [ 6 | { 7 | type: "heading", 8 | heading: localize( 9 | "ui.panel.lovelace.editor.section.default_section_title" 10 | ), 11 | }, 12 | ], 13 | }); 14 | -------------------------------------------------------------------------------- /src/panels/lovelace/views/default-view-editable.ts: -------------------------------------------------------------------------------- 1 | // hui-view dependencies for when in edit mode. 2 | import "../../../components/ha-fab"; 3 | import "../components/hui-card-options"; 4 | import { importCreateCardDialog } from "../editor/card-editor/show-create-card-dialog"; 5 | import { importDeleteCardDialog } from "../editor/card-editor/show-delete-card-dialog"; 6 | import { importEditCardDialog } from "../editor/card-editor/show-edit-card-dialog"; 7 | 8 | importCreateCardDialog(); 9 | importDeleteCardDialog(); 10 | importEditCardDialog(); 11 | -------------------------------------------------------------------------------- /src/panels/lovelace/views/get-view-type.ts: -------------------------------------------------------------------------------- 1 | import type { LovelaceViewConfig } from "../../../data/lovelace/config/view"; 2 | import { 3 | MASONRY_VIEW_LAYOUT, 4 | PANEL_VIEW_LAYOUT, 5 | SECTIONS_VIEW_LAYOUT, 6 | } from "./const"; 7 | 8 | export const getViewType = (config?: LovelaceViewConfig): string => { 9 | if (config?.type) { 10 | return config.type; 11 | } 12 | if (config?.panel) { 13 | return PANEL_VIEW_LAYOUT; 14 | } 15 | if (config?.sections) { 16 | return SECTIONS_VIEW_LAYOUT; 17 | } 18 | if (config?.cards) { 19 | return MASONRY_VIEW_LAYOUT; 20 | } 21 | return SECTIONS_VIEW_LAYOUT; 22 | }; 23 | -------------------------------------------------------------------------------- /src/panels/profile/show-long-lived-access-token-dialog.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../../common/dom/fire_event"; 2 | 3 | export interface LongLivedAccessTokenDialogParams { 4 | token: string; 5 | name: string; 6 | } 7 | 8 | export const showLongLivedAccessTokenDialog = ( 9 | element: HTMLElement, 10 | longLivedAccessTokenDialogParams: LongLivedAccessTokenDialogParams 11 | ): void => { 12 | fireEvent(element, "show-dialog", { 13 | dialogTag: "ha-long-lived-access-token-dialog", 14 | dialogImport: () => import("./ha-long-lived-access-token-dialog"), 15 | dialogParams: longLivedAccessTokenDialogParams, 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /src/resources/append-ha-style.ts: -------------------------------------------------------------------------------- 1 | import { themeStyles } from "./theme/theme"; 2 | 3 | const styleElement = document.createElement("style"); 4 | styleElement.textContent = themeStyles; 5 | document.head.append(styleElement); 6 | -------------------------------------------------------------------------------- /src/resources/custom-card-support.ts: -------------------------------------------------------------------------------- 1 | import { css, html, LitElement } from "lit"; 2 | 3 | (LitElement.prototype as any).html = html; 4 | (LitElement.prototype as any).css = css; 5 | -------------------------------------------------------------------------------- /src/resources/hammer.ts: -------------------------------------------------------------------------------- 1 | export { 2 | DIRECTION_LEFT, 3 | DIRECTION_RIGHT, 4 | Manager, 5 | Swipe, 6 | } from "@egjs/hammerjs"; 7 | -------------------------------------------------------------------------------- /src/resources/icon-metadata.ts: -------------------------------------------------------------------------------- 1 | import * as iconMetadata_ from "../../build/mdi/iconMetadata.json"; 2 | import type { IconMetaFile } from "../types.js"; 3 | 4 | export const iconMetadata = (iconMetadata_ as any).default as IconMetaFile; 5 | -------------------------------------------------------------------------------- /src/resources/polyfills/element-getattributenames.ts: -------------------------------------------------------------------------------- 1 | // Source: https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttributeNames 2 | if (Element.prototype.getAttributeNames === undefined) { 3 | Element.prototype.getAttributeNames = function () { 4 | const attributes = this.attributes; 5 | const length = attributes.length; 6 | const result = new Array(length); 7 | for (let i = 0; i < length; i++) { 8 | result[i] = attributes[i].name; 9 | } 10 | return result; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/resources/polyfills/element-toggleattribute.ts: -------------------------------------------------------------------------------- 1 | // Source: https://gist.github.com/rebelchris/365f26f95d7e9f432f64f21886d9b9ef 2 | if (!Element.prototype.toggleAttribute) { 3 | Element.prototype.toggleAttribute = function (name, force) { 4 | if (force !== undefined) { 5 | force = !!force; 6 | } 7 | 8 | if (this.hasAttribute(name)) { 9 | if (force) { 10 | return true; 11 | } 12 | 13 | this.removeAttribute(name); 14 | return false; 15 | } 16 | if (force === false) { 17 | return false; 18 | } 19 | 20 | this.setAttribute(name, ""); 21 | return true; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/polyfills/resize-observer.ts: -------------------------------------------------------------------------------- 1 | if (typeof window.ResizeObserver !== "function") { 2 | window.ResizeObserver = ( 3 | await import( 4 | "@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver" 5 | ) 6 | ).default; 7 | } 8 | 9 | export {}; 10 | -------------------------------------------------------------------------------- /src/resources/sortable.ts: -------------------------------------------------------------------------------- 1 | import type Sortable from "sortablejs"; 2 | import SortableCore, { 3 | AutoScroll, 4 | OnSpill, 5 | } from "sortablejs/modular/sortable.core.esm"; 6 | 7 | SortableCore.mount(OnSpill); 8 | SortableCore.mount(new AutoScroll()); 9 | 10 | export default SortableCore as typeof Sortable; 11 | 12 | export type { Sortable as SortableInstance }; 13 | -------------------------------------------------------------------------------- /src/resources/theme/theme.ts: -------------------------------------------------------------------------------- 1 | import { fontStyles } from "../roboto"; 2 | import { colorDerivedVariables, colorStyles } from "./color.globals"; 3 | import { mainDerivedVariables, mainStyles } from "./main.globals"; 4 | import { 5 | typographyDerivedVariables, 6 | typographyStyles, 7 | } from "./typography.globals"; 8 | 9 | export const themeStyles = [ 10 | mainStyles.toString(), 11 | typographyStyles.toString(), 12 | colorStyles.toString(), 13 | fontStyles.toString(), 14 | ].join(""); 15 | 16 | export const derivedStyles = { 17 | ...mainDerivedVariables, 18 | ...typographyDerivedVariables, 19 | ...colorDerivedVariables, 20 | }; 21 | -------------------------------------------------------------------------------- /src/resources/translations-metadata.ts: -------------------------------------------------------------------------------- 1 | import * as translationMetadata_ from "../../build/translations/translationMetadata.json"; 2 | import type { TranslationMetadata } from "../types.js"; 3 | 4 | export const translationMetadata = (translationMetadata_ as any) 5 | .default as TranslationMetadata; 6 | -------------------------------------------------------------------------------- /src/resources/virtualizer.ts: -------------------------------------------------------------------------------- 1 | export const loadVirtualizer = async () => { 2 | await import("@lit-labs/virtualizer"); 3 | }; 4 | -------------------------------------------------------------------------------- /src/state/notification-mixin.ts: -------------------------------------------------------------------------------- 1 | import type { Constructor } from "../types"; 2 | import type { HassBaseEl } from "./hass-base-mixin"; 3 | 4 | export default >(superClass: T) => 5 | class extends superClass { 6 | protected firstUpdated(changedProps) { 7 | super.firstUpdated(changedProps); 8 | // @ts-ignore 9 | this.registerDialog({ 10 | dialogShowEvent: "hass-notification", 11 | dialogTag: "notification-manager", 12 | dialogImport: () => import("../managers/notification-manager"), 13 | addHistory: false, 14 | }); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /src/types/echarts.d.ts: -------------------------------------------------------------------------------- 1 | declare module "echarts/lib/chart/graph/install" { 2 | export const install: EChartsExtensionInstaller; 3 | } 4 | -------------------------------------------------------------------------------- /src/types/node-vibrant.d.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-var 2 | declare var Vibrant: Any; 3 | declare module "node-vibrant" { 4 | export default Vibrant; 5 | } 6 | -------------------------------------------------------------------------------- /src/util/bytes-to-string.ts: -------------------------------------------------------------------------------- 1 | export const bytesToString = (value = 0, decimals = 2): string => { 2 | if (value === 0) { 3 | return "0 Bytes"; 4 | } 5 | const k = 1024; 6 | decimals = decimals < 0 ? 0 : decimals; 7 | const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; 8 | const i = Math.floor(Math.log(value) / Math.log(k)); 9 | return `${parseFloat((value / k ** i).toFixed(decimals))} ${sizes[i]}`; 10 | }; 11 | -------------------------------------------------------------------------------- /src/util/custom-panel/create-custom-panel-element.ts: -------------------------------------------------------------------------------- 1 | export const createCustomPanelElement = (panelConfig) => { 2 | // Legacy support. Custom panels used to have to define element ha-panel-{name} 3 | const tagName = 4 | "html_url" in panelConfig 5 | ? `ha-panel-${panelConfig.name}` 6 | : panelConfig.name; 7 | return document.createElement(tagName); 8 | }; 9 | -------------------------------------------------------------------------------- /src/util/custom-panel/set-custom-panel-properties.ts: -------------------------------------------------------------------------------- 1 | export const setCustomPanelProperties = (root, properties) => { 2 | if ("setProperties" in root) { 3 | root.setProperties(properties); 4 | } else { 5 | Object.keys(properties).forEach((key) => { 6 | root[key] = properties[key]; 7 | }); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /src/util/documentation-url.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | 3 | export const documentationUrl = (hass: HomeAssistant, path: string) => 4 | `https://${ 5 | hass.config.version.includes("b") 6 | ? "rc" 7 | : hass.config.version.includes("dev") 8 | ? "next" 9 | : "www" 10 | }.home-assistant.io${path}`; 11 | -------------------------------------------------------------------------------- /src/util/empty.js: -------------------------------------------------------------------------------- 1 | /* empty file that we alias some files to that we don't want to include */ 2 | 3 | export {}; // for Babel to treat as a module 4 | -------------------------------------------------------------------------------- /src/util/fetch-with-auth.ts: -------------------------------------------------------------------------------- 1 | import type { Auth } from "home-assistant-js-websocket"; 2 | 3 | export const fetchWithAuth = async ( 4 | auth: Auth, 5 | input: RequestInfo, 6 | init: RequestInit = {} 7 | ) => { 8 | if (auth.expired) { 9 | await auth.refreshAccessToken(); 10 | } 11 | init.credentials = "same-origin"; 12 | if (!init.headers) { 13 | init.headers = {}; 14 | } 15 | if (!init.headers) { 16 | init.headers = {}; 17 | } 18 | // @ts-ignore 19 | init.headers.authorization = `Bearer ${auth.accessToken}`; 20 | return fetch(input, init); 21 | }; 22 | -------------------------------------------------------------------------------- /src/util/iframe.ts: -------------------------------------------------------------------------------- 1 | export const IFRAME_SANDBOX = 2 | "allow-forms allow-popups allow-pointer-lock allow-same-origin allow-scripts allow-modals allow-downloads"; 3 | -------------------------------------------------------------------------------- /src/util/is_ios.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | import { isSafari } from "./is_safari"; 3 | 4 | export const isIosApp = (hass: HomeAssistant): boolean => 5 | !!hass.auth.external && isSafari; 6 | -------------------------------------------------------------------------------- /src/util/is_mac.ts: -------------------------------------------------------------------------------- 1 | export const isMac = /Mac/i.test(navigator.userAgent); 2 | -------------------------------------------------------------------------------- /src/util/is_mobile.ts: -------------------------------------------------------------------------------- 1 | export const isMobileClient = /(?:iphone|android|ipad)/i.test( 2 | navigator.userAgent 3 | ); 4 | -------------------------------------------------------------------------------- /src/util/is_safari.ts: -------------------------------------------------------------------------------- 1 | export const isSafari = /^((?!chrome|android).)*safari/i.test( 2 | navigator.userAgent 3 | ); 4 | -------------------------------------------------------------------------------- /src/util/is_touch.ts: -------------------------------------------------------------------------------- 1 | export const isTouch = 2 | "ontouchstart" in window || 3 | navigator.maxTouchPoints > 0 || 4 | // @ts-ignore 5 | navigator.msMaxTouchPoints > 0; 6 | -------------------------------------------------------------------------------- /src/util/launch-screen.ts: -------------------------------------------------------------------------------- 1 | import type { TemplateResult } from "lit"; 2 | import { render } from "lit"; 3 | 4 | export const removeLaunchScreen = () => { 5 | const launchScreenElement = document.getElementById("ha-launch-screen"); 6 | if (launchScreenElement) { 7 | launchScreenElement.parentElement!.removeChild(launchScreenElement); 8 | } 9 | }; 10 | 11 | export const renderLaunchScreenInfoBox = (content: TemplateResult) => { 12 | const infoBoxElement = document.getElementById("ha-launch-screen-info-box"); 13 | if (infoBoxElement) { 14 | render(content, infoBoxElement); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /src/util/toast-saved-success.ts: -------------------------------------------------------------------------------- 1 | import type { HomeAssistant } from "../types"; 2 | import { showToast } from "./toast"; 3 | 4 | export const showSaveSuccessToast = (el: HTMLElement, hass: HomeAssistant) => 5 | showToast(el, { 6 | message: hass!.localize("ui.common.successfully_saved"), 7 | }); 8 | -------------------------------------------------------------------------------- /src/util/toast.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from "../common/dom/fire_event"; 2 | import type { ShowToastParams } from "../managers/notification-manager"; 3 | 4 | export const showToast = (el: HTMLElement, params: ShowToastParams) => 5 | fireEvent(el, "hass-notification", params); 6 | -------------------------------------------------------------------------------- /src/util/url.ts: -------------------------------------------------------------------------------- 1 | export function obfuscateUrl(url: string) { 2 | if (url.endsWith(".ui.nabu.casa")) { 3 | return "https://•••••••••••••••••.ui.nabu.casa"; 4 | } 5 | // hide any words that look like they might be a hostname or IP address 6 | return url.replace(/(?<=:\/\/)[\w-]+|(?<=\.)[\w-]+/g, (match) => 7 | "•".repeat(match.length) 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /test/common/config/is_component_loaded.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | import { isComponentLoaded } from "../../../src/common/config/is_component_loaded"; 3 | import type { HomeAssistant } from "../../../src/types"; 4 | 5 | describe("isComponentLoaded", () => { 6 | it("should return if the component is loaded", () => { 7 | const hass = { 8 | config: { components: ["test_component"] }, 9 | } as unknown as HomeAssistant; 10 | expect(isComponentLoaded(hass, "test_component")).toBe(true); 11 | expect(isComponentLoaded(hass, "other_component")).toBe(false); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/common/datetime/duration_to_seconds.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, describe, it } from "vitest"; 2 | 3 | import durationToSeconds from "../../../src/common/datetime/duration_to_seconds"; 4 | 5 | describe("durationToSeconds", () => { 6 | it("works", () => { 7 | assert.strictEqual(durationToSeconds("0:01:05"), 65); 8 | assert.strictEqual(durationToSeconds("11:01:05"), 39665); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /test/common/datetime/resolve-time-zone.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { 3 | LOCAL_TIME_ZONE, 4 | resolveTimeZone, 5 | } from "../../../src/common/datetime/resolve-time-zone"; 6 | import { TimeZone } from "../../../src/data/translation"; 7 | 8 | test("resolveTimeZone", () => { 9 | const serverTimeZone = "Vienna/Austria"; 10 | expect(resolveTimeZone(TimeZone.local, serverTimeZone)).toBe(LOCAL_TIME_ZONE); 11 | expect(resolveTimeZone(TimeZone.server, serverTimeZone)).toBe(serverTimeZone); 12 | }); 13 | -------------------------------------------------------------------------------- /test/common/entity/compute_domain.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, describe, it } from "vitest"; 2 | 3 | import { computeDomain } from "../../../src/common/entity/compute_domain"; 4 | 5 | describe("computeDomain", () => { 6 | it("Returns domains", () => { 7 | assert.equal(computeDomain("sensor.bla"), "sensor"); 8 | assert.equal(computeDomain("switch.bla"), "switch"); 9 | assert.equal(computeDomain("light.bla"), "light"); 10 | assert.equal( 11 | computeDomain("persistent_notification.bla"), 12 | "persistent_notification" 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/common/entity/compute_state_domain.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, describe, it } from "vitest"; 2 | 3 | import { computeStateDomain } from "../../../src/common/entity/compute_state_domain"; 4 | 5 | describe("computeStateDomain", () => { 6 | it("Detects sensor domain", () => { 7 | const stateObj: any = { 8 | entity_id: "sensor.test", 9 | }; 10 | assert.strictEqual(computeStateDomain(stateObj), "sensor"); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /test/common/entity/state_color.ts: -------------------------------------------------------------------------------- 1 | export {}; // for Babel to treat as a module 2 | -------------------------------------------------------------------------------- /test/common/string/is_date.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { isDate } from "../../../src/common/string/is_date"; 3 | 4 | test("isDate", () => { 5 | expect(isDate("ABC")).toBe(false); 6 | 7 | expect(isDate("2021-02-03", false)).toBe(true); 8 | expect(isDate("2021-02-03", true)).toBe(true); 9 | 10 | expect(isDate("2021-05-25T19:23:52+00:00", true)).toBe(true); 11 | expect(isDate("2021-05-25T19:23:52+00:00", false)).toBe(false); 12 | }); 13 | -------------------------------------------------------------------------------- /test/setup.ts: -------------------------------------------------------------------------------- 1 | import { beforeAll } from "vitest"; 2 | 3 | beforeAll(() => { 4 | global.window = {} as any; 5 | global.navigator = {} as any; 6 | 7 | global.__DEMO__ = false; 8 | }); 9 | --------------------------------------------------------------------------------