mirror of
https://github.com/home-assistant/frontend.git
synced 2026-06-03 06:51:48 +00:00
Compare commits
457 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 09982a9238 | |||
| ab1a58b3f3 | |||
| a7ff89385e | |||
| f3d41be3bf | |||
| b73707751a | |||
| 61bff43cdb | |||
| 0a0d08fa19 | |||
| ae29ba63ff | |||
| 0579cd8eb6 | |||
| 8c3eafec6d | |||
| b5c2e12016 | |||
| f7a13392cd | |||
| a2cdd592f1 | |||
| f04341a2a2 | |||
| 91bdc80a67 | |||
| b4824cc0a7 | |||
| 28f375c0d4 | |||
| da7ccac811 | |||
| a8ad921efd | |||
| 3b8f219800 | |||
| e36a2e1c70 | |||
| e06ea1047c | |||
| 99cb997d08 | |||
| ac3edd20f8 | |||
| 0d88d139f0 | |||
| b8d08ccb05 | |||
| 7c20316ba5 | |||
| fa633efc87 | |||
| 85d461f0fd | |||
| b55e1c9988 | |||
| 1da349a36d | |||
| 74f7139a09 | |||
| 2911cc77fa | |||
| ab20383a3a | |||
| 514cb9da9d | |||
| 7c52ac8ca7 | |||
| 07b4a44228 | |||
| 2b28a6c3f2 | |||
| 84f2e304cf | |||
| 18cd40ab01 | |||
| 8e3b1dc6ac | |||
| 5cc223a582 | |||
| 9a62a9217c | |||
| 70be747e9d | |||
| bb57a91494 | |||
| 7e22e6c0e2 | |||
| c93f910e56 | |||
| 8bf4ff5d25 | |||
| debc3adf19 | |||
| ae21017de8 | |||
| f15f518cc2 | |||
| 0e44417051 | |||
| 3581b43336 | |||
| 32b9676f97 | |||
| 7876642f35 | |||
| 0e3bcfad5e | |||
| cd1c273d5a | |||
| d92ac4b4b7 | |||
| bfecb1d4a9 | |||
| 69a8db00fa | |||
| bbda7affdc | |||
| 10c90d222d | |||
| 072f70b49f | |||
| 7f2a5ecc27 | |||
| a42f6f864a | |||
| a07772c514 | |||
| a6ab6e218f | |||
| ed96657085 | |||
| 50ca39722e | |||
| 7026e5b375 | |||
| 37e8e1b728 | |||
| 48369854af | |||
| 7715e01126 | |||
| e4ee108e14 | |||
| 407609c118 | |||
| 68cbaf6481 | |||
| b9b249a317 | |||
| df6578dfdf | |||
| b4a07f504c | |||
| 24b8078a9c | |||
| 2bd8a657b8 | |||
| 61724a52ba | |||
| 67d73261a4 | |||
| 419ba64bed | |||
| e87155bba3 | |||
| d8a3939e22 | |||
| 5141b6aea9 | |||
| 9aaf1bdd07 | |||
| a0e7c8e9bb | |||
| 8f482776b9 | |||
| 2c80183ded | |||
| 9bd5e25ee3 | |||
| 994193465f | |||
| 530b7ed457 | |||
| 24332e8288 | |||
| 980aaa2bac | |||
| 344856cbc4 | |||
| 06877cbaaa | |||
| e1ac7e98b0 | |||
| 4b2426ab77 | |||
| f9471d6b4c | |||
| 0645484258 | |||
| 2da3efb812 | |||
| e3674e550f | |||
| cff038fea4 | |||
| bed39fd8e9 | |||
| b8346d0286 | |||
| 5f80b74322 | |||
| 73e0f1e18d | |||
| 0b16b735e8 | |||
| c88dcf10b9 | |||
| 08bc23e2e7 | |||
| 97d49f06b1 | |||
| 50b727393d | |||
| 5c6dd2a697 | |||
| 87758cc228 | |||
| 60e8b8b505 | |||
| 3c012c30ac | |||
| 84d234a330 | |||
| a12543fe74 | |||
| cc53f977a2 | |||
| 71541625d7 | |||
| 43da700ccc | |||
| efbbdbf3e8 | |||
| eee6f79639 | |||
| 9381bbd656 | |||
| 2724087290 | |||
| 6bdf1ccd8c | |||
| 79743c0afa | |||
| 15b1df5a58 | |||
| 8222d9796c | |||
| 3337b414d7 | |||
| ce90d83c92 | |||
| 1f6d0d2e63 | |||
| 0327b02d0b | |||
| 780db9b066 | |||
| 89755f274d | |||
| 6ea15f507a | |||
| c506fa8990 | |||
| 9470863808 | |||
| 4bdac1f385 | |||
| 5bbfa36228 | |||
| a8070b322c | |||
| 9cbc44123e | |||
| c8f4c892f9 | |||
| 40b9f9dccb | |||
| 823c222a55 | |||
| 02acd2996c | |||
| c462fc0639 | |||
| 903553dab9 | |||
| 25a1c14523 | |||
| f03eee6cb2 | |||
| a2a38e1da7 | |||
| 88c063ba2a | |||
| 984b50bac7 | |||
| 09e4355451 | |||
| 7ee76538ae | |||
| eb8b2a9d17 | |||
| 10e8c2a148 | |||
| e1a8616ab0 | |||
| ccdd71dd64 | |||
| d3e1d55686 | |||
| 4f916abcbf | |||
| 4548f9daae | |||
| 4020bcec42 | |||
| 22c0035e60 | |||
| 6b6ad8dd2c | |||
| 3bbc3403d6 | |||
| 9979bb13ea | |||
| 8ac831679d | |||
| db05b07997 | |||
| dba8cefa67 | |||
| 6935c55c3c | |||
| 635a1185a3 | |||
| 585c894c5a | |||
| f9d052a818 | |||
| a29132441d | |||
| 479d52bf1d | |||
| d96d78d6f6 | |||
| f80cba341f | |||
| 77ee966442 | |||
| 2fec5a497e | |||
| ed75d96d3c | |||
| 0fac47992b | |||
| 91a608c4c5 | |||
| df61953ed4 | |||
| 2cda46b4bb | |||
| 037190a393 | |||
| ebe0154e32 | |||
| efa73067f6 | |||
| fdb40c9d01 | |||
| 5a7ddb4972 | |||
| dbe46d3b3f | |||
| eb43d85439 | |||
| 1bbfb79ddb | |||
| cf50db350f | |||
| e04a0ec7dc | |||
| e08576a6dc | |||
| a7831f86ee | |||
| c66e5b379b | |||
| e819c30151 | |||
| e278e33375 | |||
| 8313be8e7e | |||
| 6d95a59ca0 | |||
| a498ad3d06 | |||
| c4a2229baa | |||
| 15245af52d | |||
| c697735e46 | |||
| ddec792ae3 | |||
| cfd0e72609 | |||
| 8a5bcd67ab | |||
| a794a80228 | |||
| 41ed7d2877 | |||
| b0b86e7ba8 | |||
| e67c4842d4 | |||
| d9c39640e0 | |||
| a8478ab346 | |||
| 3ac2434b6f | |||
| f2f1044992 | |||
| 53bc66883a | |||
| d795bd1f61 | |||
| 869e1d32b3 | |||
| 3370bfa9dd | |||
| b1921d1b66 | |||
| c2a2b382e9 | |||
| 7d95c2b6cb | |||
| 67536a8a64 | |||
| 3d89ad4f91 | |||
| 36e08367d9 | |||
| 6e3cf3e42f | |||
| fe53656c7e | |||
| 14615191f4 | |||
| 86ca8ebf71 | |||
| 16c1db5346 | |||
| b9568c079e | |||
| 0f9d90c217 | |||
| ad092df9e0 | |||
| 484473080e | |||
| 97dcc62ae7 | |||
| d12d4811b4 | |||
| 3747abe1a9 | |||
| 8541494b3d | |||
| 2d1e211034 | |||
| 147a21db27 | |||
| e2e5feb8d5 | |||
| 619c75ac8b | |||
| 5b09101903 | |||
| 408efd2e2c | |||
| fd0b503a21 | |||
| 1e9a1eaa04 | |||
| b42d52b854 | |||
| 21a5e643ac | |||
| 52ac052baf | |||
| a13ffa3c35 | |||
| c51535eb79 | |||
| 5ea05768a3 | |||
| d10376e9d8 | |||
| e21f7baa93 | |||
| 14098e0d7e | |||
| bd8c407690 | |||
| c452acf6cf | |||
| 814106e4aa | |||
| a2254eb048 | |||
| fa5e0bb0c7 | |||
| e8e62a0aa0 | |||
| 4893b631a5 | |||
| d851a5bdf3 | |||
| 148d01b05b | |||
| 171875c65c | |||
| 6a61186507 | |||
| 1690991726 | |||
| 4904566460 | |||
| b3b8f1a38a | |||
| 3bb870f52a | |||
| 95a7b91ea5 | |||
| 9c4aacdb1f | |||
| 3feb40a8f4 | |||
| 7a310812e0 | |||
| ee77619da3 | |||
| cfa8eb5370 | |||
| d9d2d6aa03 | |||
| 1f46f477c7 | |||
| 52667b3266 | |||
| c790d2356c | |||
| f24c009dd7 | |||
| 8d42395938 | |||
| 1a6d46a7ff | |||
| b286b07cfd | |||
| 1859d35f7b | |||
| 29b3303f94 | |||
| 5dc2c51251 | |||
| 571fccf4a0 | |||
| 8f958147dd | |||
| 41753e48bf | |||
| d496b2a6fe | |||
| 3260c48130 | |||
| a356c153f8 | |||
| b60dc94196 | |||
| c5cb196aa1 | |||
| 5ddb31ce7b | |||
| 7465c9874c | |||
| bbe81ca8f1 | |||
| 51ecdb0851 | |||
| 268c0a60f0 | |||
| 8745cfa1ed | |||
| 8bcccb5792 | |||
| 0844d9c2c0 | |||
| 9d3aafe219 | |||
| 0cf3e34956 | |||
| 7d20b04469 | |||
| 6f6ba71e61 | |||
| d61de4d2df | |||
| f8dcee6867 | |||
| 0f975acca1 | |||
| 9e57dacb3c | |||
| 2650c1c0b2 | |||
| 6957e1f4d9 | |||
| 32be26320d | |||
| cdbaa85beb | |||
| b58fc68ea8 | |||
| 4792659c61 | |||
| eeae66e026 | |||
| 60b4b1c4e2 | |||
| 877c5e8d16 | |||
| 11fd10a011 | |||
| 623baea59d | |||
| 052909ea01 | |||
| 5e3c80ef6e | |||
| 6e2fdbb396 | |||
| 5b981062f6 | |||
| 5a2d7f100a | |||
| b62e6c9328 | |||
| 537ab2debb | |||
| 04d31e4ea9 | |||
| 3d0c7b6aab | |||
| 87d3d06e79 | |||
| 872d1c684f | |||
| d9d2ebfb9d | |||
| e26315c4d2 | |||
| d9a2e1cbee | |||
| b7d6652e5c | |||
| b188da0b5c | |||
| 9f87257f41 | |||
| f4e409f157 | |||
| 44d727763c | |||
| 2f87614c4c | |||
| 697a945056 | |||
| 67dbacce52 | |||
| e891ae6bdd | |||
| a11d1cfecf | |||
| 933bb4a2cc | |||
| 1ca1ef3c32 | |||
| f529a349b9 | |||
| b3b35e4299 | |||
| 59364d05ec | |||
| 6444c0df15 | |||
| 8f704d8c0a | |||
| aeddeb3bd7 | |||
| 1377e3a363 | |||
| e47bf22798 | |||
| b3f1ba9433 | |||
| 829c5ca4df | |||
| fbd4fc6d5f | |||
| 7612ec1979 | |||
| 71a5a1d3b4 | |||
| ad91d360f8 | |||
| a88f492c05 | |||
| 0fc85a52a0 | |||
| e01dc89a48 | |||
| 52c36db5d4 | |||
| f217dab8d4 | |||
| 5709af57de | |||
| bb16cc8c00 | |||
| 17c6dc52a8 | |||
| 1b8211db6d | |||
| 2b2bb77a2b | |||
| 64749350ef | |||
| 043d4eed85 | |||
| 2f2e64bb1d | |||
| b74b02c09f | |||
| ab4c3a4316 | |||
| b89b02e044 | |||
| daff323606 | |||
| 356bceb1cc | |||
| acb5af2f41 | |||
| 17314fe62b | |||
| 3826a69465 | |||
| a68acdf9dd | |||
| bb56bbb1ba | |||
| 76aef60c05 | |||
| 23af40743b | |||
| c4326b4f3a | |||
| d248f5614f | |||
| a4da7b26ea | |||
| 3c49cdf3c0 | |||
| 26af81d1a4 | |||
| 2a08f2d79b | |||
| a5be02b743 | |||
| 4228871f00 | |||
| 9a7a8fd377 | |||
| 8b82882e15 | |||
| 2701015eda | |||
| 1991a9e493 | |||
| 2b72c54194 | |||
| a7cb2fe7a7 | |||
| 51ea0c8201 | |||
| ead7081bc6 | |||
| ee982b1899 | |||
| e8b100a39e | |||
| 50c361db62 | |||
| e7a8d15a13 | |||
| fbd0409837 | |||
| a0d100611f | |||
| a969bf1065 | |||
| a153330610 | |||
| bd2f1ca3a8 | |||
| 3263034416 | |||
| 82b28b547a | |||
| 61c2c750b4 | |||
| 117690ee70 | |||
| e753de85eb | |||
| a240019968 | |||
| 0bdf4b8777 | |||
| 6337828ed8 | |||
| b8e5af652b | |||
| e4ae29e8b5 | |||
| 08231dbbb0 | |||
| 0ca656933d | |||
| b23cf8eba4 | |||
| 61b546415d | |||
| 4e1b709303 | |||
| 34e65b302d | |||
| 336d0e1b9d | |||
| 58d4cf8d84 | |||
| d3453aff37 | |||
| 64ff2e414c | |||
| 2ca25c980f | |||
| 73d93bc601 | |||
| 5ca6a8aced | |||
| 7ff4993e0b | |||
| 4e6fbacccc | |||
| 2958d49e36 | |||
| 92289dc7ea | |||
| f6c1a890e4 | |||
| d06321ed43 | |||
| 3c3d8d9974 | |||
| 4f39fa482d | |||
| 5d0fe3236c | |||
| b86142ae50 | |||
| 5d2f3ee5e8 | |||
| e3f7c631a7 | |||
| 49f9d95853 | |||
| db3d7701b5 | |||
| 3e55acf531 | |||
| f102618d9d | |||
| a3c02b511d | |||
| 74111d248e |
@@ -464,7 +464,14 @@ this.hass.localize("ui.panel.config.updates.update_available", {
|
||||
|
||||
### Pull Requests
|
||||
|
||||
When creating a pull request, you **must** use the PR template located at `.github/PULL_REQUEST_TEMPLATE.md`. Read the template file and use its full content as the PR body, filling in each section appropriately. Do not omit, reorder, or rewrite the template sections. Do not check the checklist items on behalf of the user — those are the user's responsibility to review and check. If the PR includes UI changes, remind the user to add screenshots or a short video to the PR after creating it.
|
||||
When creating a pull request, you **must** use the PR template located at `.github/PULL_REQUEST_TEMPLATE.md`. Read the template file and use its full content as the PR body, filling in each section appropriately.
|
||||
|
||||
- Do not omit, reorder, or rewrite the template sections
|
||||
- Check the appropriate "Type of change" box based on the changes
|
||||
- Do not check the checklist items on behalf of the user — those are the user's responsibility to review and check
|
||||
- If the PR includes UI changes, remind the user to add screenshots or a short video to the PR after creating it
|
||||
- Be simple and user friendly — explain what the change does, not implementation details
|
||||
- Use markdown so the user can copy it
|
||||
|
||||
### Text and Copy Guidelines
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ updates:
|
||||
schedule:
|
||||
interval: weekly
|
||||
time: "06:00"
|
||||
cooldown:
|
||||
default-days-before-reopen: 30
|
||||
default-days: 7
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- Dependencies
|
||||
|
||||
@@ -8,6 +8,9 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=6144
|
||||
|
||||
@@ -24,9 +27,10 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: dev
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -59,9 +63,10 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: master
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
||||
@@ -18,6 +18,9 @@ concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint and check format
|
||||
@@ -25,8 +28,10 @@ jobs:
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -37,7 +42,7 @@ jobs:
|
||||
- name: Build resources
|
||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
|
||||
- name: Setup lint cache
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: |
|
||||
node_modules/.cache/prettier
|
||||
@@ -59,8 +64,10 @@ jobs:
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -77,8 +84,10 @@ jobs:
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -89,13 +98,13 @@ jobs:
|
||||
env:
|
||||
IS_TEST: "true"
|
||||
- name: Upload bundle stats
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: frontend-bundle-stats
|
||||
path: build/stats/*.json
|
||||
if-no-files-found: error
|
||||
- name: Upload frontend build
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: frontend-build
|
||||
path: hass_frontend/
|
||||
|
||||
@@ -7,6 +7,10 @@ on:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [dev]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
@@ -28,6 +32,7 @@ jobs:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
@@ -36,14 +41,14 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
|
||||
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
|
||||
uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -57,4 +62,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
|
||||
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
|
||||
|
||||
@@ -9,6 +9,9 @@ on:
|
||||
- dev
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=6144
|
||||
|
||||
@@ -25,9 +28,10 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: dev
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -60,9 +64,10 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: master
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
||||
@@ -5,6 +5,9 @@ on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=6144
|
||||
|
||||
@@ -17,9 +20,11 @@ jobs:
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
||||
@@ -10,6 +10,9 @@ on:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=6144
|
||||
|
||||
@@ -22,9 +25,11 @@ jobs:
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: "Pull Request Labeler"
|
||||
|
||||
on: pull_request_target
|
||||
on: pull_request_target # zizmor: ignore[dangerous-triggers] -- safe: only runs actions/labeler, no PR code checkout
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
|
||||
@@ -5,6 +5,10 @@ on:
|
||||
schedule:
|
||||
- cron: "0 * * * *"
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -21,6 +21,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
||||
@@ -28,7 +30,7 @@ jobs:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -57,14 +59,14 @@ jobs:
|
||||
run: tar -czvf translations.tar.gz translations
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: wheels
|
||||
path: dist/home_assistant_frontend*.whl
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload translations
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: translations
|
||||
path: translations.tar.gz
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
name: RelativeCI
|
||||
|
||||
on:
|
||||
# zizmor: ignore[dangerous-triggers] -- safe: only downloads artifacts, no PR code checkout
|
||||
workflow_run:
|
||||
workflows: [CI]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
name: Upload stats
|
||||
upload-frontend-modern:
|
||||
name: Upload stats (frontend/modern)
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
strategy:
|
||||
matrix:
|
||||
bundle: [frontend]
|
||||
build: [modern, legacy]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send bundle stats and build information to RelativeCI
|
||||
uses: relative-ci/agent-action@3c681926017930047fc03acaa35cd6a44efcbfc3 # v3.2.2
|
||||
with:
|
||||
key: ${{ secrets[format('RELATIVE_CI_KEY_{0}_{1}', matrix.bundle, matrix.build)] }}
|
||||
key: ${{ secrets.RELATIVE_CI_KEY_frontend_modern }}
|
||||
token: ${{ github.token }}
|
||||
artifactName: ${{ format('{0}-bundle-stats', matrix.bundle) }}
|
||||
webpackStatsFile: ${{ format('{0}-{1}.json', matrix.bundle, matrix.build) }}
|
||||
artifactName: frontend-bundle-stats
|
||||
webpackStatsFile: frontend-modern.json
|
||||
|
||||
upload-frontend-legacy:
|
||||
name: Upload stats (frontend/legacy)
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send bundle stats and build information to RelativeCI
|
||||
uses: relative-ci/agent-action@3c681926017930047fc03acaa35cd6a44efcbfc3 # v3.2.2
|
||||
with:
|
||||
key: ${{ secrets.RELATIVE_CI_KEY_frontend_legacy }}
|
||||
token: ${{ github.token }}
|
||||
artifactName: frontend-bundle-stats
|
||||
webpackStatsFile: frontend-legacy.json
|
||||
|
||||
@@ -18,6 +18,6 @@ jobs:
|
||||
pull-requests: read
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@6db134d15f3909ccc9eefd369f02bd1e9cffdf97 # v6.2.0
|
||||
- uses: release-drafter/release-drafter@139054aeaa9adc52ab36ddf67437541f039b88e2 # v7.1.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -27,6 +27,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
@@ -34,13 +36,12 @@ jobs:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: Verify version
|
||||
uses: home-assistant/actions/helpers/verify-version@master
|
||||
uses: home-assistant/actions/helpers/verify-version@d56d093b9ab8d2105bc0cb6ee9bcc0ef4ec8b96d # master
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
@@ -62,11 +63,10 @@ jobs:
|
||||
skip-existing: true
|
||||
|
||||
- name: Upload release assets
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
|
||||
with:
|
||||
files: |
|
||||
dist/*.whl
|
||||
dist/*.tar.gz
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG_NAME" dist/*.whl dist/*.tar.gz --clobber
|
||||
|
||||
wheels-init:
|
||||
name: Init wheels build
|
||||
@@ -74,15 +74,17 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate requirements.txt
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
run: |
|
||||
# Sleep to give pypi time to populate the new version across mirrors
|
||||
sleep 240
|
||||
version=$(echo "${{ github.ref }}" | awk -F"/" '{print $NF}' )
|
||||
version=$(echo "$GITHUB_REF" | awk -F"/" '{print $NF}' )
|
||||
echo "home-assistant-frontend==$version" > ./requirements.txt
|
||||
|
||||
# home-assistant/wheels doesn't support SHA pinning
|
||||
- name: Build wheels
|
||||
uses: home-assistant/wheels@2025.12.0
|
||||
uses: home-assistant/wheels@e5742a69d69f0e274e2689c998900c7d19652c21 # 2025.12.0
|
||||
with:
|
||||
abi: cp314
|
||||
tag: musllinux_1_2
|
||||
@@ -99,11 +101,12 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
- name: Download Translations
|
||||
@@ -113,8 +116,11 @@ jobs:
|
||||
- name: Build landing-page
|
||||
run: landing-page/script/build_landing_page
|
||||
- name: Tar folder
|
||||
run: tar -czf landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz -C landing-page/dist .
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: tar -czf "landing-page/home_assistant_frontend_landingpage-${TAG_NAME}.tar.gz" -C landing-page/dist .
|
||||
- name: Upload release asset
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
|
||||
with:
|
||||
files: landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG_NAME" "landing-page/home_assistant_frontend_landingpage-${TAG_NAME}.tar.gz" --clobber
|
||||
|
||||
@@ -5,6 +5,10 @@ on:
|
||||
schedule:
|
||||
- cron: "0 * * * *"
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -8,6 +8,9 @@ on:
|
||||
paths:
|
||||
- src/translations/en.json
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
name: Upload
|
||||
@@ -15,6 +18,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Upload Translations
|
||||
run: |
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ index 8795ddcaa77aea7b0356417e4bc4b19e2b3f860c..fcdc68342d9ac53936c9ed40a9ccfc2f
|
||||
@@ -129,7 +129,10 @@ export async function injectManifest(
|
||||
searchString: options.injectionPoint!,
|
||||
});
|
||||
|
||||
|
||||
- filesToWrite[options.swDest] = source;
|
||||
+ filesToWrite[options.swDest] = source.replace(
|
||||
+ url!,
|
||||
Vendored
-942
File diff suppressed because one or more lines are too long
+940
File diff suppressed because one or more lines are too long
+1
-1
@@ -8,4 +8,4 @@ enableGlobalCache: false
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.12.0.cjs
|
||||
yarnPath: .yarn/releases/yarn-4.13.0.cjs
|
||||
|
||||
@@ -99,6 +99,44 @@ const lokaliseProjects = {
|
||||
frontend: "3420425759f6d6d241f598.13594006",
|
||||
};
|
||||
|
||||
const POLL_INTERVAL_MS = 1000;
|
||||
|
||||
/* eslint-disable no-await-in-loop */
|
||||
async function pollProcess(lokaliseApi, projectId, processId) {
|
||||
while (true) {
|
||||
const process = await lokaliseApi
|
||||
.queuedProcesses()
|
||||
.get(processId, { project_id: projectId });
|
||||
|
||||
const project =
|
||||
projectId === lokaliseProjects.backend ? "backend" : "frontend";
|
||||
|
||||
if (process.status === "finished") {
|
||||
console.log(`Lokalise export process for ${project} finished`);
|
||||
return process;
|
||||
}
|
||||
|
||||
if (process.status === "failed" || process.status === "cancelled") {
|
||||
throw new Error(
|
||||
`Lokalise export process for ${project} ${process.status}: ${process.message}`
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Lokalise export process for ${project} in progress...`,
|
||||
process.status,
|
||||
process.details?.items_to_process
|
||||
? `${Math.round(((process.details.items_processed || 0) / process.details.items_to_process) * 100)}% (${process.details.items_processed}/${process.details.items_to_process})`
|
||||
: ""
|
||||
);
|
||||
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, POLL_INTERVAL_MS);
|
||||
});
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-await-in-loop */
|
||||
|
||||
gulp.task("fetch-lokalise", async function () {
|
||||
let apiKey;
|
||||
try {
|
||||
@@ -118,55 +156,60 @@ gulp.task("fetch-lokalise", async function () {
|
||||
]);
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(lokaliseProjects).map(([project, projectId]) =>
|
||||
lokaliseApi
|
||||
.files()
|
||||
.download(projectId, {
|
||||
format: "json",
|
||||
original_filenames: false,
|
||||
replace_breaks: false,
|
||||
json_unescaped_slashes: true,
|
||||
export_empty_as: "skip",
|
||||
filter_data: ["verified"],
|
||||
})
|
||||
.then((download) => fetch(download.bundle_url))
|
||||
.then((response) => {
|
||||
if (response.status === 200 || response.status === 0) {
|
||||
return response.arrayBuffer();
|
||||
}
|
||||
Object.entries(lokaliseProjects).map(async ([project, projectId]) => {
|
||||
try {
|
||||
const exportProcess = await lokaliseApi
|
||||
.files()
|
||||
.async_download(projectId, {
|
||||
format: "json",
|
||||
original_filenames: false,
|
||||
replace_breaks: false,
|
||||
json_unescaped_slashes: true,
|
||||
export_empty_as: "skip",
|
||||
filter_data: ["verified"],
|
||||
});
|
||||
|
||||
const finishedProcess = await pollProcess(
|
||||
lokaliseApi,
|
||||
projectId,
|
||||
exportProcess.process_id
|
||||
);
|
||||
|
||||
const bundleUrl = finishedProcess.details.download_url;
|
||||
|
||||
console.log(`Downloading translations from: ${bundleUrl}`);
|
||||
|
||||
const response = await fetch(bundleUrl);
|
||||
|
||||
if (response.status !== 200 && response.status !== 0) {
|
||||
throw new Error(response.statusText);
|
||||
})
|
||||
.then(JSZip.loadAsync)
|
||||
.then(async (contents) => {
|
||||
await mkdirPromise;
|
||||
return Promise.all(
|
||||
Object.keys(contents.files).map(async (filename) => {
|
||||
const file = contents.file(filename);
|
||||
if (!file) {
|
||||
// no file, probably a directory
|
||||
return Promise.resolve();
|
||||
}
|
||||
return file
|
||||
.async("nodebuffer")
|
||||
.then((content) =>
|
||||
fs.writeFile(
|
||||
path.join(
|
||||
inDir,
|
||||
project,
|
||||
filename.split("/").splice(-1)[0]
|
||||
),
|
||||
content,
|
||||
{ flag: "w", encoding }
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
throw err;
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
console.log(`Extracting translations...`);
|
||||
|
||||
const contents = await JSZip.loadAsync(await response.arrayBuffer());
|
||||
|
||||
await mkdirPromise;
|
||||
await Promise.all(
|
||||
Object.keys(contents.files).map(async (filename) => {
|
||||
const file = contents.file(filename);
|
||||
if (!file) {
|
||||
// no file, probably a directory
|
||||
return;
|
||||
}
|
||||
const content = await file.async("nodebuffer");
|
||||
await fs.writeFile(
|
||||
path.join(inDir, project, filename.split("/").splice(-1)[0]),
|
||||
content,
|
||||
{ flag: "w", encoding }
|
||||
);
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -40,18 +40,24 @@ const convertToJSON = async (
|
||||
throw e;
|
||||
}
|
||||
// Convert to JSON
|
||||
const parts = localeData.split("} else {");
|
||||
const firstBlock = parts[0];
|
||||
const obj = INTL_POLYFILLS[pkg];
|
||||
const dataRegex = new RegExp(
|
||||
`Intl\\.${obj}\\.${addFunc}\\((?<data>.*)\\)`,
|
||||
"s"
|
||||
);
|
||||
localeData = localeData.match(dataRegex)?.groups?.data;
|
||||
localeData = firstBlock.match(dataRegex)?.groups?.data;
|
||||
if (!localeData) {
|
||||
throw Error(`Failed to extract data for language ${lang} from ${pkg}`);
|
||||
}
|
||||
// Parse to validate JSON, then stringify to minify
|
||||
localeData = JSON.stringify(JSON.parse(localeData));
|
||||
await writeFile(join(outDir, `${pkg}/${lang}.json`), localeData);
|
||||
try {
|
||||
localeData = JSON.stringify(JSON.parse(localeData));
|
||||
await writeFile(join(outDir, `${pkg}/${lang}.json`), localeData);
|
||||
} catch (e) {
|
||||
throw Error(`Failed to parse JSON for language ${lang} from ${pkg}: ${e}`);
|
||||
}
|
||||
};
|
||||
|
||||
gulp.task("clean-locale-data", async () => deleteSync([outDir]));
|
||||
|
||||
@@ -57,6 +57,12 @@ const runDevServer = async ({
|
||||
directory: contentBase,
|
||||
watch: true,
|
||||
},
|
||||
client: {
|
||||
overlay: {
|
||||
runtimeErrors: (error) =>
|
||||
!error?.message?.includes("ResizeObserver loop"),
|
||||
},
|
||||
},
|
||||
proxy,
|
||||
},
|
||||
compiler
|
||||
|
||||
@@ -26,7 +26,7 @@ import "../../../../src/components/ha-svg-icon";
|
||||
import "../../../../src/layouts/hass-loading-screen";
|
||||
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
||||
import "./hc-layout";
|
||||
import "../../../../src/components/ha-textfield";
|
||||
import "../../../../src/components/input/ha-input";
|
||||
import "../../../../src/components/ha-button";
|
||||
|
||||
const seeFAQ = (qid) => html`
|
||||
@@ -123,11 +123,11 @@ export class HcConnect extends LitElement {
|
||||
To get started, enter your Home Assistant URL and click authorize.
|
||||
If you want a preview instead, click the show demo button.
|
||||
</p>
|
||||
<ha-textfield
|
||||
<ha-input
|
||||
label="Home Assistant URL"
|
||||
placeholder="https://abcdefghijklmnop.ui.nabu.casa"
|
||||
@keydown=${this._handleInputKeyDown}
|
||||
></ha-textfield>
|
||||
></ha-input>
|
||||
${this.error ? html` <p class="error">${this.error}</p> ` : ""}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
@@ -204,7 +204,7 @@ export class HcConnect extends LitElement {
|
||||
}
|
||||
|
||||
private async _handleConnect() {
|
||||
const inputEl = this.shadowRoot!.querySelector("ha-textfield")!;
|
||||
const inputEl = this.shadowRoot!.querySelector("ha-input")!;
|
||||
const value = inputEl.value || "";
|
||||
this.error = undefined;
|
||||
|
||||
@@ -319,7 +319,7 @@ export class HcConnect extends LitElement {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
ha-textfield {
|
||||
ha-input {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { Entity } from "../../../../src/fake_data/entity";
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import type { EntityInput } from "../../../../src/fake_data/entities/types";
|
||||
|
||||
export const castDemoEntities: () => Entity[] = () =>
|
||||
convertEntities({
|
||||
export const castDemoEntities: () => EntityInput[] = () =>
|
||||
Object.values({
|
||||
"light.reading_light": {
|
||||
entity_id: "light.reading_light",
|
||||
state: "on",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import type { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
convertEntities({
|
||||
Object.values({
|
||||
"todo.shopping_list": {
|
||||
entity_id: "todo.shopping_list",
|
||||
state: "2",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import type { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesJimpower: DemoConfig["entities"] = () =>
|
||||
convertEntities({
|
||||
Object.values({
|
||||
"todo.shopping_list": {
|
||||
entity_id: "todo.shopping_list",
|
||||
state: "2",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import type { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
||||
convertEntities({
|
||||
Object.values({
|
||||
"todo.shopping_list": {
|
||||
entity_id: "todo.shopping_list",
|
||||
state: "2",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import type { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesSections: DemoConfig["entities"] = (localize) =>
|
||||
convertEntities({
|
||||
Object.values({
|
||||
"cover.living_room_garden_shutter": {
|
||||
entity_id: "cover.living_room_garden_shutter",
|
||||
state: "open",
|
||||
@@ -142,7 +141,7 @@ export const demoEntitiesSections: DemoConfig["entities"] = (localize) =>
|
||||
},
|
||||
},
|
||||
"device_tracker.car": {
|
||||
entity_id: "sensor.outdoor_humidity",
|
||||
entity_id: "device_tracker.car",
|
||||
state: "not_home",
|
||||
attributes: {
|
||||
friendly_name: "Car",
|
||||
@@ -200,7 +199,7 @@ export const demoEntitiesSections: DemoConfig["entities"] = (localize) =>
|
||||
},
|
||||
},
|
||||
"binary_sensor.kitchen_motion": {
|
||||
entity_id: "light.kitchen_motion",
|
||||
entity_id: "binary_sensor.kitchen_motion",
|
||||
state: "on",
|
||||
attributes: {
|
||||
device_class: "motion",
|
||||
@@ -336,7 +335,7 @@ export const demoEntitiesSections: DemoConfig["entities"] = (localize) =>
|
||||
},
|
||||
},
|
||||
"sensor.rain": {
|
||||
entity_id: "sensor.moon_phase",
|
||||
entity_id: "sensor.rain",
|
||||
state: "7.2",
|
||||
attributes: {
|
||||
state_class: "total_increasing",
|
||||
@@ -566,7 +565,7 @@ export const demoEntitiesSections: DemoConfig["entities"] = (localize) =>
|
||||
},
|
||||
},
|
||||
"update.home_assistant_core_update": {
|
||||
entity_id: "update.home_assistant_supervisor_update",
|
||||
entity_id: "update.home_assistant_core_update",
|
||||
state: "off",
|
||||
attributes: {
|
||||
auto_update: false,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import type { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
convertEntities({
|
||||
Object.values({
|
||||
"todo.shopping_list": {
|
||||
entity_id: "todo.shopping_list",
|
||||
state: "2",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { TemplateResult } from "lit";
|
||||
import type { LocalizeFunc } from "../../../src/common/translations/localize";
|
||||
import type { LovelaceConfig } from "../../../src/data/lovelace/config/types";
|
||||
import type { Entity } from "../../../src/fake_data/entity";
|
||||
import type { EntityInput } from "../../../src/fake_data/entities/types";
|
||||
|
||||
export interface DemoConfig {
|
||||
index?: number;
|
||||
@@ -12,6 +12,6 @@ export interface DemoConfig {
|
||||
| string
|
||||
| ((localize: LocalizeFunc) => string | TemplateResult<1>);
|
||||
lovelace: (localize: LocalizeFunc) => LovelaceConfig;
|
||||
entities: (localize: LocalizeFunc) => Entity[];
|
||||
entities: (localize: LocalizeFunc) => EntityInput[];
|
||||
theme: () => Record<string, string> | null;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/// <reference types="chromecast-caf-sender" />
|
||||
import { mdiTelevision } from "@mdi/js";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { convertEntities } from "../../../src/fake_data/entity";
|
||||
|
||||
export const mapEntities = () =>
|
||||
convertEntities({
|
||||
Object.values({
|
||||
"zone.home": {
|
||||
entity_id: "zone.home",
|
||||
state: "zoning",
|
||||
@@ -51,7 +49,7 @@ export const mapEntities = () =>
|
||||
});
|
||||
|
||||
export const energyEntities = () =>
|
||||
convertEntities({
|
||||
Object.values({
|
||||
"sensor.grid_fossil_fuel_percentage": {
|
||||
entity_id: "sensor.grid_fossil_fuel_percentage",
|
||||
state: "88.6",
|
||||
|
||||
+251
-173
@@ -1,175 +1,253 @@
|
||||
import { getEntity } from "../../../src/fake_data/entity";
|
||||
|
||||
export const createMediaPlayerEntities = () => [
|
||||
getEntity("media_player", "music_paused", "paused", {
|
||||
friendly_name: "Pausing The Music",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
||||
// Select Source + Stop + Clear + Play + Shuffle Set
|
||||
supported_features: 64063,
|
||||
entity_picture: "/images/album_cover_2.jpg",
|
||||
media_duration: 300,
|
||||
media_position: 50,
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
volume_level: 0.5,
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
source: "AirPlay",
|
||||
sound_mode_list: ["Movie", "Music", "Game", "Pure Audio"],
|
||||
sound_mode: "Music",
|
||||
}),
|
||||
getEntity("media_player", "music_playing", "playing", {
|
||||
friendly_name: "Playing The Music",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
||||
// Select Source + Stop + Clear + Play + Shuffle Set + Browse Media + Grouping
|
||||
supported_features: 784959,
|
||||
entity_picture: "/images/album_cover.jpg",
|
||||
media_duration: 300,
|
||||
media_position: 0,
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
volume_level: 0.5,
|
||||
sound_mode_list: ["Movie", "Music", "Game", "Pure Audio"],
|
||||
sound_mode: "Music",
|
||||
group_members: ["media_player.playing", "media_player.stream_playing"],
|
||||
}),
|
||||
getEntity("media_player", "stream_playing", "playing", {
|
||||
friendly_name: "Playing the Stream",
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
entity_picture: "/images/frenck.jpg",
|
||||
// Pause + Next Track + Play + Browse Media
|
||||
supported_features: 147489,
|
||||
}),
|
||||
getEntity("media_player", "stream_paused", "paused", {
|
||||
friendly_name: "Paused the Stream",
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
entity_picture: "/images/frenck.jpg",
|
||||
// Pause + Next Track + Play
|
||||
supported_features: 16417,
|
||||
}),
|
||||
getEntity("media_player", "stream_playing_previous", "playing", {
|
||||
friendly_name: 'Playing the Stream (with "previous" support)',
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
entity_picture: "/images/frenck.jpg",
|
||||
// Pause + Previous Track + Play
|
||||
supported_features: 16401,
|
||||
}),
|
||||
getEntity("media_player", "tv_playing", "playing", {
|
||||
friendly_name: "Playing non-skip TV Show",
|
||||
media_content_type: "tvshow",
|
||||
media_title: "Chapter 1",
|
||||
media_series_title: "House of Cards",
|
||||
app_name: "Netflix",
|
||||
entity_picture: "/images/netflix.jpg",
|
||||
// Pause
|
||||
supported_features: 1,
|
||||
}),
|
||||
getEntity("media_player", "sonos_idle", "idle", {
|
||||
friendly_name: "Sonos Idle",
|
||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
||||
// Select Source + Stop + Clear + Play + Shuffle Set
|
||||
supported_features: 64063,
|
||||
volume_level: 0.33,
|
||||
is_volume_muted: true,
|
||||
}),
|
||||
getEntity("media_player", "idle_browse_media", "idle", {
|
||||
friendly_name: "Idle waiting for Browse Media (e.g. Spotify)",
|
||||
// Pause + Seek + Volume Set + Previous Track + Next Track + Play Media +
|
||||
// Select Source + Play + Shuffle Set + Browse Media
|
||||
supported_features: 182839,
|
||||
volume_level: 0.79,
|
||||
}),
|
||||
getEntity("media_player", "theater_off", "off", {
|
||||
friendly_name: "TV Off",
|
||||
// On + Off + Play + Next + Pause
|
||||
supported_features: 16801,
|
||||
}),
|
||||
getEntity("media_player", "theater_on", "on", {
|
||||
friendly_name: "TV On",
|
||||
// On + Off + Play + Next + Pause
|
||||
supported_features: 16801,
|
||||
}),
|
||||
getEntity("media_player", "theater_off_static", "off", {
|
||||
friendly_name: "TV Off (cannot be switched on)",
|
||||
// Off + Next + Pause
|
||||
supported_features: 289,
|
||||
}),
|
||||
getEntity("media_player", "theater_on_static", "on", {
|
||||
friendly_name: "TV On (cannot be switched off)",
|
||||
// On + Next + Pause
|
||||
supported_features: 161,
|
||||
}),
|
||||
getEntity("media_player", "android_cast", "playing", {
|
||||
friendly_name: "Casting App (no supported features)",
|
||||
media_title: "Android Screen Casting",
|
||||
app_name: "Screen Mirroring",
|
||||
}),
|
||||
getEntity("media_player", "image_display", "playing", {
|
||||
friendly_name: "Digital Picture Frame",
|
||||
media_content_type: "image",
|
||||
media_title: "Famous Painting",
|
||||
media_artist: "Famous Artist",
|
||||
entity_picture: "/images/sunflowers.jpg",
|
||||
// On + Off + Browse Media
|
||||
supported_features: 131456,
|
||||
}),
|
||||
getEntity("media_player", "unavailable", "unavailable", {
|
||||
friendly_name: "Player Unavailable",
|
||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
||||
// Play Media + Stop + Play
|
||||
supported_features: 21437,
|
||||
}),
|
||||
getEntity("media_player", "unknown", "unknown", {
|
||||
friendly_name: "Player Unknown",
|
||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
||||
// Play Media + Stop + Play
|
||||
supported_features: 21437,
|
||||
}),
|
||||
getEntity("media_player", "playing", "playing", {
|
||||
friendly_name: "Player Playing (no Pause support)",
|
||||
// Volume Set + Volume Mute + Previous Track + Next Track +
|
||||
// Play Media + Stop + Play
|
||||
supported_features: 21436,
|
||||
volume_level: 1,
|
||||
}),
|
||||
getEntity("media_player", "idle", "idle", {
|
||||
friendly_name: "Player Idle",
|
||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
||||
// Play Media + Stop + Play
|
||||
supported_features: 21437,
|
||||
volume_level: 0,
|
||||
}),
|
||||
getEntity("media_player", "receiver_on", "on", {
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
sound_mode_list: ["Movie", "Music", "Game", "Pure Audio"],
|
||||
volume_level: 0.63,
|
||||
is_volume_muted: false,
|
||||
source: "TV",
|
||||
sound_mode: "Movie",
|
||||
friendly_name: "Receiver (selectable sources)",
|
||||
// Volume Set + Volume Mute + On + Off + Select Source + Play + Sound Mode
|
||||
supported_features: 84364,
|
||||
}),
|
||||
getEntity("media_player", "receiver_off", "off", {
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
sound_mode_list: ["Movie", "Music", "Game", "Pure Audio"],
|
||||
friendly_name: "Receiver (selectable sources)",
|
||||
// Volume Set + Volume Mute + On + Off + Select Source + Play + Sound Mode
|
||||
supported_features: 84364,
|
||||
}),
|
||||
{
|
||||
entity_id: "media_player.music_paused",
|
||||
state: "paused",
|
||||
attributes: {
|
||||
friendly_name: "Pausing The Music",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
||||
// Select Source + Stop + Clear + Play + Shuffle Set
|
||||
supported_features: 64063,
|
||||
entity_picture: "/images/album_cover_2.jpg",
|
||||
media_duration: 300,
|
||||
media_position: 50,
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
volume_level: 0.5,
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
source: "AirPlay",
|
||||
sound_mode_list: ["Movie", "Music", "Game", "Pure Audio"],
|
||||
sound_mode: "Music",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.music_playing",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Playing The Music",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
||||
// Select Source + Stop + Clear + Play + Shuffle Set + Browse Media + Grouping
|
||||
supported_features: 784959,
|
||||
entity_picture: "/images/album_cover.jpg",
|
||||
media_duration: 300,
|
||||
media_position: 0,
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
volume_level: 0.5,
|
||||
sound_mode_list: ["Movie", "Music", "Game", "Pure Audio"],
|
||||
sound_mode: "Music",
|
||||
group_members: ["media_player.playing", "media_player.stream_playing"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.stream_playing",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Playing the Stream",
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
entity_picture: "/images/frenck.jpg",
|
||||
// Pause + Next Track + Play + Browse Media
|
||||
supported_features: 147489,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.stream_paused",
|
||||
state: "paused",
|
||||
attributes: {
|
||||
friendly_name: "Paused the Stream",
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
entity_picture: "/images/frenck.jpg",
|
||||
// Pause + Next Track + Play
|
||||
supported_features: 16417,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.stream_playing_previous",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: 'Playing the Stream (with "previous" support)',
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
entity_picture: "/images/frenck.jpg",
|
||||
// Pause + Previous Track + Play
|
||||
supported_features: 16401,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.tv_playing",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Playing non-skip TV Show",
|
||||
media_content_type: "tvshow",
|
||||
media_title: "Chapter 1",
|
||||
media_series_title: "House of Cards",
|
||||
app_name: "Netflix",
|
||||
entity_picture: "/images/netflix.jpg",
|
||||
// Pause
|
||||
supported_features: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.sonos_idle",
|
||||
state: "idle",
|
||||
attributes: {
|
||||
friendly_name: "Sonos Idle",
|
||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
||||
// Select Source + Stop + Clear + Play + Shuffle Set
|
||||
supported_features: 64063,
|
||||
volume_level: 0.33,
|
||||
is_volume_muted: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.idle_browse_media",
|
||||
state: "idle",
|
||||
attributes: {
|
||||
friendly_name: "Idle waiting for Browse Media (e.g. Spotify)",
|
||||
// Pause + Seek + Volume Set + Previous Track + Next Track + Play Media +
|
||||
// Select Source + Play + Shuffle Set + Browse Media
|
||||
supported_features: 182839,
|
||||
volume_level: 0.79,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.theater_off",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "TV Off",
|
||||
// On + Off + Play + Next + Pause
|
||||
supported_features: 16801,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.theater_on",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "TV On",
|
||||
// On + Off + Play + Next + Pause
|
||||
supported_features: 16801,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.theater_off_static",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "TV Off (cannot be switched on)",
|
||||
// Off + Next + Pause
|
||||
supported_features: 289,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.theater_on_static",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "TV On (cannot be switched off)",
|
||||
// On + Next + Pause
|
||||
supported_features: 161,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.android_cast",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Casting App (no supported features)",
|
||||
media_title: "Android Screen Casting",
|
||||
app_name: "Screen Mirroring",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.image_display",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Digital Picture Frame",
|
||||
media_content_type: "image",
|
||||
media_title: "Famous Painting",
|
||||
media_artist: "Famous Artist",
|
||||
entity_picture: "/images/sunflowers.jpg",
|
||||
// On + Off + Browse Media
|
||||
supported_features: 131456,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Player Unavailable",
|
||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
||||
// Play Media + Stop + Play
|
||||
supported_features: 21437,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.unknown",
|
||||
state: "unknown",
|
||||
attributes: {
|
||||
friendly_name: "Player Unknown",
|
||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
||||
// Play Media + Stop + Play
|
||||
supported_features: 21437,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.playing",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Player Playing (no Pause support)",
|
||||
// Volume Set + Volume Mute + Previous Track + Next Track +
|
||||
// Play Media + Stop + Play
|
||||
supported_features: 21436,
|
||||
volume_level: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.idle",
|
||||
state: "idle",
|
||||
attributes: {
|
||||
friendly_name: "Player Idle",
|
||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
||||
// Play Media + Stop + Play
|
||||
supported_features: 21437,
|
||||
volume_level: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.receiver_on",
|
||||
state: "on",
|
||||
attributes: {
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
sound_mode_list: ["Movie", "Music", "Game", "Pure Audio"],
|
||||
volume_level: 0.63,
|
||||
is_volume_muted: false,
|
||||
source: "TV",
|
||||
sound_mode: "Movie",
|
||||
friendly_name: "Receiver (selectable sources)",
|
||||
// Volume Set + Volume Mute + On + Off + Select Source + Play + Sound Mode
|
||||
supported_features: 84364,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.receiver_off",
|
||||
state: "off",
|
||||
attributes: {
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
sound_mode_list: ["Movie", "Music", "Game", "Pure Audio"],
|
||||
friendly_name: "Receiver (selectable sources)",
|
||||
// Volume Set + Volume Mute + On + Off + Select Source + Play + Sound Mode
|
||||
supported_features: 84364,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
+77
-67
@@ -1,72 +1,82 @@
|
||||
import { getEntity } from "../../../src/fake_data/entity";
|
||||
|
||||
export const createPlantEntities = () => [
|
||||
getEntity("plant", "lemon_tree", "ok", {
|
||||
problem: "none",
|
||||
sensors: {
|
||||
moisture: "sensor.lemon_tree_moisture",
|
||||
battery: "sensor.lemon_tree_battery",
|
||||
temperature: "sensor.lemon_tree_temperature",
|
||||
conductivity: "sensor.lemon_tree_conductivity",
|
||||
brightness: "sensor.lemon_tree_brightness",
|
||||
{
|
||||
entity_id: "plant.lemon_tree",
|
||||
state: "ok",
|
||||
attributes: {
|
||||
problem: "none",
|
||||
sensors: {
|
||||
moisture: "sensor.lemon_tree_moisture",
|
||||
battery: "sensor.lemon_tree_battery",
|
||||
temperature: "sensor.lemon_tree_temperature",
|
||||
conductivity: "sensor.lemon_tree_conductivity",
|
||||
brightness: "sensor.lemon_tree_brightness",
|
||||
},
|
||||
unit_of_measurement_dict: {
|
||||
temperature: "°C",
|
||||
moisture: "%",
|
||||
brightness: "lx",
|
||||
battery: "%",
|
||||
conductivity: "μS/cm",
|
||||
},
|
||||
moisture: 54,
|
||||
battery: 95,
|
||||
temperature: 15.6,
|
||||
conductivity: 1,
|
||||
brightness: 12,
|
||||
max_brightness: 20,
|
||||
friendly_name: "Lemon Tree",
|
||||
},
|
||||
unit_of_measurement_dict: {
|
||||
temperature: "°C",
|
||||
moisture: "%",
|
||||
brightness: "lx",
|
||||
battery: "%",
|
||||
conductivity: "μS/cm",
|
||||
},
|
||||
{
|
||||
entity_id: "plant.apple_tree",
|
||||
state: "ok",
|
||||
attributes: {
|
||||
problem: "brightness",
|
||||
sensors: {
|
||||
moisture: "sensor.apple_tree_moisture",
|
||||
battery: "sensor.apple_tree_battery",
|
||||
temperature: "sensor.apple_tree_temperature",
|
||||
conductivity: "sensor.apple_tree_conductivity",
|
||||
brightness: "sensor.apple_tree_brightness",
|
||||
},
|
||||
unit_of_measurement_dict: {
|
||||
temperature: "°C",
|
||||
moisture: "%",
|
||||
brightness: "lx",
|
||||
battery: "%",
|
||||
conductivity: "μS/cm",
|
||||
},
|
||||
moisture: 54,
|
||||
battery: 2,
|
||||
temperature: 15.6,
|
||||
conductivity: 1,
|
||||
brightness: 25,
|
||||
max_brightness: 20,
|
||||
friendly_name: "Apple Tree",
|
||||
},
|
||||
moisture: 54,
|
||||
battery: 95,
|
||||
temperature: 15.6,
|
||||
conductivity: 1,
|
||||
brightness: 12,
|
||||
max_brightness: 20,
|
||||
friendly_name: "Lemon Tree",
|
||||
}),
|
||||
getEntity("plant", "apple_tree", "ok", {
|
||||
problem: "brightness",
|
||||
sensors: {
|
||||
moisture: "sensor.apple_tree_moisture",
|
||||
battery: "sensor.apple_tree_battery",
|
||||
temperature: "sensor.apple_tree_temperature",
|
||||
conductivity: "sensor.apple_tree_conductivity",
|
||||
brightness: "sensor.apple_tree_brightness",
|
||||
},
|
||||
{
|
||||
entity_id: "plant.sunflowers",
|
||||
state: "ok",
|
||||
attributes: {
|
||||
problem: "moisture, temperature, conductivity",
|
||||
sensors: {
|
||||
moisture: "sensor.sunflowers_moisture",
|
||||
temperature: "sensor.sunflowers_temperature",
|
||||
conductivity: "sensor.sunflowers_conductivity",
|
||||
brightness: "sensor.sunflowers_brightness",
|
||||
},
|
||||
unit_of_measurement_dict: {
|
||||
temperature: "°C",
|
||||
moisture: "%",
|
||||
brightness: "lx",
|
||||
conductivity: "μS/cm",
|
||||
},
|
||||
moisture: 54,
|
||||
temperature: 15.6,
|
||||
conductivity: 1,
|
||||
brightness: 25,
|
||||
entity_picture: "/images/sunflowers.jpg",
|
||||
},
|
||||
unit_of_measurement_dict: {
|
||||
temperature: "°C",
|
||||
moisture: "%",
|
||||
brightness: "lx",
|
||||
battery: "%",
|
||||
conductivity: "μS/cm",
|
||||
},
|
||||
moisture: 54,
|
||||
battery: 2,
|
||||
temperature: 15.6,
|
||||
conductivity: 1,
|
||||
brightness: 25,
|
||||
max_brightness: 20,
|
||||
friendly_name: "Apple Tree",
|
||||
}),
|
||||
getEntity("plant", "sunflowers", "ok", {
|
||||
problem: "moisture, temperature, conductivity",
|
||||
sensors: {
|
||||
moisture: "sensor.sunflowers_moisture",
|
||||
temperature: "sensor.sunflowers_temperature",
|
||||
conductivity: "sensor.sunflowers_conductivity",
|
||||
brightness: "sensor.sunflowers_brightness",
|
||||
},
|
||||
unit_of_measurement_dict: {
|
||||
temperature: "°C",
|
||||
moisture: "%",
|
||||
brightness: "lx",
|
||||
conductivity: "μS/cm",
|
||||
},
|
||||
moisture: 54,
|
||||
temperature: 15.6,
|
||||
conductivity: 1,
|
||||
brightness: 25,
|
||||
entity_picture: "/images/sunflowers.jpg",
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -5,17 +5,24 @@ import "../../../../src/components/ha-card";
|
||||
import "../../../../src/components/ha-yaml-editor";
|
||||
import type { Action } from "../../../../src/data/script";
|
||||
import { describeAction } from "../../../../src/data/script_i18n";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import type { HomeAssistant } from "../../../../src/types";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("scene", "kitchen_morning", "scening", {
|
||||
friendly_name: "Kitchen Morning",
|
||||
}),
|
||||
getEntity("media_player", "kitchen", "playing", {
|
||||
friendly_name: "Sonos Kitchen",
|
||||
}),
|
||||
{
|
||||
entity_id: "scene.kitchen_morning",
|
||||
state: "scening",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Morning",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.kitchen",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Sonos Kitchen",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const ACTIONS = [
|
||||
|
||||
@@ -5,20 +5,31 @@ import "../../../../src/components/ha-card";
|
||||
import "../../../../src/components/ha-yaml-editor";
|
||||
import type { Condition } from "../../../../src/data/automation";
|
||||
import { describeCondition } from "../../../../src/data/automation_i18n";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import type { HomeAssistant } from "../../../../src/types";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "kitchen", "on", {
|
||||
friendly_name: "Kitchen Light",
|
||||
}),
|
||||
getEntity("device_tracker", "person", "home", {
|
||||
friendly_name: "Person",
|
||||
}),
|
||||
getEntity("zone", "home", "", {
|
||||
friendly_name: "Home",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.kitchen",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.person",
|
||||
state: "home",
|
||||
attributes: {
|
||||
friendly_name: "Person",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "zone.home",
|
||||
state: "",
|
||||
attributes: {
|
||||
friendly_name: "Home",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const conditions: Condition[] = [
|
||||
|
||||
@@ -5,20 +5,31 @@ import "../../../../src/components/ha-card";
|
||||
import "../../../../src/components/ha-yaml-editor";
|
||||
import type { LegacyTrigger } from "../../../../src/data/automation";
|
||||
import { describeTrigger } from "../../../../src/data/automation_i18n";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import type { HomeAssistant } from "../../../../src/types";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "kitchen", "on", {
|
||||
friendly_name: "Kitchen Light",
|
||||
}),
|
||||
getEntity("person", "person", "", {
|
||||
friendly_name: "Person",
|
||||
}),
|
||||
getEntity("zone", "home", "", {
|
||||
friendly_name: "Home",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.kitchen",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "person.person",
|
||||
state: "",
|
||||
attributes: {
|
||||
friendly_name: "Person",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "zone.home",
|
||||
state: "",
|
||||
attributes: {
|
||||
friendly_name: "Home",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const triggers = [
|
||||
|
||||
@@ -12,34 +12,53 @@ import "../../../../src/components/ha-form/ha-form";
|
||||
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
|
||||
import type { AreaRegistryEntry } from "../../../../src/data/area/area_registry";
|
||||
import type { DeviceRegistryEntry } from "../../../../src/data/device/device_registry";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import type { HomeAssistant } from "../../../../src/types";
|
||||
import "../../components/demo-black-white-row";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
||||
friendly_name: "Alarm",
|
||||
}),
|
||||
getEntity("media_player", "livingroom", "playing", {
|
||||
friendly_name: "Livingroom",
|
||||
media_content_type: "music",
|
||||
device_class: "tv",
|
||||
}),
|
||||
getEntity("media_player", "lounge", "idle", {
|
||||
friendly_name: "Lounge",
|
||||
supported_features: 444983,
|
||||
device_class: "speaker",
|
||||
}),
|
||||
getEntity("light", "bedroom", "on", {
|
||||
friendly_name: "Bedroom",
|
||||
effect: "colorloop",
|
||||
effect_list: ["colorloop", "random"],
|
||||
}),
|
||||
getEntity("switch", "coffee", "off", {
|
||||
friendly_name: "Coffee",
|
||||
device_class: "switch",
|
||||
}),
|
||||
{
|
||||
entity_id: "alarm_control_panel.alarm",
|
||||
state: "disarmed",
|
||||
attributes: {
|
||||
friendly_name: "Alarm",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.livingroom",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Livingroom",
|
||||
media_content_type: "music",
|
||||
device_class: "tv",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.lounge",
|
||||
state: "idle",
|
||||
attributes: {
|
||||
friendly_name: "Lounge",
|
||||
supported_features: 444983,
|
||||
device_class: "speaker",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.bedroom",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bedroom",
|
||||
effect: "colorloop",
|
||||
effect_list: ["colorloop", "random"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "switch.coffee",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Coffee",
|
||||
device_class: "switch",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const DEVICES: DeviceRegistryEntry[] = [
|
||||
@@ -461,6 +480,12 @@ const SCHEMAS: {
|
||||
},
|
||||
{ type: "string", name: "path", default: "/" },
|
||||
{ type: "boolean", name: "ssl", default: false },
|
||||
{
|
||||
type: "string",
|
||||
name: "comments",
|
||||
default: "disabled field",
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: Input
|
||||
---
|
||||
|
||||
# Input `<ha-input>`
|
||||
|
||||
A text input component supporting Home Assistant theming and validation, based on webawesome input.
|
||||
Supports multiple input types including text, number, password, email, search, and more.
|
||||
|
||||
## Implementation
|
||||
|
||||
### Example usage
|
||||
|
||||
```html
|
||||
<ha-input label="Name" value="Hello"></ha-input>
|
||||
|
||||
<ha-input label="Email" type="email" placeholder="you@example.com"></ha-input>
|
||||
|
||||
<ha-input label="Password" type="password" password-toggle></ha-input>
|
||||
|
||||
<ha-input label="Required" required></ha-input>
|
||||
|
||||
<ha-input label="Disabled" disabled value="Can't touch this"></ha-input>
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
This component is based on the webawesome input component.
|
||||
|
||||
**Slots**
|
||||
|
||||
- `start`: Content placed before the input (usually for icons or prefixes).
|
||||
- `end`: Content placed after the input (usually for icons or suffixes).
|
||||
- `label`: Custom label content. Overrides the `label` property.
|
||||
- `hint`: Custom hint content. Overrides the `hint` property.
|
||||
- `clear-icon`: Custom clear icon.
|
||||
- `show-password-icon`: Custom show password icon.
|
||||
- `hide-password-icon`: Custom hide password icon.
|
||||
|
||||
**Properties/Attributes**
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| -------------------- | ---------------------------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| appearance | "material"/"outlined" | "material" | Sets the input appearance style. "material" is the default filled style, "outlined" uses a bordered style. |
|
||||
| type | "text"/"number"/"password"/"email"/"search"/"tel"/"url"/"date"/"datetime-local"/"time"/"color" | "text" | Sets the input type. |
|
||||
| value | String | - | The current value of the input. |
|
||||
| label | String | "" | The input's label text. |
|
||||
| hint | String | "" | The input's hint/helper text. |
|
||||
| placeholder | String | "" | Placeholder text shown when the input is empty. |
|
||||
| with-clear | Boolean | false | Adds a clear button when the input is not empty. |
|
||||
| readonly | Boolean | false | Makes the input readonly. |
|
||||
| disabled | Boolean | false | Disables the input and prevents user interaction. |
|
||||
| required | Boolean | false | Makes the input a required field. |
|
||||
| password-toggle | Boolean | false | Adds a button to toggle the password visibility. |
|
||||
| without-spin-buttons | Boolean | false | Hides the browser's built-in spin buttons for number inputs. |
|
||||
| auto-validate | Boolean | false | Validates the input on blur instead of on form submit. |
|
||||
| invalid | Boolean | false | Marks the input as invalid. |
|
||||
| inset-label | Boolean | false | Uses an inset label style where the label stays inside the input. |
|
||||
| validation-message | String | "" | Custom validation message shown when the input is invalid. |
|
||||
| pattern | String | - | A regular expression pattern to validate input against. |
|
||||
| minlength | Number | - | The minimum length of input that will be considered valid. |
|
||||
| maxlength | Number | - | The maximum length of input that will be considered valid. |
|
||||
| min | Number/String | - | The input's minimum value. Only applies to date and number input types. |
|
||||
| max | Number/String | - | The input's maximum value. Only applies to date and number input types. |
|
||||
| step | Number/"any" | - | Specifies the granularity that the value must adhere to. |
|
||||
|
||||
**CSS Custom Properties**
|
||||
|
||||
- `--ha-input-padding-top` - Padding above the input.
|
||||
- `--ha-input-padding-bottom` - Padding below the input. Defaults to `var(--ha-space-2)`.
|
||||
- `--ha-input-text-align` - Text alignment of the input. Defaults to `start`.
|
||||
- `--ha-input-required-marker` - The marker shown after the label for required fields. Defaults to `"*"`.
|
||||
|
||||
---
|
||||
|
||||
## Derivatives
|
||||
|
||||
The following components extend or wrap `ha-input` for specific use cases:
|
||||
|
||||
- **`<ha-input-search>`** — A pre-configured search input with a magnify icon, clear button, and localized "Search" placeholder. Extends `ha-input`.
|
||||
- **`<ha-input-copy>`** — A read-only input with a copy-to-clipboard button. Supports optional value masking with a reveal toggle.
|
||||
- **`<ha-input-multi>`** — A dynamic list of text inputs for managing arrays of strings. Supports adding, removing, and drag-and-drop reordering.
|
||||
@@ -0,0 +1,232 @@
|
||||
import { ContextProvider } from "@lit/context";
|
||||
import { mdiMagnify } from "@mdi/js";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { applyThemesOnElement } from "../../../../src/common/dom/apply_themes_on_element";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/components/ha-svg-icon";
|
||||
import "../../../../src/components/input/ha-input";
|
||||
import "../../../../src/components/input/ha-input-copy";
|
||||
import "../../../../src/components/input/ha-input-multi";
|
||||
import "../../../../src/components/input/ha-input-search";
|
||||
import { localizeContext } from "../../../../src/data/context";
|
||||
|
||||
const LOCALIZE_KEYS: Record<string, string> = {
|
||||
"ui.common.copy": "Copy",
|
||||
"ui.common.show": "Show",
|
||||
"ui.common.hide": "Hide",
|
||||
"ui.common.add": "Add",
|
||||
"ui.common.remove": "Remove",
|
||||
"ui.common.search": "Search",
|
||||
"ui.common.copied_clipboard": "Copied to clipboard",
|
||||
};
|
||||
|
||||
@customElement("demo-components-ha-input")
|
||||
export class DemoHaInput extends LitElement {
|
||||
constructor() {
|
||||
super();
|
||||
// Provides localizeContext for ha-input-copy, ha-input-multi and ha-input-search
|
||||
// eslint-disable-next-line no-new
|
||||
new ContextProvider(this, {
|
||||
context: localizeContext,
|
||||
initialValue: ((key: string) => LOCALIZE_KEYS[key] ?? key) as any,
|
||||
});
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
${["light", "dark"].map(
|
||||
(mode) => html`
|
||||
<div class=${mode}>
|
||||
<ha-card header="ha-input in ${mode}">
|
||||
<div class="card-content">
|
||||
<h3>Basic</h3>
|
||||
<div class="row">
|
||||
<ha-input label="Default"></ha-input>
|
||||
<ha-input label="With value" value="Hello"></ha-input>
|
||||
<ha-input
|
||||
label="With placeholder"
|
||||
placeholder="Type here..."
|
||||
></ha-input>
|
||||
</div>
|
||||
|
||||
<h3>Input types</h3>
|
||||
<div class="row">
|
||||
<ha-input label="Text" type="text" value="Text"></ha-input>
|
||||
<ha-input label="Number" type="number" value="42"></ha-input>
|
||||
<ha-input
|
||||
label="Email"
|
||||
type="email"
|
||||
placeholder="you@example.com"
|
||||
></ha-input>
|
||||
</div>
|
||||
<div class="row">
|
||||
<ha-input
|
||||
label="Password"
|
||||
type="password"
|
||||
value="secret"
|
||||
password-toggle
|
||||
></ha-input>
|
||||
<ha-input label="URL" type="url" placeholder="https://...">
|
||||
</ha-input>
|
||||
<ha-input label="Date" type="date"></ha-input>
|
||||
</div>
|
||||
|
||||
<h3>States</h3>
|
||||
<div class="row">
|
||||
<ha-input
|
||||
label="Disabled"
|
||||
disabled
|
||||
value="Disabled"
|
||||
></ha-input>
|
||||
<ha-input
|
||||
label="Readonly"
|
||||
readonly
|
||||
value="Readonly"
|
||||
></ha-input>
|
||||
<ha-input label="Required" required></ha-input>
|
||||
</div>
|
||||
<div class="row">
|
||||
<ha-input
|
||||
label="Invalid"
|
||||
invalid
|
||||
validation-message="This field is required"
|
||||
value=""
|
||||
></ha-input>
|
||||
<ha-input label="With hint" hint="This is a hint"></ha-input>
|
||||
<ha-input
|
||||
label="With clear"
|
||||
with-clear
|
||||
value="Clear me"
|
||||
></ha-input>
|
||||
</div>
|
||||
|
||||
<h3>With slots</h3>
|
||||
<div class="row">
|
||||
<ha-input label="With prefix">
|
||||
<span slot="start">$</span>
|
||||
</ha-input>
|
||||
<ha-input label="With suffix">
|
||||
<span slot="end">kg</span>
|
||||
</ha-input>
|
||||
<ha-input label="With icon">
|
||||
<ha-svg-icon .path=${mdiMagnify} slot="start"></ha-svg-icon>
|
||||
</ha-input>
|
||||
</div>
|
||||
|
||||
<h3>Appearance: outlined</h3>
|
||||
<div class="row">
|
||||
<ha-input
|
||||
appearance="outlined"
|
||||
label="Outlined"
|
||||
value="Hello"
|
||||
></ha-input>
|
||||
<ha-input
|
||||
appearance="outlined"
|
||||
label="Outlined disabled"
|
||||
disabled
|
||||
value="Disabled"
|
||||
></ha-input>
|
||||
<ha-input
|
||||
appearance="outlined"
|
||||
label="Outlined invalid"
|
||||
invalid
|
||||
validation-message="Required"
|
||||
></ha-input>
|
||||
</div>
|
||||
<div class="row">
|
||||
<ha-input
|
||||
appearance="outlined"
|
||||
placeholder="Placeholder only"
|
||||
></ha-input>
|
||||
</div>
|
||||
</div>
|
||||
</ha-card>
|
||||
|
||||
<ha-card header="Derivatives in ${mode}">
|
||||
<div class="card-content">
|
||||
<h3>ha-input-search</h3>
|
||||
<ha-input-search label="Search label"></ha-input-search>
|
||||
<ha-input-search appearance="outlined"></ha-input-search>
|
||||
|
||||
<h3>ha-input-copy</h3>
|
||||
<ha-input-copy
|
||||
value="my-api-token-123"
|
||||
masked-value="••••••••••••••••••"
|
||||
masked-toggle
|
||||
></ha-input-copy>
|
||||
|
||||
<h3>ha-input-multi</h3>
|
||||
<ha-input-multi
|
||||
label="URL"
|
||||
add-label="Add URL"
|
||||
.value=${["https://example.com"]}
|
||||
></ha-input-multi>
|
||||
</div>
|
||||
</ha-card>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
applyThemesOnElement(
|
||||
this.shadowRoot!.querySelector(".dark"),
|
||||
{
|
||||
default_theme: "default",
|
||||
default_dark_theme: "default",
|
||||
themes: {},
|
||||
darkMode: true,
|
||||
theme: "default",
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.dark,
|
||||
.light {
|
||||
display: block;
|
||||
background-color: var(--primary-background-color);
|
||||
padding: 0 50px;
|
||||
}
|
||||
ha-card {
|
||||
margin: 24px auto;
|
||||
}
|
||||
.card-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ha-space-2);
|
||||
}
|
||||
h3 {
|
||||
margin: var(--ha-space-4) 0 var(--ha-space-1) 0;
|
||||
font-size: var(--ha-font-size-l);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
}
|
||||
h3:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
gap: var(--ha-space-4);
|
||||
}
|
||||
.row > * {
|
||||
flex: 1;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-components-ha-input": DemoHaInput;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
|
||||
import { mockConfigEntries } from "../../../../demo/src/stubs/config_entries";
|
||||
@@ -8,6 +8,7 @@ import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
|
||||
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
|
||||
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
|
||||
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
|
||||
import type { HASSDomEvent } from "../../../../src/common/dom/fire_event";
|
||||
import "../../../../src/components/ha-formfield";
|
||||
import "../../../../src/components/ha-selector/ha-selector";
|
||||
import "../../../../src/components/ha-settings-row";
|
||||
@@ -16,33 +17,59 @@ import type { BlueprintInput } from "../../../../src/data/blueprint";
|
||||
import type { DeviceRegistryEntry } from "../../../../src/data/device/device_registry";
|
||||
import type { FloorRegistryEntry } from "../../../../src/data/floor_registry";
|
||||
import type { LabelRegistryEntry } from "../../../../src/data/label/label_registry";
|
||||
import { showDialog } from "../../../../src/dialogs/make-dialog-manager";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import {
|
||||
showDialog,
|
||||
type ShowDialogParams,
|
||||
} from "../../../../src/dialogs/make-dialog-manager";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import type { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
|
||||
import type { HomeAssistant } from "../../../../src/types";
|
||||
import "../../components/demo-black-white-row";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
||||
friendly_name: "Alarm",
|
||||
}),
|
||||
getEntity("media_player", "livingroom", "playing", {
|
||||
friendly_name: "Livingroom",
|
||||
}),
|
||||
getEntity("media_player", "lounge", "idle", {
|
||||
friendly_name: "Lounge",
|
||||
supported_features: 444983,
|
||||
}),
|
||||
getEntity("light", "bedroom", "on", {
|
||||
friendly_name: "Bedroom",
|
||||
}),
|
||||
getEntity("switch", "coffee", "off", {
|
||||
friendly_name: "Coffee",
|
||||
}),
|
||||
getEntity("number", "number", 5, {
|
||||
friendly_name: "Number",
|
||||
}),
|
||||
{
|
||||
entity_id: "alarm_control_panel.alarm",
|
||||
state: "disarmed",
|
||||
attributes: {
|
||||
friendly_name: "Alarm",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.livingroom",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Livingroom",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.lounge",
|
||||
state: "idle",
|
||||
attributes: {
|
||||
friendly_name: "Lounge",
|
||||
supported_features: 444983,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.bedroom",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bedroom",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "switch.coffee",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Coffee",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "number.number",
|
||||
state: "5",
|
||||
attributes: {
|
||||
friendly_name: "Number",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const DEVICES: DeviceRegistryEntry[] = [
|
||||
@@ -611,14 +638,15 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
||||
};
|
||||
};
|
||||
|
||||
private _dialogManager = (e) => {
|
||||
const { dialogTag, dialogImport, dialogParams, addHistory } = e.detail;
|
||||
private _dialogManager = (e: HASSDomEvent<ShowDialogParams<unknown>>) => {
|
||||
const { dialogTag, dialogImport, dialogParams, addHistory, parentElement } =
|
||||
e.detail;
|
||||
showDialog(
|
||||
this,
|
||||
this.shadowRoot!,
|
||||
dialogTag,
|
||||
dialogParams,
|
||||
dialogImport,
|
||||
parentElement,
|
||||
addHistory
|
||||
);
|
||||
};
|
||||
@@ -664,7 +692,11 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
||||
([key, value]) => html`
|
||||
<ha-settings-row narrow slot=${slot}>
|
||||
<span slot="heading">${value?.name || key}</span>
|
||||
<span slot="description">${value?.description}</span>
|
||||
${value?.description
|
||||
? html`<span slot="description"
|
||||
>${value?.description}</span
|
||||
>`
|
||||
: nothing}
|
||||
<ha-selector
|
||||
.hass=${this.hass}
|
||||
.selector=${value!.selector}
|
||||
|
||||
@@ -28,9 +28,12 @@ This element is based on webawesome `wa-tooltip` it only sets some css tokens an
|
||||
|
||||
In your theme settings use this without the prefixed `--`.
|
||||
|
||||
- `--ha-tooltip-border-radius` (Default: 4px)
|
||||
- `--ha-tooltip-arrow-size` (Default: 8px)
|
||||
- `--wa-tooltip-font-family` (Default: `var(--ha-font-family-body)`)
|
||||
- `--ha-tooltip-background-color` (Default: `var(--secondary-background-color)`)
|
||||
- `--ha-tooltip-text-color` (Default: `var(--primary-text-color)`)
|
||||
- `--ha-tooltip-font-family` (Default: `var(--ha-font-family-body)`)
|
||||
- `--ha-tooltip-font-size` (Default: `var(--ha-font-size-s)`)
|
||||
- `--wa-tooltip-font-weight` (Default: `var(--ha-font-weight-normal)`)
|
||||
- `--wa-tooltip-line-height` (Default: `var(--ha-line-height-condensed)`)
|
||||
- `--ha-tooltip-font-weight` (Default: `var(--ha-font-weight-normal)`)
|
||||
- `--ha-tooltip-line-height` (Default: `var(--ha-line-height-condensed)`)
|
||||
- `--ha-tooltip-padding` (Default: 8px)
|
||||
- `--ha-tooltip-border-radius` (Default: `var(--ha-border-radius-sm)`)
|
||||
- `--ha-tooltip-arrow-size` (Default: 8px)
|
||||
|
||||
@@ -19,7 +19,7 @@ The Home Assistant interface is based on Material Design. It's a design system c
|
||||
We want to make it as easy for designers to contribute as it is for developers. There’s a lot a designer can contribute to:
|
||||
|
||||
- Meet us at <a href="https://www.home-assistant.io/join-chat-design" rel="noopener noreferrer" target="_blank">Discord #designers channel</a>. If you can't see the channel, make sure you set the correct role in Channels & Roles.
|
||||
- Start designing with our <a href="https://www.figma.com/community/file/967153512097289521/Home-Assistant-DesignKit" rel="noopener noreferrer" target="_blank">Figma DesignKit</a>.
|
||||
- Start designing with our <a href="https://www.figma.com/design/2WGI8IDGyxINjSV6NRvPur/Home-Assistant-Design-Kit" rel="noopener noreferrer" target="_blank">Figma DesignKit</a>.
|
||||
- Find the latest UX <a href="https://github.com/home-assistant/frontend/discussions?discussions_q=label%3Aux" rel="noopener noreferrer" target="_blank">discussions</a> and <a href="https://github.com/home-assistant/frontend/labels/ux" rel="noopener noreferrer" target="_blank">issues</a> on GitHub. Everyone can start a new issue or discussion!
|
||||
|
||||
## Developers
|
||||
|
||||
@@ -1,25 +1,40 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
||||
friendly_name: "Alarm",
|
||||
}),
|
||||
getEntity("alarm_control_panel", "alarm_armed", "armed_home", {
|
||||
friendly_name: "Alarm",
|
||||
}),
|
||||
getEntity("alarm_control_panel", "unavailable", "unavailable", {
|
||||
friendly_name: "Alarm",
|
||||
}),
|
||||
getEntity("alarm_control_panel", "alarm_code", "disarmed", {
|
||||
friendly_name: "Alarm",
|
||||
code_format: "number",
|
||||
}),
|
||||
{
|
||||
entity_id: "alarm_control_panel.alarm",
|
||||
state: "disarmed",
|
||||
attributes: {
|
||||
friendly_name: "Alarm",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "alarm_control_panel.alarm_armed",
|
||||
state: "armed_home",
|
||||
attributes: {
|
||||
friendly_name: "Alarm",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "alarm_control_panel.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Alarm",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "alarm_control_panel.alarm_code",
|
||||
state: "disarmed",
|
||||
attributes: {
|
||||
friendly_name: "Alarm",
|
||||
code_format: "number",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,44 +1,79 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
getEntity("switch", "bed_ac", "on", {
|
||||
friendly_name: "Ecobee",
|
||||
}),
|
||||
getEntity("sensor", "bed_temp", "72", {
|
||||
friendly_name: "Bedroom Temp",
|
||||
device_class: "temperature",
|
||||
unit_of_measurement: "°F",
|
||||
}),
|
||||
getEntity("light", "living_room_light", "off", {
|
||||
friendly_name: "Living Room Light",
|
||||
}),
|
||||
getEntity("fan", "living_room", "on", {
|
||||
friendly_name: "Living Room Fan",
|
||||
}),
|
||||
getEntity("sensor", "office_humidity", "73", {
|
||||
friendly_name: "Office Humidity",
|
||||
device_class: "humidity",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
getEntity("light", "office", "on", {
|
||||
friendly_name: "Office Light",
|
||||
}),
|
||||
getEntity("fan", "kitchen", "on", {
|
||||
friendly_name: "Kitchen Fan",
|
||||
}),
|
||||
getEntity("binary_sensor", "kitchen_door", "on", {
|
||||
friendly_name: "Office Door",
|
||||
device_class: "door",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "switch.bed_ac",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Ecobee",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.bed_temp",
|
||||
state: "72",
|
||||
attributes: {
|
||||
friendly_name: "Bedroom Temp",
|
||||
device_class: "temperature",
|
||||
unit_of_measurement: "°F",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.living_room_light",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Living Room Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "fan.living_room",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Living Room Fan",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.office_humidity",
|
||||
state: "73",
|
||||
attributes: {
|
||||
friendly_name: "Office Humidity",
|
||||
device_class: "humidity",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.office",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Office Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "fan.kitchen",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Fan",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "binary_sensor.kitchen_door",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Office Door",
|
||||
device_class: "door",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// TODO: Update image here
|
||||
|
||||
@@ -1,24 +1,39 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "controller_1", "on", {
|
||||
friendly_name: "Controller 1",
|
||||
}),
|
||||
getEntity("light", "controller_2", "on", {
|
||||
friendly_name: "Controller 2",
|
||||
}),
|
||||
getEntity("light", "floor", "off", {
|
||||
friendly_name: "Floor light",
|
||||
}),
|
||||
getEntity("light", "kitchen", "on", {
|
||||
friendly_name: "Kitchen light",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.controller_1",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Controller 1",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.controller_2",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Controller 2",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.floor",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Floor light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.kitchen",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen light",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,150 +1,257 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
getEntity("group", "kitchen", "on", {
|
||||
entity_id: ["light.bed_light"],
|
||||
order: 8,
|
||||
friendly_name: "Kitchen Group",
|
||||
}),
|
||||
getEntity("lock", "kitchen_door", "locked", {
|
||||
friendly_name: "Kitchen Lock",
|
||||
}),
|
||||
getEntity("cover", "kitchen_window", "open", {
|
||||
friendly_name: "Kitchen Window",
|
||||
supported_features: 11,
|
||||
}),
|
||||
getEntity("scene", "romantic_lights", "scening", {
|
||||
entity_id: ["light.bed_light", "light.ceiling_lights"],
|
||||
friendly_name: "Romantic Scene",
|
||||
}),
|
||||
getEntity("device_tracker", "demo_paulus", "home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity("climate", "ecobee", "auto", {
|
||||
current_temperature: 73,
|
||||
min_temp: 45,
|
||||
max_temp: 95,
|
||||
temperature: null,
|
||||
target_temp_high: 75,
|
||||
target_temp_low: 70,
|
||||
fan_mode: "Auto Low",
|
||||
fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
operation_mode: "auto",
|
||||
operation_list: ["heat", "cool", "auto", "off"],
|
||||
hold_mode: "home",
|
||||
swing_mode: "Auto",
|
||||
swing_list: ["Auto", "1", "2", "3", "Off"],
|
||||
unit_of_measurement: "°F",
|
||||
friendly_name: "Ecobee",
|
||||
supported_features: 1014,
|
||||
}),
|
||||
getEntity("input_number", "number", 5, {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
mode: "slider",
|
||||
unit_of_measurement: "dB",
|
||||
friendly_name: "Number",
|
||||
icon: "mdi:bell-ring",
|
||||
}),
|
||||
getEntity("input_boolean", "toggle", "on", {
|
||||
friendly_name: "Toggle",
|
||||
}),
|
||||
getEntity("input_datetime", "date_and_time", "2022-01-10 00:00:00", {
|
||||
has_date: true,
|
||||
has_time: true,
|
||||
editable: true,
|
||||
year: 2022,
|
||||
month: 1,
|
||||
day: 10,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
timestamp: 1641801600,
|
||||
friendly_name: "Date and Time",
|
||||
}),
|
||||
getEntity("sensor", "humidity", "23.2", {
|
||||
friendly_name: "Humidity",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
getEntity("input_select", "dropdown", "Soda", {
|
||||
friendly_name: "Dropdown",
|
||||
options: ["Soda", "Beer", "Wine"],
|
||||
}),
|
||||
getEntity("input_text", "text", "Inspiration", {
|
||||
friendly_name: "Text",
|
||||
mode: "text",
|
||||
}),
|
||||
getEntity("timer", "timer", "idle", {
|
||||
friendly_name: "Timer",
|
||||
duration: "0:05:00",
|
||||
}),
|
||||
getEntity("counter", "counter", "3", {
|
||||
friendly_name: "Counter",
|
||||
initial: 0,
|
||||
step: 1,
|
||||
minimum: 0,
|
||||
maximum: 10,
|
||||
}),
|
||||
getEntity("text", "message", "Hello!", {
|
||||
friendly_name: "Message",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "group.kitchen",
|
||||
state: "on",
|
||||
attributes: {
|
||||
entity_id: ["light.bed_light"],
|
||||
order: 8,
|
||||
friendly_name: "Kitchen Group",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "lock.kitchen_door",
|
||||
state: "locked",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Lock",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.kitchen_window",
|
||||
state: "open",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Window",
|
||||
supported_features: 11,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "scene.romantic_lights",
|
||||
state: "scening",
|
||||
attributes: {
|
||||
entity_id: ["light.bed_light", "light.ceiling_lights"],
|
||||
friendly_name: "Romantic Scene",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.demo_paulus",
|
||||
state: "home",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Paulus",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.ecobee",
|
||||
state: "auto",
|
||||
attributes: {
|
||||
current_temperature: 73,
|
||||
min_temp: 45,
|
||||
max_temp: 95,
|
||||
temperature: null,
|
||||
target_temp_high: 75,
|
||||
target_temp_low: 70,
|
||||
fan_mode: "Auto Low",
|
||||
fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
operation_mode: "auto",
|
||||
operation_list: ["heat", "cool", "auto", "off"],
|
||||
hold_mode: "home",
|
||||
swing_mode: "Auto",
|
||||
swing_list: ["Auto", "1", "2", "3", "Off"],
|
||||
unit_of_measurement: "°F",
|
||||
friendly_name: "Ecobee",
|
||||
supported_features: 1014,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_number.number",
|
||||
state: "5",
|
||||
attributes: {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
mode: "slider",
|
||||
unit_of_measurement: "dB",
|
||||
friendly_name: "Number",
|
||||
icon: "mdi:bell-ring",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_boolean.toggle",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Toggle",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_datetime.date_and_time",
|
||||
state: "2022-01-10 00:00:00",
|
||||
attributes: {
|
||||
has_date: true,
|
||||
has_time: true,
|
||||
editable: true,
|
||||
year: 2022,
|
||||
month: 1,
|
||||
day: 10,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
timestamp: 1641801600,
|
||||
friendly_name: "Date and Time",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.humidity",
|
||||
state: "23.2",
|
||||
attributes: {
|
||||
friendly_name: "Humidity",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_select.dropdown",
|
||||
state: "Soda",
|
||||
attributes: {
|
||||
friendly_name: "Dropdown",
|
||||
options: ["Soda", "Beer", "Wine"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_text.text",
|
||||
state: "Inspiration",
|
||||
attributes: {
|
||||
friendly_name: "Text",
|
||||
mode: "text",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "timer.timer",
|
||||
state: "idle",
|
||||
attributes: {
|
||||
friendly_name: "Timer",
|
||||
duration: "0:05:00",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "counter.counter",
|
||||
state: "3",
|
||||
attributes: {
|
||||
friendly_name: "Counter",
|
||||
initial: 0,
|
||||
step: 1,
|
||||
minimum: 0,
|
||||
maximum: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "text.message",
|
||||
state: "Hello!",
|
||||
attributes: {
|
||||
friendly_name: "Message",
|
||||
},
|
||||
},
|
||||
|
||||
getEntity("light", "unavailable", "unavailable", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
getEntity("lock", "unavailable", "unavailable", {
|
||||
friendly_name: "Kitchen Door",
|
||||
}),
|
||||
getEntity("cover", "unavailable", "unavailable", {
|
||||
friendly_name: "Kitchen Window",
|
||||
supported_features: 11,
|
||||
}),
|
||||
getEntity("scene", "unavailable", "unavailable", {
|
||||
friendly_name: "Romantic Scene",
|
||||
}),
|
||||
getEntity("device_tracker", "unavailable", "unavailable", {
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity("climate", "unavailable", "unavailable", {
|
||||
unit_of_measurement: "°F",
|
||||
friendly_name: "Ecobee",
|
||||
supported_features: 1014,
|
||||
}),
|
||||
getEntity("input_number", "unavailable", "unavailable", {
|
||||
friendly_name: "Allowed Noise",
|
||||
icon: "mdi:bell-ring",
|
||||
}),
|
||||
getEntity("input_select", "unavailable", "unavailable", {
|
||||
unit_of_measurement: "dB",
|
||||
friendly_name: "Who cooks",
|
||||
icon: "mdi:cheff",
|
||||
}),
|
||||
getEntity("text", "unavailable", "unavailable", {
|
||||
friendly_name: "Message",
|
||||
}),
|
||||
getEntity("event", "unavailable", "unavailable", {
|
||||
friendly_name: "Empty remote",
|
||||
}),
|
||||
getEntity("event", "doorbell", "2023-07-17T21:26:11.615+00:00", {
|
||||
friendly_name: "Doorbell",
|
||||
device_class: "doorbell",
|
||||
event_type: "Ding-Dong",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "lock.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Door",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Window",
|
||||
supported_features: 11,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "scene.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Romantic Scene",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Paulus",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
unit_of_measurement: "°F",
|
||||
friendly_name: "Ecobee",
|
||||
supported_features: 1014,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_number.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Allowed Noise",
|
||||
icon: "mdi:bell-ring",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_select.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
unit_of_measurement: "dB",
|
||||
friendly_name: "Who cooks",
|
||||
icon: "mdi:cheff",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "text.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Message",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "event.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Empty remote",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "event.doorbell",
|
||||
state: "2023-07-17T21:26:11.615+00:00",
|
||||
attributes: {
|
||||
friendly_name: "Doorbell",
|
||||
device_class: "doorbell",
|
||||
event_type: "Ding-Dong",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,74 +1,117 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("device_tracker", "demo_paulus", "work", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 25,
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity("device_tracker", "demo_anne_therese", "school", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 50,
|
||||
friendly_name: "Anne Therese",
|
||||
}),
|
||||
getEntity("device_tracker", "demo_home_boy", "home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 75,
|
||||
friendly_name: "Home Boy",
|
||||
}),
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
getEntity("light", "kitchen_lights", "on", {
|
||||
friendly_name: "Kitchen Lights",
|
||||
}),
|
||||
getEntity("light", "ceiling_lights", "off", {
|
||||
friendly_name: "Ceiling Lights",
|
||||
}),
|
||||
getEntity("sensor", "battery_1", 20, {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery 1",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
getEntity("sensor", "battery_2", 35, {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery 2",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
getEntity("sensor", "battery_3", 40, {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery 3",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
getEntity("sensor", "battery_4", 80, {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery 4",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
getEntity("input_number", "min_battery_level", 30, {
|
||||
mode: "slider",
|
||||
step: 10,
|
||||
min: 0,
|
||||
max: 100,
|
||||
icon: "mdi:battery-alert-variant",
|
||||
friendly_name: "Minimum Battery Level",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
{
|
||||
entity_id: "device_tracker.demo_paulus",
|
||||
state: "work",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 25,
|
||||
friendly_name: "Paulus",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.demo_anne_therese",
|
||||
state: "school",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 50,
|
||||
friendly_name: "Anne Therese",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.demo_home_boy",
|
||||
state: "home",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 75,
|
||||
friendly_name: "Home Boy",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.kitchen_lights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.ceiling_lights",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Ceiling Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.battery_1",
|
||||
state: "20",
|
||||
attributes: {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery 1",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.battery_2",
|
||||
state: "35",
|
||||
attributes: {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery 2",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.battery_3",
|
||||
state: "40",
|
||||
attributes: {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery 3",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.battery_4",
|
||||
state: "80",
|
||||
attributes: {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery 4",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_number.min_battery_level",
|
||||
state: "30",
|
||||
attributes: {
|
||||
mode: "slider",
|
||||
step: 10,
|
||||
min: 0,
|
||||
max: 100,
|
||||
icon: "mdi:battery-alert-variant",
|
||||
friendly_name: "Minimum Battery Level",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("sensor", "brightness", "12", {}),
|
||||
getEntity("sensor", "brightness_medium", "53", {}),
|
||||
getEntity("sensor", "brightness_high", "87", {}),
|
||||
getEntity("plant", "bonsai", "ok", {}),
|
||||
getEntity("sensor", "not_working", "unavailable", {}),
|
||||
getEntity("sensor", "outside_humidity", "54", {
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
getEntity("sensor", "outside_temperature", "15.6", {
|
||||
unit_of_measurement: "°C",
|
||||
}),
|
||||
{ entity_id: "sensor.brightness", state: "12", attributes: {} },
|
||||
{ entity_id: "sensor.brightness_medium", state: "53", attributes: {} },
|
||||
{ entity_id: "sensor.brightness_high", state: "87", attributes: {} },
|
||||
{ entity_id: "plant.bonsai", state: "ok", attributes: {} },
|
||||
{ entity_id: "sensor.not_working", state: "unavailable", attributes: {} },
|
||||
{
|
||||
entity_id: "sensor.outside_humidity",
|
||||
state: "54",
|
||||
attributes: {
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.outside_temperature",
|
||||
state: "15.6",
|
||||
attributes: {
|
||||
unit_of_measurement: "°C",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
@@ -47,6 +54,19 @@ const CONFIGS = [
|
||||
needle: true
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Rendering needle and severity levels",
|
||||
config: `
|
||||
- type: gauge
|
||||
entity: sensor.brightness_high
|
||||
name: Brightness High
|
||||
needle: true
|
||||
severity:
|
||||
red: 75
|
||||
green: 0
|
||||
yellow: 50
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Setting severity levels",
|
||||
config: `
|
||||
@@ -114,6 +134,21 @@ const CONFIGS = [
|
||||
entity: sensor.not_working
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Lower minimum",
|
||||
config: `
|
||||
- type: gauge
|
||||
entity: sensor.brightness_high
|
||||
needle: true
|
||||
severity:
|
||||
green: 0
|
||||
yellow: 0.45
|
||||
red: 0.9
|
||||
min: -0.05
|
||||
name: " "
|
||||
max: 1.9
|
||||
unit: GBP/h`,
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-lovelace-gauge-card")
|
||||
|
||||
@@ -1,62 +1,89 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("device_tracker", "demo_paulus", "home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity("media_player", "living_room", "playing", {
|
||||
volume_level: 1,
|
||||
is_volume_muted: false,
|
||||
media_content_id: "eyU3bRy2x44",
|
||||
media_content_type: "movie",
|
||||
media_duration: 300,
|
||||
media_position: 45.017773,
|
||||
media_position_updated_at: "2018-07-19T10:44:45.919514+00:00",
|
||||
media_title: "♥♥ The Best Fireplace Video (3 hours)",
|
||||
app_name: "YouTube",
|
||||
sound_mode: "Dummy Music",
|
||||
sound_mode_list: ["Dummy Music", "Dummy Movie"],
|
||||
shuffle: false,
|
||||
friendly_name: "Living Room",
|
||||
entity_picture:
|
||||
"/api/media_player_proxy/media_player.living_room?token=e925f8db7f7bd1f317e4524dcb8333d60f6019219a3799a22604b5787f243567&cache=bc2ffb49c4f67034",
|
||||
supported_features: 115597,
|
||||
}),
|
||||
getEntity("sun", "sun", "below_horizon", {
|
||||
next_dawn: "2018-07-19T20:48:47+00:00",
|
||||
next_dusk: "2018-07-20T11:46:06+00:00",
|
||||
next_midnight: "2018-07-19T16:17:28+00:00",
|
||||
next_noon: "2018-07-20T04:17:26+00:00",
|
||||
next_rising: "2018-07-19T21:16:31+00:00",
|
||||
next_setting: "2018-07-20T11:18:22+00:00",
|
||||
elevation: 67.69,
|
||||
azimuth: 338.55,
|
||||
friendly_name: "Sun",
|
||||
}),
|
||||
getEntity("cover", "kitchen_window", "open", {
|
||||
friendly_name: "Kitchen Window",
|
||||
supported_features: 11,
|
||||
}),
|
||||
getEntity("light", "kitchen_lights", "on", {
|
||||
friendly_name: "Kitchen Lights",
|
||||
}),
|
||||
getEntity("light", "ceiling_lights", "off", {
|
||||
friendly_name: "Ceiling Lights",
|
||||
}),
|
||||
getEntity("lock", "kitchen_door", "locked", {
|
||||
friendly_name: "Kitchen Door",
|
||||
}),
|
||||
{
|
||||
entity_id: "device_tracker.demo_paulus",
|
||||
state: "home",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Paulus",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.living_room",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
volume_level: 1,
|
||||
is_volume_muted: false,
|
||||
media_content_id: "eyU3bRy2x44",
|
||||
media_content_type: "movie",
|
||||
media_duration: 300,
|
||||
media_position: 45.017773,
|
||||
media_position_updated_at: "2018-07-19T10:44:45.919514+00:00",
|
||||
media_title: "♥♥ The Best Fireplace Video (3 hours)",
|
||||
app_name: "YouTube",
|
||||
sound_mode: "Dummy Music",
|
||||
sound_mode_list: ["Dummy Music", "Dummy Movie"],
|
||||
shuffle: false,
|
||||
friendly_name: "Living Room",
|
||||
entity_picture:
|
||||
"/api/media_player_proxy/media_player.living_room?token=e925f8db7f7bd1f317e4524dcb8333d60f6019219a3799a22604b5787f243567&cache=bc2ffb49c4f67034",
|
||||
supported_features: 115597,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sun.sun",
|
||||
state: "below_horizon",
|
||||
attributes: {
|
||||
next_dawn: "2018-07-19T20:48:47+00:00",
|
||||
next_dusk: "2018-07-20T11:46:06+00:00",
|
||||
next_midnight: "2018-07-19T16:17:28+00:00",
|
||||
next_noon: "2018-07-20T04:17:26+00:00",
|
||||
next_rising: "2018-07-19T21:16:31+00:00",
|
||||
next_setting: "2018-07-20T11:18:22+00:00",
|
||||
elevation: 67.69,
|
||||
azimuth: 338.55,
|
||||
friendly_name: "Sun",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.kitchen_window",
|
||||
state: "open",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Window",
|
||||
supported_features: 11,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.kitchen_lights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.ceiling_lights",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Ceiling Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "lock.kitchen_door",
|
||||
state: "locked",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Door",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -2,46 +2,69 @@ import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "kitchen_lights", "on", {
|
||||
friendly_name: "Kitchen Lights",
|
||||
}),
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Lights",
|
||||
}),
|
||||
getEntity("device_tracker", "demo_paulus", "work", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity("device_tracker", "demo_anne_therese", "school", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Anne Therese",
|
||||
}),
|
||||
getEntity("device_tracker", "demo_home_boy", "home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Home Boy",
|
||||
}),
|
||||
getEntity("sensor", "illumination", "23", {
|
||||
friendly_name: "Illumination",
|
||||
unit_of_measurement: "lx",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.kitchen_lights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bed Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.demo_paulus",
|
||||
state: "work",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Paulus",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.demo_anne_therese",
|
||||
state: "school",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Anne Therese",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.demo_home_boy",
|
||||
state: "home",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Home Boy",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.illumination",
|
||||
state: "23",
|
||||
attributes: {
|
||||
friendly_name: "Illumination",
|
||||
unit_of_measurement: "lx",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,29 +1,44 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
brightness: 255,
|
||||
}),
|
||||
getEntity("light", "dim_on", "on", {
|
||||
friendly_name: "Dining Room",
|
||||
supported_features: 1,
|
||||
brightness: 100,
|
||||
}),
|
||||
getEntity("light", "dim_off", "off", {
|
||||
friendly_name: "Dining Room",
|
||||
supported_features: 1,
|
||||
}),
|
||||
getEntity("light", "unavailable", "unavailable", {
|
||||
friendly_name: "Lost Light",
|
||||
supported_features: 1,
|
||||
}),
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
brightness: 255,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.dim_on",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Dining Room",
|
||||
supported_features: 1,
|
||||
brightness: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.dim_off",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Dining Room",
|
||||
supported_features: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Lost Light",
|
||||
supported_features: 1,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,59 +1,86 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("device_tracker", "demo_paulus", "not_home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity("device_tracker", "demo_home_boy", "home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.87334,
|
||||
longitude: 117.22745,
|
||||
gps_accuracy: 20,
|
||||
battery: 53,
|
||||
friendly_name: "Home Boy",
|
||||
}),
|
||||
getEntity("zone", "home", "zoning", {
|
||||
latitude: 32.87354,
|
||||
longitude: 117.22765,
|
||||
radius: 100,
|
||||
friendly_name: "Home",
|
||||
icon: "mdi:home",
|
||||
}),
|
||||
getEntity("zone", "bushfire", "zoning", {
|
||||
latitude: -33.8611,
|
||||
longitude: 151.203,
|
||||
radius: 35000,
|
||||
friendly_name: "Bushfire Zone",
|
||||
icon: "mdi:home",
|
||||
}),
|
||||
getEntity("geo_location", "nelsons_creek", "15", {
|
||||
source: "bushfire_demo",
|
||||
latitude: -34.07792,
|
||||
longitude: 151.03219,
|
||||
friendly_name: "Nelsons Creek",
|
||||
}),
|
||||
getEntity("geo_location", "forest_rd_nowra_hill", "8", {
|
||||
source: "bushfire_demo",
|
||||
latitude: -33.69452,
|
||||
longitude: 151.19577,
|
||||
friendly_name: "Forest Rd, Nowra Hill",
|
||||
}),
|
||||
getEntity("geo_location", "stoney_ridge_rd_kremnos", "20", {
|
||||
source: "bushfire_demo",
|
||||
latitude: -33.66584,
|
||||
longitude: 150.97209,
|
||||
friendly_name: "Stoney Ridge Rd, Kremnos",
|
||||
}),
|
||||
{
|
||||
entity_id: "device_tracker.demo_paulus",
|
||||
state: "not_home",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: "Paulus",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "device_tracker.demo_home_boy",
|
||||
state: "home",
|
||||
attributes: {
|
||||
source_type: "gps",
|
||||
latitude: 32.87334,
|
||||
longitude: 117.22745,
|
||||
gps_accuracy: 20,
|
||||
battery: 53,
|
||||
friendly_name: "Home Boy",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "zone.home",
|
||||
state: "zoning",
|
||||
attributes: {
|
||||
latitude: 32.87354,
|
||||
longitude: 117.22765,
|
||||
radius: 100,
|
||||
friendly_name: "Home",
|
||||
icon: "mdi:home",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "zone.bushfire",
|
||||
state: "zoning",
|
||||
attributes: {
|
||||
latitude: -33.8611,
|
||||
longitude: 151.203,
|
||||
radius: 35000,
|
||||
friendly_name: "Bushfire Zone",
|
||||
icon: "mdi:home",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "geo_location.nelsons_creek",
|
||||
state: "15",
|
||||
attributes: {
|
||||
source: "bushfire_demo",
|
||||
latitude: -34.07792,
|
||||
longitude: 151.03219,
|
||||
friendly_name: "Nelsons Creek",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "geo_location.forest_rd_nowra_hill",
|
||||
state: "8",
|
||||
attributes: {
|
||||
source: "bushfire_demo",
|
||||
latitude: -33.69452,
|
||||
longitude: 151.19577,
|
||||
friendly_name: "Forest Rd, Nowra Hill",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "geo_location.stoney_ridge_rd_kremnos",
|
||||
state: "20",
|
||||
attributes: {
|
||||
source: "bushfire_demo",
|
||||
latitude: -33.66584,
|
||||
longitude: 150.97209,
|
||||
friendly_name: "Stoney Ridge Rd, Kremnos",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("person", "paulus", "home", {
|
||||
friendly_name: "Paulus",
|
||||
entity_picture: "/images/paulus.jpg",
|
||||
}),
|
||||
{
|
||||
entity_id: "person.paulus",
|
||||
state: "home",
|
||||
attributes: {
|
||||
friendly_name: "Paulus",
|
||||
entity_picture: "/images/paulus.jpg",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,40 +1,63 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
getEntity("group", "all_lights", "on", {
|
||||
entity_id: ["light.bed_light"],
|
||||
order: 8,
|
||||
friendly_name: "All Lights",
|
||||
}),
|
||||
getEntity("camera", "demo_camera", "idle", {
|
||||
access_token:
|
||||
"2f5bb163fb91cd8770a9494fa5e7eab172d8d34f4aba806eb6b59411b8c720b8",
|
||||
friendly_name: "Demo camera",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.demo_camera?token=2f5bb163fb91cd8770a9494fa5e7eab172d8d34f4aba806eb6b59411b8c720b8",
|
||||
}),
|
||||
getEntity("binary_sensor", "movement_backyard", "on", {
|
||||
friendly_name: "Movement Backyard",
|
||||
device_class: "motion",
|
||||
}),
|
||||
getEntity("person", "paulus", "home", {
|
||||
friendly_name: "Paulus",
|
||||
entity_picture: "/images/paulus.jpg",
|
||||
}),
|
||||
getEntity("sensor", "battery", 35, {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "group.all_lights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
entity_id: ["light.bed_light"],
|
||||
order: 8,
|
||||
friendly_name: "All Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "camera.demo_camera",
|
||||
state: "idle",
|
||||
attributes: {
|
||||
access_token:
|
||||
"2f5bb163fb91cd8770a9494fa5e7eab172d8d34f4aba806eb6b59411b8c720b8",
|
||||
friendly_name: "Demo camera",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.demo_camera?token=2f5bb163fb91cd8770a9494fa5e7eab172d8d34f4aba806eb6b59411b8c720b8",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "binary_sensor.movement_backyard",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Movement Backyard",
|
||||
device_class: "motion",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "person.paulus",
|
||||
state: "home",
|
||||
attributes: {
|
||||
friendly_name: "Paulus",
|
||||
entity_picture: "/images/paulus.jpg",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.battery",
|
||||
state: "35",
|
||||
attributes: {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "kitchen_lights", "on", {
|
||||
friendly_name: "Kitchen Lights",
|
||||
}),
|
||||
getEntity("light", "bed_light", "off", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
getEntity("person", "paulus", "home", {
|
||||
friendly_name: "Paulus",
|
||||
entity_picture: "/images/paulus.jpg",
|
||||
}),
|
||||
{
|
||||
entity_id: "light.kitchen_lights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "person.paulus",
|
||||
state: "home",
|
||||
attributes: {
|
||||
friendly_name: "Paulus",
|
||||
entity_picture: "/images/paulus.jpg",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,35 +1,58 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("switch", "decorative_lights", "on", {
|
||||
friendly_name: "Decorative Lights",
|
||||
}),
|
||||
getEntity("light", "ceiling_lights", "on", {
|
||||
friendly_name: "Ceiling Lights",
|
||||
}),
|
||||
getEntity("binary_sensor", "movement_backyard", "on", {
|
||||
friendly_name: "Movement Backyard",
|
||||
device_class: "moving",
|
||||
}),
|
||||
getEntity("binary_sensor", "basement_floor_wet", "off", {
|
||||
friendly_name: "Basement Floor Wet",
|
||||
device_class: "moisture",
|
||||
}),
|
||||
getEntity("person", "paulus", "home", {
|
||||
friendly_name: "Paulus",
|
||||
entity_picture: "/images/paulus.jpg",
|
||||
}),
|
||||
getEntity("sensor", "battery", 35, {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery",
|
||||
unit_of_measurement: "%",
|
||||
}),
|
||||
{
|
||||
entity_id: "switch.decorative_lights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Decorative Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.ceiling_lights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Ceiling Lights",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "binary_sensor.movement_backyard",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Movement Backyard",
|
||||
device_class: "moving",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "binary_sensor.basement_floor_wet",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Basement Floor Wet",
|
||||
device_class: "moisture",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "person.paulus",
|
||||
state: "home",
|
||||
attributes: {
|
||||
friendly_name: "Paulus",
|
||||
entity_picture: "/images/paulus.jpg",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "sensor.battery",
|
||||
state: "35",
|
||||
attributes: {
|
||||
device_class: "battery",
|
||||
friendly_name: "Battery",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -1,100 +1,123 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("climate", "ecobee", "auto", {
|
||||
current_temperature: 73,
|
||||
min_temp: 45,
|
||||
max_temp: 95,
|
||||
temperature: null,
|
||||
target_temp_high: 75,
|
||||
target_temp_low: 70,
|
||||
fan_mode: "Auto Low",
|
||||
fan_modes: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
swing_mode: "Auto",
|
||||
swing_modes: ["Auto", "1", "2", "3", "Off"],
|
||||
friendly_name: "Ecobee",
|
||||
supported_features: 59,
|
||||
preset_mode: "eco",
|
||||
preset_modes: ["away", "eco"],
|
||||
}),
|
||||
getEntity("climate", "nest", "heat", {
|
||||
current_temperature: 17,
|
||||
min_temp: 15,
|
||||
max_temp: 25,
|
||||
temperature: 19,
|
||||
fan_mode: "Auto Low",
|
||||
fan_modes: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
swing_mode: "Auto",
|
||||
swing_modes: ["Auto", "1", "2", "3", "Off"],
|
||||
friendly_name: "Nest",
|
||||
supported_features: 43,
|
||||
}),
|
||||
getEntity("climate", "overkiz_radiator", "heat", {
|
||||
current_temperature: 18,
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
temperature: 20,
|
||||
hvac_modes: ["heat", "auto", "off"],
|
||||
friendly_name: "Overkiz radiator",
|
||||
supported_features: 17,
|
||||
preset_mode: "comfort",
|
||||
preset_modes: [
|
||||
"none",
|
||||
"frost_protection",
|
||||
"eco",
|
||||
"comfort",
|
||||
"comfort-1",
|
||||
"comfort-2",
|
||||
"auto",
|
||||
"boost",
|
||||
"external",
|
||||
"prog",
|
||||
],
|
||||
}),
|
||||
getEntity("climate", "overkiz_towel_dryer", "heat", {
|
||||
current_temperature: null,
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
hvac_modes: ["heat", "off"],
|
||||
friendly_name: "Overkiz towel dryer",
|
||||
supported_features: 16,
|
||||
preset_mode: "eco",
|
||||
preset_modes: [
|
||||
"none",
|
||||
"frost_protection",
|
||||
"eco",
|
||||
"comfort",
|
||||
"comfort-1",
|
||||
"comfort-2",
|
||||
],
|
||||
}),
|
||||
getEntity("climate", "sensibo", "fan_only", {
|
||||
current_temperature: null,
|
||||
temperature: null,
|
||||
min_temp: 0,
|
||||
max_temp: 1,
|
||||
target_temp_step: 1,
|
||||
hvac_modes: ["fan_only", "off"],
|
||||
friendly_name: "Sensibo purifier",
|
||||
fan_modes: ["low", "high"],
|
||||
fan_mode: "low",
|
||||
swing_modes: ["both", "rangefull", "off"],
|
||||
swing_mode: "rangefull",
|
||||
swing_horizontal_modes: ["both", "rangefull", "off"],
|
||||
swing_horizontal_mode: "both",
|
||||
supported_features: 553,
|
||||
}),
|
||||
getEntity("climate", "unavailable", "unavailable", {
|
||||
supported_features: 43,
|
||||
}),
|
||||
{
|
||||
entity_id: "climate.ecobee",
|
||||
state: "auto",
|
||||
attributes: {
|
||||
current_temperature: 73,
|
||||
min_temp: 45,
|
||||
max_temp: 95,
|
||||
temperature: null,
|
||||
target_temp_high: 75,
|
||||
target_temp_low: 70,
|
||||
fan_mode: "Auto Low",
|
||||
fan_modes: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
swing_mode: "Auto",
|
||||
swing_modes: ["Auto", "1", "2", "3", "Off"],
|
||||
friendly_name: "Ecobee",
|
||||
supported_features: 59,
|
||||
preset_mode: "eco",
|
||||
preset_modes: ["away", "eco"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.nest",
|
||||
state: "heat",
|
||||
attributes: {
|
||||
current_temperature: 17,
|
||||
min_temp: 15,
|
||||
max_temp: 25,
|
||||
temperature: 19,
|
||||
fan_mode: "Auto Low",
|
||||
fan_modes: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
swing_mode: "Auto",
|
||||
swing_modes: ["Auto", "1", "2", "3", "Off"],
|
||||
friendly_name: "Nest",
|
||||
supported_features: 43,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.overkiz_radiator",
|
||||
state: "heat",
|
||||
attributes: {
|
||||
current_temperature: 18,
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
temperature: 20,
|
||||
hvac_modes: ["heat", "auto", "off"],
|
||||
friendly_name: "Overkiz radiator",
|
||||
supported_features: 17,
|
||||
preset_mode: "comfort",
|
||||
preset_modes: [
|
||||
"none",
|
||||
"frost_protection",
|
||||
"eco",
|
||||
"comfort",
|
||||
"comfort-1",
|
||||
"comfort-2",
|
||||
"auto",
|
||||
"boost",
|
||||
"external",
|
||||
"prog",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.overkiz_towel_dryer",
|
||||
state: "heat",
|
||||
attributes: {
|
||||
current_temperature: null,
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
hvac_modes: ["heat", "off"],
|
||||
friendly_name: "Overkiz towel dryer",
|
||||
supported_features: 16,
|
||||
preset_mode: "eco",
|
||||
preset_modes: [
|
||||
"none",
|
||||
"frost_protection",
|
||||
"eco",
|
||||
"comfort",
|
||||
"comfort-1",
|
||||
"comfort-2",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.sensibo",
|
||||
state: "fan_only",
|
||||
attributes: {
|
||||
current_temperature: null,
|
||||
temperature: null,
|
||||
min_temp: 0,
|
||||
max_temp: 1,
|
||||
target_temp_step: 1,
|
||||
hvac_modes: ["fan_only", "off"],
|
||||
friendly_name: "Sensibo purifier",
|
||||
fan_modes: ["low", "high"],
|
||||
fan_mode: "low",
|
||||
swing_modes: ["both", "rangefull", "off"],
|
||||
swing_mode: "rangefull",
|
||||
swing_horizontal_modes: ["both", "rangefull", "off"],
|
||||
swing_horizontal_mode: "both",
|
||||
supported_features: 553,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
supported_features: 43,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -6,7 +6,6 @@ import { LightColorMode } from "../../../../src/data/light";
|
||||
import { LockEntityFeature } from "../../../../src/data/lock";
|
||||
import { MediaPlayerEntityFeature } from "../../../../src/data/media-player";
|
||||
import { VacuumEntityFeature } from "../../../../src/data/vacuum";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
@@ -14,102 +13,154 @@ import { ClimateEntityFeature } from "../../../../src/data/climate";
|
||||
import { FanEntityFeature } from "../../../../src/data/fan";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("switch", "tv_outlet", "on", {
|
||||
friendly_name: "TV outlet",
|
||||
device_class: "outlet",
|
||||
}),
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
supported_color_modes: [LightColorMode.HS, LightColorMode.COLOR_TEMP],
|
||||
}),
|
||||
getEntity("light", "unavailable", "unavailable", {
|
||||
friendly_name: "Unavailable entity",
|
||||
}),
|
||||
getEntity("lock", "front_door", "locked", {
|
||||
friendly_name: "Front Door Lock",
|
||||
device_class: "lock",
|
||||
supported_features: LockEntityFeature.OPEN,
|
||||
}),
|
||||
getEntity("media_player", "living_room", "playing", {
|
||||
friendly_name: "Living room speaker",
|
||||
supported_features: MediaPlayerEntityFeature.VOLUME_SET,
|
||||
}),
|
||||
getEntity("climate", "thermostat", "heat", {
|
||||
current_temperature: 73,
|
||||
min_temp: 45,
|
||||
max_temp: 95,
|
||||
temperature: 80,
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
friendly_name: "Thermostat",
|
||||
hvac_action: "heating",
|
||||
}),
|
||||
getEntity("person", "paulus", "home", {
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity("vacuum", "first_floor_vacuum", "docked", {
|
||||
friendly_name: "First floor vacuum",
|
||||
supported_features:
|
||||
VacuumEntityFeature.START +
|
||||
VacuumEntityFeature.STOP +
|
||||
VacuumEntityFeature.RETURN_HOME,
|
||||
}),
|
||||
getEntity("cover", "kitchen_shutter", "open", {
|
||||
friendly_name: "Kitchen shutter",
|
||||
device_class: "shutter",
|
||||
supported_features:
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP,
|
||||
}),
|
||||
getEntity("cover", "pergola_roof", "open", {
|
||||
friendly_name: "Pergola Roof",
|
||||
supported_features:
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT,
|
||||
}),
|
||||
getEntity("input_number", "counter", "1.0", {
|
||||
friendly_name: "Counter",
|
||||
initial: 0,
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
mode: "slider",
|
||||
}),
|
||||
getEntity("climate", "dual_thermostat", "heat/cool", {
|
||||
friendly_name: "Dual thermostat",
|
||||
hvac_modes: ["off", "cool", "heat_cool", "auto", "dry", "fan_only"],
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
fan_modes: ["on_low", "on_high", "auto_low", "auto_high", "off"],
|
||||
preset_modes: ["home", "eco", "away"],
|
||||
swing_modes: ["auto", "1", "2", "3", "off"],
|
||||
switch_horizontal_modes: ["auto", "4", "5", "6", "off"],
|
||||
current_temperature: 23,
|
||||
target_temp_high: 24,
|
||||
target_temp_low: 21,
|
||||
fan_mode: "auto_low",
|
||||
preset_mode: "home",
|
||||
swing_mode: "auto",
|
||||
swing_horizontal_mode: "off",
|
||||
supported_features:
|
||||
ClimateEntityFeature.TURN_ON +
|
||||
ClimateEntityFeature.TURN_OFF +
|
||||
ClimateEntityFeature.SWING_MODE +
|
||||
ClimateEntityFeature.SWING_HORIZONTAL_MODE +
|
||||
ClimateEntityFeature.PRESET_MODE +
|
||||
ClimateEntityFeature.FAN_MODE +
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE,
|
||||
}),
|
||||
getEntity("fan", "fan_demo", "on", {
|
||||
friendly_name: "Ceiling fan",
|
||||
device_class: "fan",
|
||||
direction: "reverse",
|
||||
supported_features:
|
||||
FanEntityFeature.DIRECTION +
|
||||
FanEntityFeature.SET_SPEED +
|
||||
FanEntityFeature.OSCILLATE,
|
||||
}),
|
||||
{
|
||||
entity_id: "switch.tv_outlet",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "TV outlet",
|
||||
device_class: "outlet",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Bed Light",
|
||||
supported_color_modes: [LightColorMode.HS, LightColorMode.COLOR_TEMP],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Unavailable entity",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "lock.front_door",
|
||||
state: "locked",
|
||||
attributes: {
|
||||
friendly_name: "Front Door Lock",
|
||||
device_class: "lock",
|
||||
supported_features: LockEntityFeature.OPEN,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "media_player.living_room",
|
||||
state: "playing",
|
||||
attributes: {
|
||||
friendly_name: "Living room speaker",
|
||||
supported_features: MediaPlayerEntityFeature.VOLUME_SET,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.thermostat",
|
||||
state: "heat",
|
||||
attributes: {
|
||||
current_temperature: 73,
|
||||
min_temp: 45,
|
||||
max_temp: 95,
|
||||
temperature: 80,
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
friendly_name: "Thermostat",
|
||||
hvac_action: "heating",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "person.paulus",
|
||||
state: "home",
|
||||
attributes: {
|
||||
friendly_name: "Paulus",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "vacuum.first_floor_vacuum",
|
||||
state: "docked",
|
||||
attributes: {
|
||||
friendly_name: "First floor vacuum",
|
||||
supported_features:
|
||||
VacuumEntityFeature.START +
|
||||
VacuumEntityFeature.STOP +
|
||||
VacuumEntityFeature.RETURN_HOME,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.kitchen_shutter",
|
||||
state: "open",
|
||||
attributes: {
|
||||
friendly_name: "Kitchen shutter",
|
||||
device_class: "shutter",
|
||||
supported_features:
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.pergola_roof",
|
||||
state: "open",
|
||||
attributes: {
|
||||
friendly_name: "Pergola Roof",
|
||||
supported_features:
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_number.counter",
|
||||
state: "1.0",
|
||||
attributes: {
|
||||
friendly_name: "Counter",
|
||||
initial: 0,
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
mode: "slider",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.dual_thermostat",
|
||||
state: "heat/cool",
|
||||
attributes: {
|
||||
friendly_name: "Dual thermostat",
|
||||
hvac_modes: ["off", "cool", "heat_cool", "auto", "dry", "fan_only"],
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
fan_modes: ["on_low", "on_high", "auto_low", "auto_high", "off"],
|
||||
preset_modes: ["home", "eco", "away"],
|
||||
swing_modes: ["auto", "1", "2", "3", "off"],
|
||||
switch_horizontal_modes: ["auto", "4", "5", "6", "off"],
|
||||
current_temperature: 23,
|
||||
target_temp_high: 24,
|
||||
target_temp_low: 21,
|
||||
fan_mode: "auto_low",
|
||||
preset_mode: "home",
|
||||
swing_mode: "auto",
|
||||
swing_horizontal_mode: "off",
|
||||
supported_features:
|
||||
ClimateEntityFeature.TURN_ON +
|
||||
ClimateEntityFeature.TURN_OFF +
|
||||
ClimateEntityFeature.SWING_MODE +
|
||||
ClimateEntityFeature.SWING_HORIZONTAL_MODE +
|
||||
ClimateEntityFeature.PRESET_MODE +
|
||||
ClimateEntityFeature.FAN_MODE +
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "fan.fan_demo",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Ceiling fan",
|
||||
device_class: "fan",
|
||||
direction: "reverse",
|
||||
supported_features:
|
||||
FanEntityFeature.DIRECTION +
|
||||
FanEntityFeature.SET_SPEED +
|
||||
FanEntityFeature.OSCILLATE,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -3,18 +3,25 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
import { mockTodo } from "../../../../demo/src/stubs/todo";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("todo", "shopping_list", "2", {
|
||||
friendly_name: "Shopping List",
|
||||
supported_features: 15,
|
||||
}),
|
||||
getEntity("todo", "read_only", "2", {
|
||||
friendly_name: "Read only",
|
||||
}),
|
||||
{
|
||||
entity_id: "todo.shopping_list",
|
||||
state: "2",
|
||||
attributes: {
|
||||
friendly_name: "Shopping List",
|
||||
supported_features: 15,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "todo.read_only",
|
||||
state: "2",
|
||||
attributes: {
|
||||
friendly_name: "Read only",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
|
||||
@@ -422,7 +422,6 @@ export class DemoEntityState extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-data-table
|
||||
.hass=${this.hass}
|
||||
.columns=${this._columns(this.hass)}
|
||||
.data=${this._rows()}
|
||||
auto-height
|
||||
|
||||
@@ -3,108 +3,135 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
import { ClimateEntityFeature } from "../../../../src/data/climate";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("climate", "radiator", "heat", {
|
||||
friendly_name: "Basic heater",
|
||||
hvac_modes: ["heat", "off"],
|
||||
hvac_mode: "heat",
|
||||
current_temperature: 18,
|
||||
temperature: 20,
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
supported_features: ClimateEntityFeature.TARGET_TEMPERATURE,
|
||||
}),
|
||||
getEntity("climate", "ac", "cool", {
|
||||
friendly_name: "Basic air conditioning",
|
||||
hvac_modes: ["cool", "off"],
|
||||
hvac_mode: "cool",
|
||||
current_temperature: 18,
|
||||
temperature: 20,
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
supported_features: ClimateEntityFeature.TARGET_TEMPERATURE,
|
||||
}),
|
||||
getEntity("climate", "fan", "fan_only", {
|
||||
friendly_name: "Basic fan",
|
||||
hvac_modes: ["fan_only", "off"],
|
||||
hvac_mode: "fan_only",
|
||||
fan_modes: ["low", "high"],
|
||||
fan_mode: "low",
|
||||
current_temperature: null,
|
||||
temperature: null,
|
||||
min_temp: 0,
|
||||
max_temp: 1,
|
||||
target_temp_step: 1,
|
||||
supported_features:
|
||||
// eslint-disable-next-line no-bitwise
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE,
|
||||
}),
|
||||
getEntity("climate", "hvac", "auto", {
|
||||
friendly_name: "Basic hvac",
|
||||
hvac_modes: ["auto", "off"],
|
||||
hvac_mode: "auto",
|
||||
current_temperature: 18,
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
target_temp_step: 1,
|
||||
supported_features: ClimateEntityFeature.TARGET_TEMPERATURE_RANGE,
|
||||
target_temp_low: 20,
|
||||
target_temp_high: 25,
|
||||
}),
|
||||
getEntity("climate", "advanced", "auto", {
|
||||
friendly_name: "Advanced hvac",
|
||||
supported_features:
|
||||
// eslint-disable-next-line no-bitwise
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE |
|
||||
ClimateEntityFeature.TARGET_HUMIDITY |
|
||||
ClimateEntityFeature.PRESET_MODE,
|
||||
hvac_modes: ["auto", "off"],
|
||||
hvac_mode: "auto",
|
||||
preset_modes: ["eco", "comfort", "boost"],
|
||||
preset_mode: "eco",
|
||||
current_temperature: 18,
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
target_temp_step: 1,
|
||||
target_temp_low: 20,
|
||||
target_temp_high: 25,
|
||||
current_humidity: 40,
|
||||
min_humidity: 0,
|
||||
max_humidity: 100,
|
||||
humidity: 50,
|
||||
}),
|
||||
getEntity("climate", "towel_dryer", "heat", {
|
||||
friendly_name: "Preset only heater",
|
||||
hvac_modes: ["heat", "off"],
|
||||
hvac_mode: "heat",
|
||||
preset_modes: [
|
||||
"none",
|
||||
"frost_protection",
|
||||
"eco",
|
||||
"comfort",
|
||||
"comfort-1",
|
||||
"comfort-2",
|
||||
],
|
||||
preset_mode: "eco",
|
||||
current_temperature: null,
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
supported_features: ClimateEntityFeature.PRESET_MODE,
|
||||
}),
|
||||
getEntity("climate", "unavailable", "unavailable", {
|
||||
friendly_name: "Unavailable heater",
|
||||
hvac_modes: ["heat", "off"],
|
||||
hvac_mode: "heat",
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
supported_features: ClimateEntityFeature.TARGET_TEMPERATURE,
|
||||
}),
|
||||
{
|
||||
entity_id: "climate.radiator",
|
||||
state: "heat",
|
||||
attributes: {
|
||||
friendly_name: "Basic heater",
|
||||
hvac_modes: ["heat", "off"],
|
||||
hvac_mode: "heat",
|
||||
current_temperature: 18,
|
||||
temperature: 20,
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
supported_features: ClimateEntityFeature.TARGET_TEMPERATURE,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.ac",
|
||||
state: "cool",
|
||||
attributes: {
|
||||
friendly_name: "Basic air conditioning",
|
||||
hvac_modes: ["cool", "off"],
|
||||
hvac_mode: "cool",
|
||||
current_temperature: 18,
|
||||
temperature: 20,
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
supported_features: ClimateEntityFeature.TARGET_TEMPERATURE,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.fan",
|
||||
state: "fan_only",
|
||||
attributes: {
|
||||
friendly_name: "Basic fan",
|
||||
hvac_modes: ["fan_only", "off"],
|
||||
hvac_mode: "fan_only",
|
||||
fan_modes: ["low", "high"],
|
||||
fan_mode: "low",
|
||||
current_temperature: null,
|
||||
temperature: null,
|
||||
min_temp: 0,
|
||||
max_temp: 1,
|
||||
target_temp_step: 1,
|
||||
supported_features:
|
||||
// eslint-disable-next-line no-bitwise
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.hvac",
|
||||
state: "auto",
|
||||
attributes: {
|
||||
friendly_name: "Basic hvac",
|
||||
hvac_modes: ["auto", "off"],
|
||||
hvac_mode: "auto",
|
||||
current_temperature: 18,
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
target_temp_step: 1,
|
||||
supported_features: ClimateEntityFeature.TARGET_TEMPERATURE_RANGE,
|
||||
target_temp_low: 20,
|
||||
target_temp_high: 25,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.advanced",
|
||||
state: "auto",
|
||||
attributes: {
|
||||
friendly_name: "Advanced hvac",
|
||||
supported_features:
|
||||
// eslint-disable-next-line no-bitwise
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE |
|
||||
ClimateEntityFeature.TARGET_HUMIDITY |
|
||||
ClimateEntityFeature.PRESET_MODE,
|
||||
hvac_modes: ["auto", "off"],
|
||||
hvac_mode: "auto",
|
||||
preset_modes: ["eco", "comfort", "boost"],
|
||||
preset_mode: "eco",
|
||||
current_temperature: 18,
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
target_temp_step: 1,
|
||||
target_temp_low: 20,
|
||||
target_temp_high: 25,
|
||||
current_humidity: 40,
|
||||
min_humidity: 0,
|
||||
max_humidity: 100,
|
||||
humidity: 50,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.towel_dryer",
|
||||
state: "heat",
|
||||
attributes: {
|
||||
friendly_name: "Preset only heater",
|
||||
hvac_modes: ["heat", "off"],
|
||||
hvac_mode: "heat",
|
||||
preset_modes: [
|
||||
"none",
|
||||
"frost_protection",
|
||||
"eco",
|
||||
"comfort",
|
||||
"comfort-1",
|
||||
"comfort-2",
|
||||
],
|
||||
preset_mode: "eco",
|
||||
current_temperature: null,
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
supported_features: ClimateEntityFeature.PRESET_MODE,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "climate.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Unavailable heater",
|
||||
hvac_modes: ["heat", "off"],
|
||||
hvac_mode: "heat",
|
||||
min_temp: 10,
|
||||
max_temp: 30,
|
||||
supported_features: ClimateEntityFeature.TARGET_TEMPERATURE,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-climate")
|
||||
@@ -117,7 +144,7 @@ class DemoMoreInfoClimate extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -4,138 +4,189 @@ import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import { CoverEntityFeature } from "../../../../src/data/cover";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("cover", "position_buttons", "on", {
|
||||
friendly_name: "Position Buttons",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE,
|
||||
}),
|
||||
getEntity("cover", "position_slider_half", "on", {
|
||||
friendly_name: "Position Half-Open",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION,
|
||||
current_position: 50,
|
||||
}),
|
||||
getEntity("cover", "position_slider_open", "on", {
|
||||
friendly_name: "Position Open",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION,
|
||||
current_position: 100,
|
||||
}),
|
||||
getEntity("cover", "position_slider_closed", "on", {
|
||||
friendly_name: "Position Closed",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION,
|
||||
current_position: 0,
|
||||
}),
|
||||
getEntity("cover", "tilt_buttons", "on", {
|
||||
friendly_name: "Tilt Buttons",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_half", "on", {
|
||||
friendly_name: "Tilt Half-Open",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_tilt_position: 50,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_open", "on", {
|
||||
friendly_name: "Tilt Open",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_tilt_position: 100,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_closed", "on", {
|
||||
friendly_name: "Tilt Closed",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_tilt_position: 0,
|
||||
}),
|
||||
getEntity("cover", "position_slider_tilt_slider", "on", {
|
||||
friendly_name: "Both Sliders",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_position: 30,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
getEntity("cover", "position_tilt_slider", "on", {
|
||||
friendly_name: "Position & Tilt Slider",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
getEntity("cover", "position_slider_tilt", "on", {
|
||||
friendly_name: "Position Slider & Tilt",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT,
|
||||
current_position: 30,
|
||||
}),
|
||||
getEntity("cover", "position_slider_only_tilt_slider", "on", {
|
||||
friendly_name: "Position Slider Only & Tilt Buttons",
|
||||
supported_features:
|
||||
CoverEntityFeature.SET_POSITION +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT,
|
||||
current_position: 30,
|
||||
}),
|
||||
getEntity("cover", "position_slider_only_tilt", "on", {
|
||||
friendly_name: "Position Slider Only & Tilt",
|
||||
supported_features:
|
||||
CoverEntityFeature.SET_POSITION +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_position: 30,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
{
|
||||
entity_id: "cover.position_buttons",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Position Buttons",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.position_slider_half",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Position Half-Open",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION,
|
||||
current_position: 50,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.position_slider_open",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Position Open",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION,
|
||||
current_position: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.position_slider_closed",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Position Closed",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION,
|
||||
current_position: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.tilt_buttons",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Tilt Buttons",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.tilt_slider_half",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Tilt Half-Open",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_tilt_position: 50,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.tilt_slider_open",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Tilt Open",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_tilt_position: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.tilt_slider_closed",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Tilt Closed",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_tilt_position: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.position_slider_tilt_slider",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Both Sliders",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_position: 30,
|
||||
current_tilt_position: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.position_tilt_slider",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Position & Tilt Slider",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_tilt_position: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.position_slider_tilt",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Position Slider & Tilt",
|
||||
supported_features:
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP +
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.SET_POSITION +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT,
|
||||
current_position: 30,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.position_slider_only_tilt_slider",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Position Slider Only & Tilt Buttons",
|
||||
supported_features:
|
||||
CoverEntityFeature.SET_POSITION +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT,
|
||||
current_position: 30,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "cover.position_slider_only_tilt",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Position Slider Only & Tilt",
|
||||
supported_features:
|
||||
CoverEntityFeature.SET_POSITION +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT +
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.SET_TILT_POSITION,
|
||||
current_position: 30,
|
||||
current_tilt_position: 70,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-cover")
|
||||
@@ -148,7 +199,7 @@ class DemoMoreInfoCover extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,21 +3,24 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
import { FanEntityFeature } from "../../../../src/data/fan";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("fan", "fan", "on", {
|
||||
friendly_name: "Fan",
|
||||
device_class: "fan",
|
||||
supported_features:
|
||||
FanEntityFeature.OSCILLATE +
|
||||
FanEntityFeature.DIRECTION +
|
||||
FanEntityFeature.SET_SPEED,
|
||||
}),
|
||||
{
|
||||
entity_id: "fan.fan",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Fan",
|
||||
device_class: "fan",
|
||||
supported_features:
|
||||
FanEntityFeature.OSCILLATE +
|
||||
FanEntityFeature.DIRECTION +
|
||||
FanEntityFeature.SET_SPEED,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-fan")
|
||||
@@ -30,7 +33,7 @@ class DemoMoreInfoFan extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,27 +3,38 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("humidifier", "humidifier", "on", {
|
||||
friendly_name: "Humidifier",
|
||||
device_class: "humidifier",
|
||||
current_humidity: 50,
|
||||
humidity: 30,
|
||||
}),
|
||||
getEntity("humidifier", "dehumidifier", "on", {
|
||||
friendly_name: "Dehumidifier",
|
||||
device_class: "dehumidifier",
|
||||
current_humidity: 50,
|
||||
humidity: 30,
|
||||
}),
|
||||
getEntity("humidifier", "unavailable", "unavailable", {
|
||||
friendly_name: "Unavailable humidifier",
|
||||
}),
|
||||
{
|
||||
entity_id: "humidifier.humidifier",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Humidifier",
|
||||
device_class: "humidifier",
|
||||
current_humidity: 50,
|
||||
humidity: 30,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "humidifier.dehumidifier",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Dehumidifier",
|
||||
device_class: "dehumidifier",
|
||||
current_humidity: 50,
|
||||
humidity: 30,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "humidifier.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Unavailable humidifier",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-humidifier")
|
||||
@@ -36,7 +47,7 @@ class DemoMoreInfoHumidifier extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,30 +3,37 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("input_number", "box1", 0, {
|
||||
friendly_name: "Box1",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "box",
|
||||
unit_of_measurement: "items",
|
||||
}),
|
||||
getEntity("input_number", "slider1", 0, {
|
||||
friendly_name: "Slider1",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "slider",
|
||||
unit_of_measurement: "items",
|
||||
}),
|
||||
{
|
||||
entity_id: "input_number.box1",
|
||||
state: "0",
|
||||
attributes: {
|
||||
friendly_name: "Box1",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "box",
|
||||
unit_of_measurement: "items",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "input_number.slider1",
|
||||
state: "0",
|
||||
attributes: {
|
||||
friendly_name: "Slider1",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "slider",
|
||||
unit_of_measurement: "items",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-input-number")
|
||||
@@ -39,7 +46,7 @@ class DemoMoreInfoInputNumber extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,19 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("input_text", "text", "Inspiration", {
|
||||
friendly_name: "Text",
|
||||
mode: "text",
|
||||
}),
|
||||
{
|
||||
entity_id: "input_text.text",
|
||||
state: "Inspiration",
|
||||
attributes: {
|
||||
friendly_name: "Text",
|
||||
mode: "text",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-input-text")
|
||||
@@ -25,7 +28,7 @@ class DemoMoreInfoInputText extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -4,137 +4,172 @@ import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import { LightColorMode, LightEntityFeature } from "../../../../src/data/light";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Basic Light",
|
||||
}),
|
||||
getEntity("light", "kitchen_light", "on", {
|
||||
friendly_name: "Brightness Light",
|
||||
brightness: 200,
|
||||
supported_color_modes: [LightColorMode.BRIGHTNESS],
|
||||
color_mode: LightColorMode.BRIGHTNESS,
|
||||
}),
|
||||
getEntity("light", "color_temperature_light", "on", {
|
||||
friendly_name: "White Color Temperature Light",
|
||||
brightness: 128,
|
||||
color_temp: 75,
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
],
|
||||
color_mode: LightColorMode.COLOR_TEMP,
|
||||
}),
|
||||
getEntity("light", "color_hs_light", "on", {
|
||||
friendly_name: "Color HS Light",
|
||||
brightness: 255,
|
||||
hs_color: [30, 100],
|
||||
rgb_color: [30, 100, 255],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.HS,
|
||||
],
|
||||
color_mode: LightColorMode.HS,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_rgb_ct_light", "on", {
|
||||
friendly_name: "Color RGB + CT Light",
|
||||
brightness: 255,
|
||||
color_temp: 75,
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.RGB,
|
||||
],
|
||||
color_mode: LightColorMode.COLOR_TEMP,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_RGB_light", "on", {
|
||||
friendly_name: "Color Effects Light",
|
||||
brightness: 255,
|
||||
rgb_color: [30, 100, 255],
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [LightColorMode.BRIGHTNESS, LightColorMode.RGB],
|
||||
color_mode: LightColorMode.RGB,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_rgbw_light", "on", {
|
||||
friendly_name: "Color RGBW Light",
|
||||
brightness: 255,
|
||||
rgbw_color: [30, 100, 255, 125],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.RGBW,
|
||||
],
|
||||
color_mode: LightColorMode.RGBW,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_rgbww_light", "on", {
|
||||
friendly_name: "Color RGBWW Light",
|
||||
brightness: 255,
|
||||
rgbww_color: [30, 100, 255, 125, 10],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.RGBWW,
|
||||
],
|
||||
color_mode: LightColorMode.RGBWW,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_xy_light", "on", {
|
||||
friendly_name: "Color XY Light",
|
||||
brightness: 255,
|
||||
xy_color: [30, 100],
|
||||
rgb_color: [30, 100, 255],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.XY,
|
||||
],
|
||||
color_mode: LightColorMode.XY,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
{
|
||||
entity_id: "light.bed_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Basic Light",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.kitchen_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Brightness Light",
|
||||
brightness: 200,
|
||||
supported_color_modes: [LightColorMode.BRIGHTNESS],
|
||||
color_mode: LightColorMode.BRIGHTNESS,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.color_temperature_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "White Color Temperature Light",
|
||||
brightness: 128,
|
||||
color_temp: 75,
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
],
|
||||
color_mode: LightColorMode.COLOR_TEMP,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.color_hs_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Color HS Light",
|
||||
brightness: 255,
|
||||
hs_color: [30, 100],
|
||||
rgb_color: [30, 100, 255],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.HS,
|
||||
],
|
||||
color_mode: LightColorMode.HS,
|
||||
effect_list: ["random", "colorloop"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.color_rgb_ct_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Color RGB + CT Light",
|
||||
brightness: 255,
|
||||
color_temp: 75,
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.RGB,
|
||||
],
|
||||
color_mode: LightColorMode.COLOR_TEMP,
|
||||
effect_list: ["random", "colorloop"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.color_RGB_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Color Effects Light",
|
||||
brightness: 255,
|
||||
rgb_color: [30, 100, 255],
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [LightColorMode.BRIGHTNESS, LightColorMode.RGB],
|
||||
color_mode: LightColorMode.RGB,
|
||||
effect_list: ["random", "colorloop"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.color_rgbw_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Color RGBW Light",
|
||||
brightness: 255,
|
||||
rgbw_color: [30, 100, 255, 125],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.RGBW,
|
||||
],
|
||||
color_mode: LightColorMode.RGBW,
|
||||
effect_list: ["random", "colorloop"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.color_rgbww_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Color RGBWW Light",
|
||||
brightness: 255,
|
||||
rgbww_color: [30, 100, 255, 125, 10],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.RGBWW,
|
||||
],
|
||||
color_mode: LightColorMode.RGBWW,
|
||||
effect_list: ["random", "colorloop"],
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "light.color_xy_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Color XY Light",
|
||||
brightness: 255,
|
||||
xy_color: [30, 100],
|
||||
rgb_color: [30, 100, 255],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features:
|
||||
LightEntityFeature.EFFECT +
|
||||
LightEntityFeature.FLASH +
|
||||
LightEntityFeature.TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorMode.BRIGHTNESS,
|
||||
LightColorMode.COLOR_TEMP,
|
||||
LightColorMode.XY,
|
||||
],
|
||||
color_mode: LightColorMode.XY,
|
||||
effect_list: ["random", "colorloop"],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-light")
|
||||
@@ -147,7 +182,7 @@ class DemoMoreInfoLight extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,19 +3,26 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("lock", "lock", "locked", {
|
||||
friendly_name: "Lock",
|
||||
device_class: "lock",
|
||||
}),
|
||||
getEntity("lock", "unavailable", "unavailable", {
|
||||
friendly_name: "Unavailable lock",
|
||||
}),
|
||||
{
|
||||
entity_id: "lock.lock",
|
||||
state: "locked",
|
||||
attributes: {
|
||||
friendly_name: "Lock",
|
||||
device_class: "lock",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "lock.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Unavailable lock",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-lock")
|
||||
@@ -28,7 +35,7 @@ class DemoMoreInfoLock extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class DemoMoreInfoMediaPlayer extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,48 +3,63 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("number", "box1", 0, {
|
||||
friendly_name: "Box1",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "box",
|
||||
unit_of_measurement: "items",
|
||||
}),
|
||||
getEntity("number", "slider1", 0, {
|
||||
friendly_name: "Slider1",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "slider",
|
||||
unit_of_measurement: "items",
|
||||
}),
|
||||
getEntity("number", "auto1", 0, {
|
||||
friendly_name: "Auto1",
|
||||
min: 0,
|
||||
max: 1000,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "auto",
|
||||
unit_of_measurement: "items",
|
||||
}),
|
||||
getEntity("number", "auto2", 0, {
|
||||
friendly_name: "Auto2",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "auto",
|
||||
unit_of_measurement: "items",
|
||||
}),
|
||||
{
|
||||
entity_id: "number.box1",
|
||||
state: "0",
|
||||
attributes: {
|
||||
friendly_name: "Box1",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "box",
|
||||
unit_of_measurement: "items",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "number.slider1",
|
||||
state: "0",
|
||||
attributes: {
|
||||
friendly_name: "Slider1",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "slider",
|
||||
unit_of_measurement: "items",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "number.auto1",
|
||||
state: "0",
|
||||
attributes: {
|
||||
friendly_name: "Auto1",
|
||||
min: 0,
|
||||
max: 1000,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "auto",
|
||||
unit_of_measurement: "items",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "number.auto2",
|
||||
state: "0",
|
||||
attributes: {
|
||||
friendly_name: "Auto2",
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
initial: 0,
|
||||
mode: "auto",
|
||||
unit_of_measurement: "items",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-number")
|
||||
@@ -57,7 +72,7 @@ class DemoMoreInfoNumber extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,19 +3,26 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("scene", "romantic_lights", "scening", {
|
||||
entity_id: ["light.bed_light", "light.ceiling_lights"],
|
||||
friendly_name: "Romantic Scene",
|
||||
}),
|
||||
getEntity("scene", "unavailable", "unavailable", {
|
||||
friendly_name: "Romantic Scene",
|
||||
}),
|
||||
{
|
||||
entity_id: "scene.romantic_lights",
|
||||
state: "scening",
|
||||
attributes: {
|
||||
entity_id: ["light.bed_light", "light.ceiling_lights"],
|
||||
friendly_name: "Romantic Scene",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "scene.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Romantic Scene",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-scene")
|
||||
@@ -28,7 +35,7 @@ class DemoMoreInfoScene extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,19 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("timer", "timer", "idle", {
|
||||
friendly_name: "Timer",
|
||||
duration: "0:05:00",
|
||||
}),
|
||||
{
|
||||
entity_id: "timer.timer",
|
||||
state: "idle",
|
||||
attributes: {
|
||||
friendly_name: "Timer",
|
||||
duration: "0:05:00",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-timer")
|
||||
@@ -25,7 +28,7 @@ class DemoMoreInfoTimer extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
@@ -23,124 +22,208 @@ const base_attributes = {
|
||||
};
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("update", "update1", "on", {
|
||||
...base_attributes,
|
||||
friendly_name: "Update",
|
||||
}),
|
||||
getEntity("update", "update2", "on", {
|
||||
...base_attributes,
|
||||
title: null,
|
||||
friendly_name: "Update without title",
|
||||
}),
|
||||
getEntity("update", "update3", "on", {
|
||||
...base_attributes,
|
||||
release_url: null,
|
||||
friendly_name: "Update without release_url",
|
||||
}),
|
||||
getEntity("update", "update4", "on", {
|
||||
...base_attributes,
|
||||
release_summary: null,
|
||||
friendly_name: "Update without release_summary",
|
||||
}),
|
||||
getEntity("update", "update5", "off", {
|
||||
...base_attributes,
|
||||
installed_version: "1.2.3",
|
||||
friendly_name: "No update",
|
||||
}),
|
||||
getEntity("update", "update6", "off", {
|
||||
...base_attributes,
|
||||
skipped_version: "1.2.3",
|
||||
friendly_name: "Skipped version",
|
||||
}),
|
||||
getEntity("update", "update7", "on", {
|
||||
...base_attributes,
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.BACKUP,
|
||||
friendly_name: "With backup support",
|
||||
}),
|
||||
getEntity("update", "update8", "on", {
|
||||
...base_attributes,
|
||||
in_progress: true,
|
||||
friendly_name: "With true in_progress",
|
||||
}),
|
||||
getEntity("update", "update9", "on", {
|
||||
...base_attributes,
|
||||
in_progress: 25,
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
|
||||
friendly_name: "With 25 in_progress",
|
||||
}),
|
||||
getEntity("update", "update10", "on", {
|
||||
...base_attributes,
|
||||
in_progress: 50,
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
|
||||
friendly_name: "With 50 in_progress",
|
||||
}),
|
||||
getEntity("update", "update11", "on", {
|
||||
...base_attributes,
|
||||
in_progress: 75,
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
|
||||
friendly_name: "With 75 in_progress",
|
||||
}),
|
||||
getEntity("update", "update12", "unavailable", {
|
||||
...base_attributes,
|
||||
in_progress: 50,
|
||||
friendly_name: "Unavailable",
|
||||
}),
|
||||
getEntity("update", "update13", "on", {
|
||||
...base_attributes,
|
||||
supported_features: 0,
|
||||
friendly_name: "No install support",
|
||||
}),
|
||||
getEntity("update", "update14", "off", {
|
||||
...base_attributes,
|
||||
installed_version: null,
|
||||
friendly_name: "Update without installed_version",
|
||||
}),
|
||||
getEntity("update", "update15", "off", {
|
||||
...base_attributes,
|
||||
latest_version: null,
|
||||
friendly_name: "Update without latest_version",
|
||||
}),
|
||||
getEntity("update", "update16", "off", {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with release notes",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
|
||||
}),
|
||||
getEntity("update", "update17", "off", {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with release notes error",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
|
||||
}),
|
||||
getEntity("update", "update18", "off", {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with release notes loading",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
|
||||
}),
|
||||
getEntity("update", "update19", "on", {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with auto update",
|
||||
auto_update: true,
|
||||
}),
|
||||
getEntity("update", "update20", "on", {
|
||||
...base_attributes,
|
||||
in_progress: true,
|
||||
title: undefined,
|
||||
friendly_name: "Installing without title",
|
||||
}),
|
||||
getEntity("update", "update21", "on", {
|
||||
...base_attributes,
|
||||
in_progress: true,
|
||||
friendly_name:
|
||||
"Update with in_progress true and UpdateEntityFeature.PROGRESS",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
|
||||
}),
|
||||
{
|
||||
entity_id: "update.update1",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
friendly_name: "Update",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update2",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
title: null,
|
||||
friendly_name: "Update without title",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update3",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
release_url: null,
|
||||
friendly_name: "Update without release_url",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update4",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
release_summary: null,
|
||||
friendly_name: "Update without release_summary",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update5",
|
||||
state: "off",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
installed_version: "1.2.3",
|
||||
friendly_name: "No update",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update6",
|
||||
state: "off",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
skipped_version: "1.2.3",
|
||||
friendly_name: "Skipped version",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update7",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.BACKUP,
|
||||
friendly_name: "With backup support",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update8",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
in_progress: true,
|
||||
friendly_name: "With true in_progress",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update9",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
in_progress: 25,
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
|
||||
friendly_name: "With 25 in_progress",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update10",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
in_progress: 50,
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
|
||||
friendly_name: "With 50 in_progress",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update11",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
in_progress: 75,
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
|
||||
friendly_name: "With 75 in_progress",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update12",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
in_progress: 50,
|
||||
friendly_name: "Unavailable",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update13",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
supported_features: 0,
|
||||
friendly_name: "No install support",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update14",
|
||||
state: "off",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
installed_version: null,
|
||||
friendly_name: "Update without installed_version",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update15",
|
||||
state: "off",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
latest_version: null,
|
||||
friendly_name: "Update without latest_version",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update16",
|
||||
state: "off",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with release notes",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update17",
|
||||
state: "off",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with release notes error",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update18",
|
||||
state: "off",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with release notes loading",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update19",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with auto update",
|
||||
auto_update: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update20",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
in_progress: true,
|
||||
title: undefined,
|
||||
friendly_name: "Installing without title",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "update.update21",
|
||||
state: "on",
|
||||
attributes: {
|
||||
...base_attributes,
|
||||
in_progress: true,
|
||||
friendly_name:
|
||||
"Update with in_progress true and UpdateEntityFeature.PROGRESS",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-update")
|
||||
@@ -153,7 +236,7 @@ class DemoMoreInfoUpdate extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -3,20 +3,23 @@ import { html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
import { VacuumEntityFeature } from "../../../../src/data/vacuum";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("vacuum", "first_floor_vacuum", "docked", {
|
||||
friendly_name: "First floor vacuum",
|
||||
supported_features:
|
||||
VacuumEntityFeature.START +
|
||||
VacuumEntityFeature.STOP +
|
||||
VacuumEntityFeature.RETURN_HOME,
|
||||
}),
|
||||
{
|
||||
entity_id: "vacuum.first_floor_vacuum",
|
||||
state: "docked",
|
||||
attributes: {
|
||||
friendly_name: "First floor vacuum",
|
||||
supported_features:
|
||||
VacuumEntityFeature.START +
|
||||
VacuumEntityFeature.STOP +
|
||||
VacuumEntityFeature.RETURN_HOME,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-vacuum")
|
||||
@@ -29,7 +32,7 @@ class DemoMoreInfoVacuum extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -4,39 +4,46 @@ import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import { WaterHeaterEntityFeature } from "../../../../src/data/water_heater";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import type { MockHomeAssistant } from "../../../../src/fake_data/provide_hass";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("water_heater", "basic", "eco", {
|
||||
friendly_name: "Basic heater",
|
||||
operation_list: ["heat_pump", "eco", "performance", "off"],
|
||||
operation_mode: "eco",
|
||||
away_mode: "off",
|
||||
target_temp_step: 1,
|
||||
current_temperature: 55,
|
||||
temperature: 60,
|
||||
min_temp: 20,
|
||||
max_temp: 70,
|
||||
supported_features:
|
||||
// eslint-disable-next-line no-bitwise
|
||||
WaterHeaterEntityFeature.TARGET_TEMPERATURE |
|
||||
WaterHeaterEntityFeature.OPERATION_MODE |
|
||||
WaterHeaterEntityFeature.AWAY_MODE,
|
||||
}),
|
||||
getEntity("water_heater", "unavailable", "unavailable", {
|
||||
friendly_name: "Unavailable heater",
|
||||
operation_list: ["heat_pump", "eco", "performance", "off"],
|
||||
operation_mode: "off",
|
||||
min_temp: 20,
|
||||
max_temp: 70,
|
||||
supported_features:
|
||||
// eslint-disable-next-line no-bitwise
|
||||
WaterHeaterEntityFeature.TARGET_TEMPERATURE |
|
||||
WaterHeaterEntityFeature.OPERATION_MODE,
|
||||
}),
|
||||
{
|
||||
entity_id: "water_heater.basic",
|
||||
state: "eco",
|
||||
attributes: {
|
||||
friendly_name: "Basic heater",
|
||||
operation_list: ["heat_pump", "eco", "performance", "off"],
|
||||
operation_mode: "eco",
|
||||
away_mode: "off",
|
||||
target_temp_step: 1,
|
||||
current_temperature: 55,
|
||||
temperature: 60,
|
||||
min_temp: 20,
|
||||
max_temp: 70,
|
||||
supported_features:
|
||||
// eslint-disable-next-line no-bitwise
|
||||
WaterHeaterEntityFeature.TARGET_TEMPERATURE |
|
||||
WaterHeaterEntityFeature.OPERATION_MODE |
|
||||
WaterHeaterEntityFeature.AWAY_MODE,
|
||||
},
|
||||
},
|
||||
{
|
||||
entity_id: "water_heater.unavailable",
|
||||
state: "unavailable",
|
||||
attributes: {
|
||||
friendly_name: "Unavailable heater",
|
||||
operation_list: ["heat_pump", "eco", "performance", "off"],
|
||||
operation_mode: "off",
|
||||
min_temp: 20,
|
||||
max_temp: 70,
|
||||
supported_features:
|
||||
// eslint-disable-next-line no-bitwise
|
||||
WaterHeaterEntityFeature.TARGET_TEMPERATURE |
|
||||
WaterHeaterEntityFeature.OPERATION_MODE,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-water-heater")
|
||||
@@ -49,7 +56,7 @@ class DemoMoreInfoWaterHeater extends LitElement {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
.entities=${ENTITIES.map((ent) => ent.entity_id)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class HaLandingPage extends LandingPageBaseElement {
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
makeDialogManager(this, this.shadowRoot!);
|
||||
makeDialogManager(this);
|
||||
|
||||
if (window.innerWidth > 450) {
|
||||
import("../../src/resources/particles");
|
||||
|
||||
+49
-56
@@ -26,33 +26,33 @@
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.6",
|
||||
"@babel/runtime": "7.29.2",
|
||||
"@braintree/sanitize-url": "7.1.2",
|
||||
"@codemirror/autocomplete": "6.20.0",
|
||||
"@codemirror/commands": "6.10.2",
|
||||
"@codemirror/language": "6.12.1",
|
||||
"@codemirror/autocomplete": "6.20.1",
|
||||
"@codemirror/commands": "6.10.3",
|
||||
"@codemirror/language": "6.12.3",
|
||||
"@codemirror/legacy-modes": "6.5.2",
|
||||
"@codemirror/search": "6.6.0",
|
||||
"@codemirror/state": "6.5.4",
|
||||
"@codemirror/view": "6.39.15",
|
||||
"@codemirror/state": "6.6.0",
|
||||
"@codemirror/view": "6.40.0",
|
||||
"@date-fns/tz": "1.4.1",
|
||||
"@egjs/hammerjs": "2.0.17",
|
||||
"@formatjs/intl-datetimeformat": "7.2.2",
|
||||
"@formatjs/intl-displaynames": "7.2.1",
|
||||
"@formatjs/intl-durationformat": "0.10.1",
|
||||
"@formatjs/intl-getcanonicallocales": "3.2.1",
|
||||
"@formatjs/intl-listformat": "8.2.1",
|
||||
"@formatjs/intl-locale": "5.2.1",
|
||||
"@formatjs/intl-numberformat": "9.2.2",
|
||||
"@formatjs/intl-pluralrules": "6.2.2",
|
||||
"@formatjs/intl-relativetimeformat": "12.2.2",
|
||||
"@formatjs/intl-datetimeformat": "7.3.1",
|
||||
"@formatjs/intl-displaynames": "7.3.1",
|
||||
"@formatjs/intl-durationformat": "0.10.3",
|
||||
"@formatjs/intl-getcanonicallocales": "3.2.2",
|
||||
"@formatjs/intl-listformat": "8.3.1",
|
||||
"@formatjs/intl-locale": "5.3.1",
|
||||
"@formatjs/intl-numberformat": "9.3.1",
|
||||
"@formatjs/intl-pluralrules": "6.3.1",
|
||||
"@formatjs/intl-relativetimeformat": "12.3.1",
|
||||
"@fullcalendar/core": "6.1.20",
|
||||
"@fullcalendar/daygrid": "6.1.20",
|
||||
"@fullcalendar/interaction": "6.1.20",
|
||||
"@fullcalendar/list": "6.1.20",
|
||||
"@fullcalendar/luxon3": "6.1.20",
|
||||
"@fullcalendar/timegrid": "6.1.20",
|
||||
"@home-assistant/webawesome": "3.2.1-ha.2",
|
||||
"@home-assistant/webawesome": "3.3.1-ha.0",
|
||||
"@lezer/highlight": "1.2.3",
|
||||
"@lit-labs/motion": "1.1.0",
|
||||
"@lit-labs/observers": "2.1.0",
|
||||
@@ -72,7 +72,6 @@
|
||||
"@material/mwc-list": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
|
||||
"@material/mwc-radio": "0.27.0",
|
||||
"@material/mwc-select": "0.27.0",
|
||||
"@material/mwc-snackbar": "0.27.0",
|
||||
"@material/mwc-switch": "0.27.0",
|
||||
"@material/mwc-textarea": "0.27.0",
|
||||
"@material/mwc-textfield": "0.27.0",
|
||||
@@ -83,19 +82,18 @@
|
||||
"@mdi/js": "7.4.47",
|
||||
"@mdi/svg": "7.4.47",
|
||||
"@replit/codemirror-indentation-markers": "6.5.3",
|
||||
"@swc/helpers": "0.5.18",
|
||||
"@swc/helpers": "0.5.20",
|
||||
"@thomasloven/round-slider": "0.6.0",
|
||||
"@tsparticles/engine": "3.9.1",
|
||||
"@tsparticles/preset-links": "3.2.0",
|
||||
"@vibrant/color": "4.0.4",
|
||||
"@vue/web-component-wrapper": "1.3.0",
|
||||
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
||||
"@webcomponents/webcomponentsjs": "2.8.0",
|
||||
"app-datepicker": "5.1.1",
|
||||
"barcode-detector": "3.0.8",
|
||||
"barcode-detector": "3.1.1",
|
||||
"cally": "0.9.2",
|
||||
"color-name": "2.1.0",
|
||||
"comlink": "4.4.2",
|
||||
"core-js": "3.48.0",
|
||||
"core-js": "3.49.0",
|
||||
"cropperjs": "1.6.2",
|
||||
"culori": "4.0.2",
|
||||
"date-fns": "4.1.0",
|
||||
@@ -106,11 +104,11 @@
|
||||
"element-internals-polyfill": "3.0.2",
|
||||
"fuse.js": "7.1.0",
|
||||
"google-timezones-json": "1.2.0",
|
||||
"gulp-zopfli-green": "6.0.2",
|
||||
"gulp-zopfli-green": "7.0.0",
|
||||
"hls.js": "1.6.15",
|
||||
"home-assistant-js-websocket": "9.6.0",
|
||||
"idb-keyval": "6.2.2",
|
||||
"intl-messageformat": "11.1.2",
|
||||
"intl-messageformat": "11.2.0",
|
||||
"js-yaml": "4.1.1",
|
||||
"leaflet": "1.9.4",
|
||||
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
|
||||
@@ -118,7 +116,7 @@
|
||||
"lit": "3.3.2",
|
||||
"lit-html": "3.3.2",
|
||||
"luxon": "3.7.2",
|
||||
"marked": "17.0.3",
|
||||
"marked": "17.0.5",
|
||||
"memoize-one": "6.0.0",
|
||||
"node-vibrant": "4.0.4",
|
||||
"object-hash": "3.0.0",
|
||||
@@ -131,9 +129,6 @@
|
||||
"stacktrace-js": "2.0.2",
|
||||
"superstruct": "2.0.2",
|
||||
"tinykeys": "3.0.0",
|
||||
"ua-parser-js": "2.0.9",
|
||||
"vue": "2.7.16",
|
||||
"vue2-daterange-picker": "0.6.8",
|
||||
"weekstart": "2.0.0",
|
||||
"workbox-cacheable-response": "7.4.0",
|
||||
"workbox-core": "7.4.0",
|
||||
@@ -145,17 +140,17 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.29.0",
|
||||
"@babel/helper-define-polyfill-provider": "0.6.6",
|
||||
"@babel/helper-define-polyfill-provider": "0.6.8",
|
||||
"@babel/plugin-transform-runtime": "7.29.0",
|
||||
"@babel/preset-env": "7.29.0",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.21.10",
|
||||
"@html-eslint/eslint-plugin": "0.56.0",
|
||||
"@babel/preset-env": "7.29.2",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.22.0",
|
||||
"@html-eslint/eslint-plugin": "0.58.1",
|
||||
"@lokalise/node-api": "15.6.1",
|
||||
"@octokit/auth-oauth-device": "8.0.3",
|
||||
"@octokit/plugin-retry": "8.1.0",
|
||||
"@octokit/rest": "22.0.1",
|
||||
"@rsdoctor/rspack-plugin": "1.5.2",
|
||||
"@rspack/core": "1.7.6",
|
||||
"@rsdoctor/rspack-plugin": "1.5.6",
|
||||
"@rspack/core": "1.7.10",
|
||||
"@rspack/dev-server": "1.2.1",
|
||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||
"@types/chromecast-caf-receiver": "6.0.25",
|
||||
@@ -172,15 +167,14 @@
|
||||
"@types/mocha": "10.0.10",
|
||||
"@types/qrcode": "1.5.6",
|
||||
"@types/sortablejs": "1.15.9",
|
||||
"@types/tar": "6.1.13",
|
||||
"@types/ua-parser-js": "0.7.39",
|
||||
"@types/tar": "7.0.87",
|
||||
"@types/webspeechapi": "0.0.29",
|
||||
"@vitest/coverage-v8": "4.0.18",
|
||||
"babel-loader": "10.0.0",
|
||||
"@vitest/coverage-v8": "4.1.2",
|
||||
"babel-loader": "10.1.1",
|
||||
"babel-plugin-template-html-minifier": "4.1.0",
|
||||
"browserslist-useragent-regexp": "4.1.3",
|
||||
"del": "8.0.1",
|
||||
"eslint": "9.39.3",
|
||||
"eslint": "9.39.4",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-import-resolver-webpack": "0.13.10",
|
||||
@@ -188,9 +182,9 @@
|
||||
"eslint-plugin-lit": "2.2.1",
|
||||
"eslint-plugin-lit-a11y": "5.1.1",
|
||||
"eslint-plugin-unused-imports": "4.4.1",
|
||||
"eslint-plugin-wc": "3.0.2",
|
||||
"eslint-plugin-wc": "3.1.0",
|
||||
"fancy-log": "2.0.0",
|
||||
"fs-extra": "11.3.3",
|
||||
"fs-extra": "11.3.4",
|
||||
"glob": "13.0.6",
|
||||
"gulp": "5.0.1",
|
||||
"gulp-brotli": "3.0.0",
|
||||
@@ -198,9 +192,9 @@
|
||||
"gulp-rename": "2.1.0",
|
||||
"html-minifier-terser": "7.2.0",
|
||||
"husky": "9.1.7",
|
||||
"jsdom": "28.0.0",
|
||||
"jsdom": "29.0.1",
|
||||
"jszip": "3.10.1",
|
||||
"lint-staged": "16.2.7",
|
||||
"lint-staged": "16.4.0",
|
||||
"lit-analyzer": "2.0.3",
|
||||
"lodash.merge": "4.6.2",
|
||||
"lodash.template": "4.5.0",
|
||||
@@ -208,33 +202,32 @@
|
||||
"pinst": "3.0.0",
|
||||
"prettier": "3.8.1",
|
||||
"rspack-manifest-plugin": "5.2.1",
|
||||
"serve": "14.2.5",
|
||||
"sinon": "21.0.1",
|
||||
"tar": "7.5.8",
|
||||
"terser-webpack-plugin": "5.3.16",
|
||||
"serve": "14.2.6",
|
||||
"sinon": "21.0.3",
|
||||
"tar": "7.5.13",
|
||||
"terser-webpack-plugin": "5.4.0",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.54.0",
|
||||
"vite-tsconfig-paths": "6.0.5",
|
||||
"vitest": "4.0.18",
|
||||
"typescript": "6.0.2",
|
||||
"typescript-eslint": "8.57.2",
|
||||
"vite-tsconfig-paths": "6.1.1",
|
||||
"vitest": "4.1.2",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
"webpackbar": "7.0.0",
|
||||
"workbox-build": "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch"
|
||||
"workbox-build": "patch:workbox-build@npm%3A7.4.0#~/.yarn/patches/workbox-build-npm-7.4.0-c84561662c.patch"
|
||||
},
|
||||
"resolutions": {
|
||||
"@material/mwc-button@^0.25.3": "^0.27.0",
|
||||
"lit": "3.3.2",
|
||||
"lit-html": "3.3.2",
|
||||
"clean-css": "5.3.3",
|
||||
"@lit/reactive-element": "2.1.2",
|
||||
"@fullcalendar/daygrid": "6.1.20",
|
||||
"globals": "17.3.0",
|
||||
"globals": "17.4.0",
|
||||
"tslib": "2.8.1",
|
||||
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
|
||||
"glob@^10.2.2": "^10.5.0"
|
||||
},
|
||||
"packageManager": "yarn@4.12.0",
|
||||
"packageManager": "yarn@4.13.0",
|
||||
"volta": {
|
||||
"node": "24.13.1"
|
||||
"node": "24.14.1"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20260302.0"
|
||||
version = "20260325.0"
|
||||
license = "Apache-2.0"
|
||||
license-files = ["LICENSE*"]
|
||||
description = "The Home Assistant frontend"
|
||||
|
||||
@@ -24,11 +24,6 @@
|
||||
"extends": ["monorepo:material-components-web"],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"description": "Vue is only used by date range which is only v2",
|
||||
"matchPackageNames": ["vue"],
|
||||
"allowedVersions": "< 3"
|
||||
},
|
||||
{
|
||||
"description": "Group MDI packages",
|
||||
"groupName": "Material Design Icons",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { genClientId } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { keyed } from "lit/directives/keyed";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
import "../components/ha-alert";
|
||||
@@ -23,6 +23,7 @@ import type {
|
||||
DataEntryFlowStepForm,
|
||||
} from "../data/data_entry_flow";
|
||||
import "./ha-auth-form";
|
||||
import type { HaAuthForm } from "./ha-auth-form";
|
||||
|
||||
type State = "loading" | "error" | "step";
|
||||
|
||||
@@ -52,6 +53,8 @@ export class HaAuthFlow extends LitElement {
|
||||
|
||||
@state() private _submitting = false;
|
||||
|
||||
@query("ha-auth-form") private _form?: HaAuthForm;
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
@@ -179,7 +182,7 @@ export class HaAuthFlow extends LitElement {
|
||||
<div class="action">
|
||||
<ha-button
|
||||
@click=${this._handleSubmit}
|
||||
.disabled=${this._submitting}
|
||||
.loading=${this._submitting}
|
||||
>
|
||||
${this.step.type === "form"
|
||||
? this.localize("ui.panel.page-authorize.form.next")
|
||||
@@ -370,6 +373,11 @@ export class HaAuthFlow extends LitElement {
|
||||
this._providerChanged(this.authProvider);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._form?.reportValidity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._submitting = true;
|
||||
|
||||
const postData = { ...this._stepData, client_id: this.clientId };
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/* eslint-disable lit/prefer-static-styles */
|
||||
import type { TemplateResult } from "lit";
|
||||
import { html } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { HaFormString } from "../components/ha-form/ha-form-string";
|
||||
import "../components/ha-icon-button";
|
||||
import "./ha-auth-textfield";
|
||||
import "../components/input/ha-input";
|
||||
|
||||
@customElement("ha-auth-form-string")
|
||||
export class HaAuthFormString extends HaFormString {
|
||||
@@ -12,59 +9,9 @@ export class HaAuthFormString extends HaFormString {
|
||||
return this;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<style>
|
||||
ha-auth-form-string {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
ha-auth-form-string[own-margin] {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
ha-auth-form-string ha-auth-textfield {
|
||||
display: block !important;
|
||||
}
|
||||
ha-auth-form-string ha-icon-button {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
inset-inline-start: initial;
|
||||
inset-inline-end: 8px;
|
||||
--ha-icon-button-size: 40px;
|
||||
--mdc-icon-size: 20px;
|
||||
color: var(--secondary-text-color);
|
||||
direction: var(--direction);
|
||||
}
|
||||
</style>
|
||||
<ha-auth-textfield
|
||||
.type=${!this.isPassword
|
||||
? this.stringType
|
||||
: this.unmaskedPassword
|
||||
? "text"
|
||||
: "password"}
|
||||
.label=${this.label}
|
||||
.value=${this.data || ""}
|
||||
.helper=${this.helper}
|
||||
helperPersistent
|
||||
.disabled=${this.disabled}
|
||||
.required=${this.schema.required}
|
||||
.autoValidate=${this.schema.required}
|
||||
.name=${this.schema.name}
|
||||
.autocomplete=${this.schema.autocomplete}
|
||||
?autofocus=${this.schema.autofocus}
|
||||
.suffix=${this.isPassword
|
||||
? // reserve some space for the icon.
|
||||
html`<div style="width: 24px"></div>`
|
||||
: this.schema.description?.suffix}
|
||||
.validationMessage=${this.schema.required
|
||||
? this.localize?.("ui.panel.page-authorize.form.error_required")
|
||||
: undefined}
|
||||
@input=${this._valueChanged}
|
||||
@change=${this._valueChanged}
|
||||
></ha-auth-textfield>
|
||||
${this.renderIcon()}
|
||||
`;
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.style.position = "relative";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable lit/prefer-static-styles */
|
||||
import { html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
import { HaForm } from "../components/ha-form/ha-form";
|
||||
import "./ha-auth-form-string";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
|
||||
const localizeBaseKey = "ui.panel.page-authorize.form";
|
||||
|
||||
@@ -34,6 +34,9 @@ export class HaAuthForm extends HaForm {
|
||||
protected render() {
|
||||
return html`
|
||||
<style>
|
||||
ha-auth-form {
|
||||
--ha-input-required-marker: "";
|
||||
}
|
||||
ha-auth-form .root > * {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
/* eslint-disable lit/value-after-constraints */
|
||||
/* eslint-disable lit/prefer-static-styles */
|
||||
import { floatingLabel } from "@material/mwc-floating-label/mwc-floating-label-directive";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { html } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { live } from "lit/directives/live";
|
||||
import { HaTextField } from "../components/ha-textfield";
|
||||
|
||||
@customElement("ha-auth-textfield")
|
||||
export class HaAuthTextField extends HaTextField {
|
||||
protected renderLabel(): TemplateResult | string {
|
||||
return !this.label
|
||||
? ""
|
||||
: html`
|
||||
<span
|
||||
.floatingLabelFoundation=${floatingLabel(
|
||||
this.label
|
||||
) as unknown as any}
|
||||
.id=${this.name}
|
||||
>${this.label}</span
|
||||
>
|
||||
`;
|
||||
}
|
||||
|
||||
protected renderInput(shouldRenderHelperText: boolean): TemplateResult {
|
||||
const minOrUndef = this.minLength === -1 ? undefined : this.minLength;
|
||||
const maxOrUndef = this.maxLength === -1 ? undefined : this.maxLength;
|
||||
const autocapitalizeOrUndef = this.autocapitalize
|
||||
? (this.autocapitalize as
|
||||
| "off"
|
||||
| "none"
|
||||
| "on"
|
||||
| "sentences"
|
||||
| "words"
|
||||
| "characters")
|
||||
: undefined;
|
||||
const showValidationMessage = this.validationMessage && !this.isUiValid;
|
||||
const ariaLabelledbyOrUndef = this.label ? this.name : undefined;
|
||||
const ariaControlsOrUndef = shouldRenderHelperText
|
||||
? "helper-text"
|
||||
: undefined;
|
||||
const ariaDescribedbyOrUndef =
|
||||
this.focused || this.helperPersistent || showValidationMessage
|
||||
? "helper-text"
|
||||
: undefined;
|
||||
// TODO: live() directive needs casting for lit-analyzer
|
||||
// https://github.com/runem/lit-analyzer/pull/91/files
|
||||
// TODO: lit-analyzer labels min/max as (number|string) instead of string
|
||||
return html`<input
|
||||
aria-labelledby=${ifDefined(ariaLabelledbyOrUndef)}
|
||||
aria-controls=${ifDefined(ariaControlsOrUndef)}
|
||||
aria-describedby=${ifDefined(ariaDescribedbyOrUndef)}
|
||||
class="mdc-text-field__input"
|
||||
type=${this.type}
|
||||
.value=${live(this.value) as unknown as string}
|
||||
?disabled=${this.disabled}
|
||||
placeholder=${this.placeholder}
|
||||
?required=${this.required}
|
||||
?readonly=${this.readOnly}
|
||||
minlength=${ifDefined(minOrUndef)}
|
||||
maxlength=${ifDefined(maxOrUndef)}
|
||||
pattern=${ifDefined(this.pattern ? this.pattern : undefined)}
|
||||
min=${ifDefined(this.min === "" ? undefined : (this.min as number))}
|
||||
max=${ifDefined(this.max === "" ? undefined : (this.max as number))}
|
||||
step=${ifDefined(this.step === null ? undefined : (this.step as number))}
|
||||
size=${ifDefined(this.size === null ? undefined : this.size)}
|
||||
name=${ifDefined(this.name === "" ? undefined : this.name)}
|
||||
inputmode=${ifDefined(this.inputMode)}
|
||||
autocapitalize=${ifDefined(autocapitalizeOrUndef)}
|
||||
?autofocus=${this.autofocus}
|
||||
@input=${this.handleInputChange}
|
||||
@focus=${this.onInputFocus}
|
||||
@blur=${this.onInputBlur}
|
||||
/>`;
|
||||
}
|
||||
|
||||
public render() {
|
||||
return html`
|
||||
<style>
|
||||
ha-auth-textfield {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
outline: none;
|
||||
}
|
||||
ha-auth-textfield:not([disabled]):hover
|
||||
:not(.mdc-text-field--invalid):not(.mdc-text-field--focused)
|
||||
mwc-notched-outline {
|
||||
--mdc-notched-outline-border-color: var(
|
||||
--mdc-text-field-outlined-hover-border-color,
|
||||
rgba(0, 0, 0, 0.87)
|
||||
);
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field:not(.mdc-text-field--outlined) {
|
||||
background-color: var(--mdc-text-field-fill-color, whitesmoke);
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field.mdc-text-field--invalid
|
||||
mwc-notched-outline {
|
||||
--mdc-notched-outline-border-color: var(
|
||||
--mdc-text-field-error-color,
|
||||
var(--mdc-theme-error, #b00020)
|
||||
);
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field.mdc-text-field--invalid
|
||||
+ .mdc-text-field-helper-line
|
||||
.mdc-text-field-character-counter,
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field.mdc-text-field--invalid
|
||||
.mdc-text-field__icon {
|
||||
color: var(
|
||||
--mdc-text-field-error-color,
|
||||
var(--mdc-theme-error, #b00020)
|
||||
);
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field:not(.mdc-text-field--invalid):not(
|
||||
.mdc-text-field--focused
|
||||
)
|
||||
.mdc-floating-label,
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field:not(.mdc-text-field--invalid):not(
|
||||
.mdc-text-field--focused
|
||||
)
|
||||
.mdc-floating-label::after {
|
||||
color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6));
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field.mdc-text-field--focused
|
||||
mwc-notched-outline {
|
||||
--mdc-notched-outline-stroke-width: 2px;
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field.mdc-text-field--focused:not(.mdc-text-field--invalid)
|
||||
mwc-notched-outline {
|
||||
--mdc-notched-outline-border-color: var(
|
||||
--mdc-text-field-focused-label-color,
|
||||
var(--mdc-theme-primary, rgba(98, 0, 238, 0.87))
|
||||
);
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field.mdc-text-field--focused:not(.mdc-text-field--invalid)
|
||||
.mdc-floating-label {
|
||||
color: #6200ee;
|
||||
color: var(--mdc-theme-primary, #6200ee);
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field
|
||||
.mdc-text-field__input {
|
||||
color: var(--mdc-text-field-ink-color, rgba(0, 0, 0, 0.87));
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field
|
||||
.mdc-text-field__input::placeholder {
|
||||
color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6));
|
||||
}
|
||||
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field-helper-line
|
||||
.mdc-text-field-helper-text:not(
|
||||
.mdc-text-field-helper-text--validation-msg
|
||||
),
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field-helper-line:not(.mdc-text-field--invalid)
|
||||
.mdc-text-field-character-counter {
|
||||
color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6));
|
||||
}
|
||||
|
||||
ha-auth-textfield[disabled]
|
||||
.mdc-text-field:not(.mdc-text-field--outlined) {
|
||||
background-color: var(--mdc-text-field-disabled-fill-color, #fafafa);
|
||||
}
|
||||
|
||||
ha-auth-textfield[disabled]
|
||||
.mdc-text-field.mdc-text-field--outlined
|
||||
mwc-notched-outline {
|
||||
--mdc-notched-outline-border-color: var(
|
||||
--mdc-text-field-outlined-disabled-border-color,
|
||||
rgba(0, 0, 0, 0.06)
|
||||
);
|
||||
}
|
||||
|
||||
ha-auth-textfield[disabled]
|
||||
.mdc-text-field:not(.mdc-text-field--invalid):not(
|
||||
.mdc-text-field--focused
|
||||
)
|
||||
.mdc-floating-label,
|
||||
ha-auth-textfield[disabled]
|
||||
.mdc-text-field:not(.mdc-text-field--invalid):not(
|
||||
.mdc-text-field--focused
|
||||
)
|
||||
.mdc-floating-label::after {
|
||||
color: var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.38));
|
||||
}
|
||||
|
||||
ha-auth-textfield[disabled] .mdc-text-field .mdc-text-field__input,
|
||||
ha-auth-textfield[disabled]
|
||||
.mdc-text-field
|
||||
.mdc-text-field__input::placeholder {
|
||||
color: var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.38));
|
||||
}
|
||||
|
||||
ha-auth-textfield[disabled]
|
||||
.mdc-text-field-helper-line
|
||||
.mdc-text-field-helper-text,
|
||||
ha-auth-textfield[disabled]
|
||||
.mdc-text-field-helper-line
|
||||
.mdc-text-field-character-counter {
|
||||
color: var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.38));
|
||||
}
|
||||
ha-auth-textfield:not([disabled])
|
||||
.mdc-text-field.mdc-text-field--focused:not(.mdc-text-field--invalid)
|
||||
.mdc-floating-label {
|
||||
color: var(--mdc-theme-primary, #6200ee);
|
||||
}
|
||||
ha-auth-textfield[no-spinner] input::-webkit-outer-spin-button,
|
||||
ha-auth-textfield[no-spinner] input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
ha-auth-textfield[no-spinner] input[type="number"] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
</style>
|
||||
${super.render()}
|
||||
`;
|
||||
}
|
||||
|
||||
protected createRenderRoot() {
|
||||
// add parent style to light dom
|
||||
const style = document.createElement("style");
|
||||
style.textContent = HaTextField.elementStyles as unknown as string;
|
||||
this.append(style);
|
||||
return this;
|
||||
}
|
||||
|
||||
public firstUpdated() {
|
||||
super.firstUpdated();
|
||||
|
||||
if (this.autofocus) {
|
||||
this.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-auth-textfield": HaAuthTextField;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable no-console */
|
||||
/// <reference types="chromecast-caf-sender" />
|
||||
|
||||
import type { Auth } from "home-assistant-js-websocket";
|
||||
import { castApiAvailable } from "./cast_framework";
|
||||
@@ -58,9 +59,11 @@ export class CastManager {
|
||||
this._eventListeners[event].push(listener);
|
||||
|
||||
return () => {
|
||||
this._eventListeners[event].splice(
|
||||
this._eventListeners[event].indexOf(listener)
|
||||
);
|
||||
const listeners = this._eventListeners[event];
|
||||
const index = listeners.indexOf(listener);
|
||||
if (index !== -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -32,13 +32,49 @@ const YAML_ONLY_THEMES_COLORS = new Set([
|
||||
"disabled",
|
||||
]);
|
||||
|
||||
export function computeCssColor(color: string): string {
|
||||
/**
|
||||
* Compose a CSS variable out of a theme color
|
||||
* @param color - Theme color (examples: `red`, `primary-text`)
|
||||
* @returns CSS variable in `--xxx-color` format;
|
||||
* initial color if not found in theme colors
|
||||
*/
|
||||
export function computeCssVariableName(color: string): string {
|
||||
if (THEME_COLORS.has(color) || YAML_ONLY_THEMES_COLORS.has(color)) {
|
||||
return `var(--${color}-color)`;
|
||||
return `--${color}-color`;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a CSS variable out of a theme color & then resolve it
|
||||
* @param color - Theme color (examples: `red`, `primary-text`)
|
||||
* @returns Resolved CSS variable in `var(--xxx-color)` format;
|
||||
* initial color if not found in theme colors
|
||||
*/
|
||||
export function computeCssColor(color: string): string {
|
||||
const cssVarName = computeCssVariableName(color);
|
||||
if (cssVarName !== color) {
|
||||
return `var(${cssVarName})`;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a color from document's styles
|
||||
* @param color - Named theme color (examples: `red`, `primary-text`)
|
||||
* @returns Resolved color; initial color if not found in document's styles
|
||||
*/
|
||||
export function resolveThemeColor(color: string): string {
|
||||
const cssColor = computeCssVariableName(color);
|
||||
if (cssColor.startsWith("--")) {
|
||||
const resolved = getComputedStyle(document.body)
|
||||
.getPropertyValue(cssColor)
|
||||
.trim();
|
||||
return resolved || color;
|
||||
}
|
||||
return cssColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if a string is a valid color.
|
||||
* Accepts: hex colors (#xxx, #xxxxxx), theme colors, and valid CSS color names.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import colors from "color-name";
|
||||
import { expandHex } from "./hex";
|
||||
import { resolveThemeColor } from "./compute-color";
|
||||
|
||||
const rgb_hex = (component: number): string => {
|
||||
const hex = Math.round(Math.min(Math.max(component, 0), 255)).toString(16);
|
||||
@@ -130,26 +131,43 @@ export const rgb2hs = (rgb: [number, number, number]): [number, number] =>
|
||||
export const hs2rgb = (hs: [number, number]): [number, number, number] =>
|
||||
hsv2rgb([hs[0], hs[1], 255]);
|
||||
|
||||
export function theme2hex(themeColor: string): string {
|
||||
if (themeColor.startsWith("#")) {
|
||||
if (themeColor.length === 4 || themeColor.length === 5) {
|
||||
const c = themeColor;
|
||||
/**
|
||||
* Attempt to get a HEX color from a color defined in different formats:
|
||||
* HEX, rgb/rgba, named color
|
||||
* @param color - Color (HEX, rgb/rgba, named color) to be converted to HEX
|
||||
* @returns HEX color
|
||||
*/
|
||||
export function theme2hex(color: string): string {
|
||||
// Attempting to find a HEX pattern in the input string
|
||||
if (color.startsWith("#")) {
|
||||
if (color.length === 4 || color.length === 5) {
|
||||
const c = color;
|
||||
// Convert short-form hex (#abc) to 6 digit (#aabbcc). Ignore alpha channel.
|
||||
return `#${c[1]}${c[1]}${c[2]}${c[2]}${c[3]}${c[3]}`;
|
||||
}
|
||||
if (themeColor.length === 9) {
|
||||
if (color.length === 9) {
|
||||
// Ignore alpha channel.
|
||||
return themeColor.substring(0, 7);
|
||||
return color.substring(0, 7);
|
||||
}
|
||||
return themeColor;
|
||||
return color;
|
||||
}
|
||||
|
||||
const rgbFromColorName = colors[themeColor.toLowerCase()];
|
||||
if (rgbFromColorName) {
|
||||
return rgb2hex(rgbFromColorName);
|
||||
// Attempting to find a match in a HA Frontend theme colors
|
||||
const themeColor = resolveThemeColor(color.toLowerCase());
|
||||
if (themeColor !== color.toLowerCase()) {
|
||||
// theme color is recognized, now re-attempt
|
||||
return theme2hex(themeColor);
|
||||
}
|
||||
|
||||
const rgbMatch = themeColor.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
|
||||
// Attempting to find a match in a web colors array
|
||||
const rgbFromWebColor = colors[color.toLowerCase()];
|
||||
if (rgbFromWebColor) {
|
||||
// HEX color is recognized for the input named color
|
||||
return rgb2hex(rgbFromWebColor);
|
||||
}
|
||||
|
||||
// Attempting to find an RGB pattern in the input string
|
||||
const rgbMatch = color.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
|
||||
if (rgbMatch) {
|
||||
const [, r, g, b] = rgbMatch.map(Number);
|
||||
return rgb2hex([r, g, b]);
|
||||
@@ -158,5 +176,5 @@ export function theme2hex(themeColor: string): string {
|
||||
// We have a named color, and there's nothing in the table,
|
||||
// so nothing further we can do with it.
|
||||
// Compare/border/background color will all be the same.
|
||||
return themeColor;
|
||||
return color;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { wcagLuminance, wcagContrast } from "culori";
|
||||
import { theme2hex } from "./convert-color";
|
||||
|
||||
/**
|
||||
* Calculates the luminosity of an RGB color.
|
||||
@@ -48,3 +49,13 @@ export const getRGBContrastRatio = (
|
||||
rgb1: [number, number, number],
|
||||
rgb2: [number, number, number]
|
||||
) => Math.round((rgbContrast(rgb1, rgb2) + Number.EPSILON) * 100) / 100;
|
||||
|
||||
/**
|
||||
* Returns a contrasted color (black or white) based on the luminance of another color
|
||||
* @param color - Color (HEX, rgb/rgba, named color) to calculate a contrasted color
|
||||
* @returns HEX color ("#000000" for dark backgrounds, "#ffffff" for light backgrounds)
|
||||
*/
|
||||
export const getContrastedColorHex = (color: string): string => {
|
||||
const lum = wcagLuminance(theme2hex(color));
|
||||
return lum > 0.5 ? "#000000" : "#ffffff";
|
||||
};
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { listenMediaQuery } from "../dom/media_query";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import type { Condition } from "../../panels/lovelace/common/validate-condition";
|
||||
import type {
|
||||
Condition,
|
||||
ConditionContext,
|
||||
} from "../../panels/lovelace/common/validate-condition";
|
||||
import { checkConditionsMet } from "../../panels/lovelace/common/validate-condition";
|
||||
import { extractMediaQueries, extractTimeConditions } from "./extract";
|
||||
import { calculateNextTimeUpdate } from "./time-calculator";
|
||||
@@ -19,7 +22,8 @@ export function setupMediaQueryListeners(
|
||||
conditions: Condition[],
|
||||
hass: HomeAssistant,
|
||||
addListener: (unsub: () => void) => void,
|
||||
onUpdate: (conditionsMet: boolean) => void
|
||||
onUpdate: (conditionsMet: boolean) => void,
|
||||
getContext?: () => ConditionContext
|
||||
): void {
|
||||
const mediaQueries = extractMediaQueries(conditions);
|
||||
|
||||
@@ -36,7 +40,8 @@ export function setupMediaQueryListeners(
|
||||
if (hasOnlyMediaQuery) {
|
||||
onUpdate(matches);
|
||||
} else {
|
||||
const conditionsMet = checkConditionsMet(conditions, hass);
|
||||
const context = getContext?.() ?? {};
|
||||
const conditionsMet = checkConditionsMet(conditions, hass, context);
|
||||
onUpdate(conditionsMet);
|
||||
}
|
||||
});
|
||||
@@ -51,7 +56,8 @@ export function setupTimeListeners(
|
||||
conditions: Condition[],
|
||||
hass: HomeAssistant,
|
||||
addListener: (unsub: () => void) => void,
|
||||
onUpdate: (conditionsMet: boolean) => void
|
||||
onUpdate: (conditionsMet: boolean) => void,
|
||||
getContext?: () => ConditionContext
|
||||
): void {
|
||||
const timeConditions = extractTimeConditions(conditions);
|
||||
|
||||
@@ -70,7 +76,8 @@ export function setupTimeListeners(
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
if (delay <= MAX_TIMEOUT_DELAY) {
|
||||
const conditionsMet = checkConditionsMet(conditions, hass);
|
||||
const context = getContext?.() ?? {};
|
||||
const conditionsMet = checkConditionsMet(conditions, hass, context);
|
||||
onUpdate(conditionsMet);
|
||||
}
|
||||
scheduleUpdate();
|
||||
@@ -87,3 +94,17 @@ export function setupTimeListeners(
|
||||
scheduleUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up all condition listeners (media query, time) for conditional visibility.
|
||||
*/
|
||||
export function setupConditionListeners(
|
||||
conditions: Condition[],
|
||||
hass: HomeAssistant,
|
||||
addListener: (unsub: () => void) => void,
|
||||
onUpdate: (conditionsMet: boolean) => void,
|
||||
getContext?: () => ConditionContext
|
||||
): void {
|
||||
setupMediaQueryListeners(conditions, hass, addListener, onUpdate, getContext);
|
||||
setupTimeListeners(conditions, hass, addListener, onUpdate, getContext);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export const isLoadedIntegration = (
|
||||
) =>
|
||||
!page.component ||
|
||||
ensureArray(page.component).some((integration) =>
|
||||
isComponentLoaded(hass, integration)
|
||||
isComponentLoaded(hass.config, integration)
|
||||
);
|
||||
|
||||
export const isNotLoadedIntegration = (
|
||||
@@ -23,7 +23,7 @@ export const isNotLoadedIntegration = (
|
||||
) =>
|
||||
!page.not_component ||
|
||||
!ensureArray(page.not_component).some((integration) =>
|
||||
isComponentLoaded(hass, integration)
|
||||
isComponentLoaded(hass.config, integration)
|
||||
);
|
||||
|
||||
export const isCore = (page: PageNavigation) => page.core;
|
||||
|
||||
@@ -2,6 +2,6 @@ import type { HomeAssistant } from "../../types";
|
||||
|
||||
/** Return if a component is loaded. */
|
||||
export const isComponentLoaded = (
|
||||
hass: HomeAssistant,
|
||||
hassConfig: HomeAssistant["config"],
|
||||
component: string
|
||||
): boolean => hass && hass.config.components.includes(component);
|
||||
): boolean => hassConfig && hassConfig.components.includes(component);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import {
|
||||
addDays,
|
||||
subHours,
|
||||
endOfDay,
|
||||
endOfMonth,
|
||||
endOfQuarter,
|
||||
endOfWeek,
|
||||
endOfYear,
|
||||
startOfDay,
|
||||
startOfMonth,
|
||||
startOfQuarter,
|
||||
startOfWeek,
|
||||
startOfYear,
|
||||
startOfQuarter,
|
||||
endOfQuarter,
|
||||
subDays,
|
||||
subHours,
|
||||
subMonths,
|
||||
} from "date-fns";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
@@ -33,83 +33,89 @@ export type DateRange =
|
||||
| "now-24h";
|
||||
|
||||
export const calcDateRange = (
|
||||
hass: HomeAssistant,
|
||||
locale: HomeAssistant["locale"],
|
||||
hassConfig: HomeAssistant["config"],
|
||||
range: DateRange
|
||||
): [Date, Date] => {
|
||||
const today = new Date();
|
||||
const weekStartsOn = firstWeekdayIndex(hass.locale);
|
||||
const weekStartsOn = firstWeekdayIndex(locale);
|
||||
switch (range) {
|
||||
case "today":
|
||||
return [
|
||||
calcDate(today, startOfDay, hass.locale, hass.config, {
|
||||
calcDate(today, startOfDay, locale, hassConfig, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
calcDate(today, endOfDay, hass.locale, hass.config, {
|
||||
calcDate(today, endOfDay, locale, hassConfig, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
];
|
||||
case "yesterday":
|
||||
return [
|
||||
calcDate(addDays(today, -1), startOfDay, hass.locale, hass.config, {
|
||||
calcDate(addDays(today, -1), startOfDay, locale, hassConfig, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
calcDate(addDays(today, -1), endOfDay, hass.locale, hass.config, {
|
||||
calcDate(addDays(today, -1), endOfDay, locale, hassConfig, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
];
|
||||
case "this_week":
|
||||
return [
|
||||
calcDate(today, startOfWeek, hass.locale, hass.config, {
|
||||
calcDate(today, startOfWeek, locale, hassConfig, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
calcDate(today, endOfWeek, hass.locale, hass.config, {
|
||||
calcDate(today, endOfWeek, locale, hassConfig, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
];
|
||||
case "this_month":
|
||||
return [
|
||||
calcDate(today, startOfMonth, hass.locale, hass.config),
|
||||
calcDate(today, endOfMonth, hass.locale, hass.config),
|
||||
calcDate(today, startOfMonth, locale, hassConfig),
|
||||
calcDate(today, endOfMonth, locale, hassConfig),
|
||||
];
|
||||
case "this_quarter":
|
||||
return [
|
||||
calcDate(today, startOfQuarter, hass.locale, hass.config),
|
||||
calcDate(today, endOfQuarter, hass.locale, hass.config),
|
||||
calcDate(today, startOfQuarter, locale, hassConfig),
|
||||
calcDate(today, endOfQuarter, locale, hassConfig),
|
||||
];
|
||||
case "this_year":
|
||||
return [
|
||||
calcDate(today, startOfYear, hass.locale, hass.config),
|
||||
calcDate(today, endOfYear, hass.locale, hass.config),
|
||||
calcDate(today, startOfYear, locale, hassConfig),
|
||||
calcDate(today, endOfYear, locale, hassConfig),
|
||||
];
|
||||
case "now-7d":
|
||||
return [
|
||||
calcDate(today, subDays, hass.locale, hass.config, 7),
|
||||
calcDate(today, subDays, hass.locale, hass.config, 0),
|
||||
calcDate(today, subDays, locale, hassConfig, 7),
|
||||
calcDate(today, subDays, locale, hassConfig, 0),
|
||||
];
|
||||
case "now-30d":
|
||||
return [
|
||||
calcDate(today, subDays, hass.locale, hass.config, 30),
|
||||
calcDate(today, subDays, hass.locale, hass.config, 0),
|
||||
calcDate(today, subDays, locale, hassConfig, 30),
|
||||
calcDate(today, subDays, locale, hassConfig, 0),
|
||||
];
|
||||
case "now-12m":
|
||||
return [
|
||||
calcDate(today, subMonths, hass.locale, hass.config, 12),
|
||||
calcDate(today, subMonths, hass.locale, hass.config, 0),
|
||||
calcDate(
|
||||
today,
|
||||
(date) => subMonths(startOfMonth(date), 11),
|
||||
locale,
|
||||
hassConfig
|
||||
),
|
||||
calcDate(today, endOfMonth, locale, hassConfig),
|
||||
];
|
||||
case "now-1h":
|
||||
return [
|
||||
calcDate(today, subHours, hass.locale, hass.config, 1),
|
||||
calcDate(today, subHours, hass.locale, hass.config, 0),
|
||||
calcDate(today, subHours, locale, hassConfig, 1),
|
||||
calcDate(today, subHours, locale, hassConfig, 0),
|
||||
];
|
||||
case "now-12h":
|
||||
return [
|
||||
calcDate(today, subHours, hass.locale, hass.config, 12),
|
||||
calcDate(today, subHours, hass.locale, hass.config, 0),
|
||||
calcDate(today, subHours, locale, hassConfig, 12),
|
||||
calcDate(today, subHours, locale, hassConfig, 0),
|
||||
];
|
||||
case "now-24h":
|
||||
return [
|
||||
calcDate(today, subHours, hass.locale, hass.config, 24),
|
||||
calcDate(today, subHours, hass.locale, hass.config, 0),
|
||||
calcDate(today, subHours, locale, hassConfig, 24),
|
||||
calcDate(today, subHours, locale, hassConfig, 0),
|
||||
];
|
||||
}
|
||||
return [today, today];
|
||||
|
||||
@@ -166,6 +166,21 @@ const formatDateMonthMem = memoizeOne(
|
||||
})
|
||||
);
|
||||
|
||||
// Aug
|
||||
export const formatDateMonthShort = (
|
||||
dateObj: Date,
|
||||
locale: FrontendLocaleData,
|
||||
config: HassConfig
|
||||
) => formatDateMonthShortMem(locale, config.time_zone).format(dateObj);
|
||||
|
||||
const formatDateMonthShortMem = memoizeOne(
|
||||
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||
new Intl.DateTimeFormat(locale.language, {
|
||||
month: "short",
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
// 2021
|
||||
export const formatDateYear = (
|
||||
dateObj: Date,
|
||||
@@ -246,3 +261,36 @@ const formatDateWeekdayShortDateMem = memoizeOne(
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* Format a date as YYYY-MM-DD. Uses "en-CA" because it's the only
|
||||
* Intl locale that natively outputs ISO 8601 date format.
|
||||
* Locale/config are only used to resolve the time zone.
|
||||
*/
|
||||
export const formatISODateOnly = (
|
||||
dateObj: Date,
|
||||
locale: FrontendLocaleData,
|
||||
config: HassConfig
|
||||
) => {
|
||||
const timeZone = resolveTimeZone(locale.time_zone, config.time_zone);
|
||||
const formatter = new Intl.DateTimeFormat("en-CA", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
timeZone,
|
||||
});
|
||||
return formatter.format(dateObj);
|
||||
};
|
||||
|
||||
// 2026-08-10/2026-08-15
|
||||
export const formatCallyDateRange = (
|
||||
start: Date,
|
||||
end: Date,
|
||||
locale: FrontendLocaleData,
|
||||
config: HassConfig
|
||||
) => {
|
||||
const startDate = formatISODateOnly(start, locale, config);
|
||||
const endDate = formatISODateOnly(end, locale, config);
|
||||
|
||||
return `${startDate}/${endDate}`;
|
||||
};
|
||||
|
||||
@@ -11,11 +11,11 @@ export const canOverrideAlphanumericInput = (composedPath: EventTarget[]) => {
|
||||
|
||||
const el = composedPath[0] as Element;
|
||||
|
||||
if (el.tagName === "TEXTAREA") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (el.parentElement?.tagName === "HA-SELECT") {
|
||||
if (
|
||||
el.tagName === "TEXTAREA" ||
|
||||
el.parentElement?.tagName === "HA-SELECT" ||
|
||||
el.parentElement?.tagName === "HA-DROPDOWN"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,24 +14,25 @@ export const computeDeviceName = (
|
||||
|
||||
export const computeDeviceNameDisplay = (
|
||||
device: DeviceRegistryEntry,
|
||||
hass: HomeAssistant,
|
||||
localize: HomeAssistant["localize"],
|
||||
hassStates: HomeAssistant["states"],
|
||||
entities?: EntityRegistryEntry[] | EntityRegistryDisplayEntry[] | string[]
|
||||
) =>
|
||||
computeDeviceName(device) ||
|
||||
(entities && fallbackDeviceName(hass, entities)) ||
|
||||
hass.localize("ui.panel.config.devices.unnamed_device", {
|
||||
type: hass.localize(
|
||||
(entities && fallbackDeviceName(hassStates, entities)) ||
|
||||
localize("ui.panel.config.devices.unnamed_device", {
|
||||
type: localize(
|
||||
`ui.panel.config.devices.type.${device.entry_type || "device"}`
|
||||
),
|
||||
});
|
||||
|
||||
export const fallbackDeviceName = (
|
||||
hass: HomeAssistant,
|
||||
hassStates: HomeAssistant["states"],
|
||||
entities: EntityRegistryEntry[] | EntityRegistryDisplayEntry[] | string[]
|
||||
) => {
|
||||
for (const entity of entities || []) {
|
||||
const entityId = typeof entity === "string" ? entity : entity.entity_id;
|
||||
const stateObj = hass.states[entityId];
|
||||
const stateObj = hassStates[entityId];
|
||||
if (stateObj) {
|
||||
return computeStateName(stateObj);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { computeAreaName } from "./compute_area_name";
|
||||
import { computeDeviceName } from "./compute_device_name";
|
||||
import { computeEntityName, entityUseDeviceName } from "./compute_entity_name";
|
||||
import { computeFloorName } from "./compute_floor_name";
|
||||
import { computeStateName } from "./compute_state_name";
|
||||
import { getEntityContext } from "./context/get_entity_context";
|
||||
|
||||
const DEFAULT_SEPARATOR = " ";
|
||||
@@ -29,14 +30,23 @@ export interface EntityNameOptions {
|
||||
|
||||
export const computeEntityNameDisplay = (
|
||||
stateObj: HassEntity,
|
||||
name: EntityNameItem | EntityNameItem[] | undefined,
|
||||
name: string | EntityNameItem | EntityNameItem[] | undefined,
|
||||
entities: HomeAssistant["entities"],
|
||||
devices: HomeAssistant["devices"],
|
||||
areas: HomeAssistant["areas"],
|
||||
floors: HomeAssistant["floors"],
|
||||
options?: EntityNameOptions
|
||||
) => {
|
||||
let items = ensureArray(name || DEFAULT_ENTITY_NAME);
|
||||
if (typeof name === "string") {
|
||||
return name;
|
||||
}
|
||||
|
||||
// If no name config is provided, fall back to the friendly name
|
||||
if (!name) {
|
||||
return computeStateName(stateObj);
|
||||
}
|
||||
|
||||
let items = ensureArray(name);
|
||||
|
||||
const separator = options?.separator ?? DEFAULT_SEPARATOR;
|
||||
|
||||
|
||||
@@ -142,6 +142,8 @@ const computeStateToPartsFromEntityAttributes = (
|
||||
group: "value",
|
||||
decimal: "value",
|
||||
fraction: "value",
|
||||
minusSign: "value",
|
||||
plusSign: "value",
|
||||
literal: "literal",
|
||||
currency: "unit",
|
||||
};
|
||||
@@ -152,7 +154,7 @@ const computeStateToPartsFromEntityAttributes = (
|
||||
const type = TYPE_MAP[part.type];
|
||||
if (!type) continue;
|
||||
const last = valueParts[valueParts.length - 1];
|
||||
// Merge consecutive numeric parts (e.g. "1" + "," + "234" + "." + "56" → "1,234.56")
|
||||
// Merge consecutive value parts (e.g. "-" + "12" + "." + "00" → "-12.00")
|
||||
if (type === "value" && last?.type === "value") {
|
||||
last.value += part.value;
|
||||
} else {
|
||||
@@ -253,6 +255,7 @@ const computeStateToPartsFromEntityAttributes = (
|
||||
"conversation",
|
||||
"event",
|
||||
"image",
|
||||
"infrared",
|
||||
"input_button",
|
||||
"notify",
|
||||
"scene",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user