feat: 2.5D stage 6 — public setting, raised tiles, soft sun, theme-free walls (#649)

- settings.volumetric_view (General settings › Display, third switch) replaces
  the alpha entry, the header projection toggle and the phone-menu item; one
  rule for card, sidebar page and kiosk; editors stay Flat; backend accepts
  only a boolean, support package copies it.
- Raised tiles in 2.5D View: no ring, rounded body min(0.275 D, 0.3 h), edge
  0.1 D with the lab filters, ×1.12 size also in layout/collision, lift
  0.075 D, one floor-shadow layer under all markers (theme × floor table),
  frames hugging tile and edge (Alert > Focus > Selected > Hover), forced
  colours without edge and shadow (src/iso-tiles.ts, styles/iso-tiles).
- Soft sun wash instead of projected Flat wedges (src/iso-sun.ts): same gates
  and windows as sun_rays, length from elevation, parallelogram along the sun,
  tone and streaks by floor lightness, sill line.
- Walls take the user's wall colour (top opaque, sides × .77/.68/.60); theme
  rules for walls/openings/labels removed; furniture uses the Flat stroke rule.
- Smokes smoke_iso_tiles/iso_sun/iso_theme_walls/volumetric_setting, 16 new
  mutants, acceptance scenes STAGE6_ACCEPTANCE_SCENARIOS (golden with their
  Linux CI baselines), ACCEPTANCE.md side by side.

Issue: #649
User-Visible: yes
This commit is contained in:
Claude
2026-09-25 18:55:14 +03:00
parent 11a8b623a2
commit e5ab4659f6
164 changed files with 5567 additions and 3764 deletions
+3
View File
@@ -42,6 +42,9 @@ sync across screens.
show temperature, humidity, light state and average LQI.
- **Light and environment.** Room fills, lamp Glow, wall shadows, a day-cycle
backdrop and sunlight through windows.
- **Flat or 2.5D.** One switch in General settings › Display shows the plan
with depth everywhere: raised device tiles with soft floor shadows and a soft
wash of sunlight; decor and wall colours stay as you set them.
- **Doors, windows, gates and vacuums.** Openings follow real contacts and locks;
a robot can show its position, dock and travelled path.
- **Several floors and screens.** Space tabs, swipe navigation, local viewport,
@@ -1,147 +1,147 @@
{
"schema": 1,
"fingerprint": "5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051",
"fingerprint": "873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 291761,
"initialViewGzipBytes": 294004,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 293284,
"initialPanelGzipBytes": 295526,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2326,
"initialPanelOnlyGzipBytes": 2323,
"lazyFiles": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/de-C7gyFGpd.js",
"houseplan-assets/editor-9cyNd7R7.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/fr-BSn1zqYb.js",
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-editor-runtime-DFhn-zc9.js",
"houseplan-assets/houseplan-onboarding-runtime-BiiaK_3r.js",
"houseplan-assets/hp-zigbee-topology-overlay-D7siZQoq.js",
"houseplan-assets/iso-scene-render-xsesUj3A.js",
"houseplan-assets/live-interaction-runtime-DZWBYZP0.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/pdf-export-BYsRpVk_.js",
"houseplan-assets/summary-panel-runtime-loaded-gtNYqb9U.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js",
"houseplan-assets/zigbee-topology-runtime-A7rG7kis.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/de-DHDD9RSi.js",
"houseplan-assets/editor-C20ayYMa.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/fr-Ckenu6AU.js",
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-editor-runtime-DO6W6BMI.js",
"houseplan-assets/houseplan-onboarding-runtime-BBCA2XHL.js",
"houseplan-assets/hp-zigbee-topology-overlay-Dl2pPJ8I.js",
"houseplan-assets/iso-scene-render--t3CP3hz.js",
"houseplan-assets/live-interaction-runtime-C1Lqtmd2.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/pdf-export-DkJQi1qx.js",
"houseplan-assets/summary-panel-runtime-loaded-DfBzT94s.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js",
"houseplan-assets/zigbee-topology-runtime-D4vnCsys.js"
],
"lazyGzipBytes": 449074,
"lazyGzipBytes": 450707,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/editor-9cyNd7R7.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-editor-runtime-DFhn-zc9.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/editor-C20ayYMa.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-editor-runtime-DO6W6BMI.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js"
],
"lazyEditorGzipBytes": 231934,
"lazyEditorGzipBytes": 232048,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-onboarding-runtime-BiiaK_3r.js",
"houseplan-assets/namespace-language-B2Cyshho.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-onboarding-runtime-BBCA2XHL.js",
"houseplan-assets/namespace-language-CH9klpdW.js"
],
"lazyOnboardingGzipBytes": 27899,
"lazyOnboardingGzipBytes": 27942,
"lazyLocaleFiles": [
"houseplan-assets/de-C7gyFGpd.js",
"houseplan-assets/fr-BSn1zqYb.js"
"houseplan-assets/de-DHDD9RSi.js",
"houseplan-assets/fr-Ckenu6AU.js"
],
"lazyLocaleGzipBytes": 55699,
"lazyLocaleGzipBytes": 55684,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-xsesUj3A.js"
"houseplan-assets/iso-scene-render--t3CP3hz.js"
],
"lazyIsometricGzipBytes": 17643,
"lazyIsometricGzipBytes": 19194,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js"
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js"
],
"lazyFurnitureArtGzipBytes": 16940,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/pdf-export-BYsRpVk_.js"
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/pdf-export-DkJQi1qx.js"
],
"lazyPdfGzipBytes": 126827,
"lazyPdfGzipBytes": 126823,
"lazyNamespaceLocaleFiles": [
"houseplan-assets/settings-de-BSeiuZ78.js",
"houseplan-assets/settings-fr-Dqa7IIGC.js",
"houseplan-assets/settings-ru-DTjpLI7z.js",
"houseplan-assets/support-de-DkCHsIJX.js",
"houseplan-assets/support-fr-CF5yiuHl.js",
"houseplan-assets/support-ru-Bs7OI6GX.js",
"houseplan-assets/topology-de-BelPUGaW.js",
"houseplan-assets/topology-fr-FvLCzTYk.js",
"houseplan-assets/topology-ru-DG2M1Xdq.js"
"houseplan-assets/settings-de-7bIn6fNv.js",
"houseplan-assets/settings-fr-3J0EZ_-8.js",
"houseplan-assets/settings-ru-B2uE9Qdz.js",
"houseplan-assets/support-de-e4tT4coj.js",
"houseplan-assets/support-fr-MgvbVMC0.js",
"houseplan-assets/support-ru-C1DPLUn9.js",
"houseplan-assets/topology-de-ClOOC81f.js",
"houseplan-assets/topology-fr-BEqsOvuh.js",
"houseplan-assets/topology-ru-DqFgQJka.js"
],
"lazyNamespaceLocaleGzipBytes": 20887,
"lazyNamespaceLocaleGzipBytes": 21035,
"files": [
{
"path": "houseplan-assets/backdrop-pick-D3-yn5HD.js",
"sha256": "9979ee2d9318b8f709993cc91c77968c12ecfb3c3692a16d2ac3a268d5a752c2",
"rawBytes": 53888,
"gzipBytes": 17524,
"path": "houseplan-assets/backdrop-pick-BpwckQhw.js",
"sha256": "73faa27d8d6147f1853699a33b0e82acc8e71b9b023c7ffdadcd3a8add360d1f",
"rawBytes": 54017,
"gzipBytes": 17573,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js"
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js"
],
"dynamicImports": [
"houseplan-assets/settings-de-BSeiuZ78.js",
"houseplan-assets/settings-fr-Dqa7IIGC.js",
"houseplan-assets/settings-ru-DTjpLI7z.js"
"houseplan-assets/settings-de-7bIn6fNv.js",
"houseplan-assets/settings-fr-3J0EZ_-8.js",
"houseplan-assets/settings-ru-B2uE9Qdz.js"
]
},
{
"path": "houseplan-assets/de-C7gyFGpd.js",
"sha256": "eed3905d3c370c5071e7074d4753a769efd3d37d263f21cee2a135ef0dbd6a2c",
"rawBytes": 93083,
"gzipBytes": 28075,
"path": "houseplan-assets/de-DHDD9RSi.js",
"sha256": "9bdaeed82764cae9cfa892d5d25fd256521529734c8b8f926f5cbd02158ef81a",
"rawBytes": 93055,
"gzipBytes": 28066,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-9cyNd7R7.js",
"sha256": "e49468af916efc53baab7dd87825f20b2b2b957dbcae134cfa493e0c9b08ae3a",
"path": "houseplan-assets/editor-C20ayYMa.js",
"sha256": "8febc098ce99ba98bf63839018a796f3f352f2475f00f39b7fe6a4640e71e238",
"rawBytes": 3833,
"gzipBytes": 1583,
"gzipBytes": 1579,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/form-kit.styles-BJpA5NGj.js",
"sha256": "e07f6da05bf8bff00363bc559c8f9ac2c7acc93d0141d37a7570bd02ec1192ca",
"path": "houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"sha256": "74900fd040f932d8c4100fb9576fa0b8313c3a8c130c185c8404ed1f676c24bf",
"rawBytes": 25600,
"gzipBytes": 5056,
"gzipBytes": 5055,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-BSn1zqYb.js",
"sha256": "f0b4b416865b978983c49e1b3321ca3d6f3956a43f7b1576d23e2d81b1a80148",
"rawBytes": 95424,
"gzipBytes": 27624,
"path": "houseplan-assets/fr-Ckenu6AU.js",
"sha256": "6c5a42ee80df955da1453e54ae1ba57b4bf747e21f5574e354a7bef7a867c5b5",
"rawBytes": 95410,
"gzipBytes": 27618,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"sha256": "b5e9e8743651feb5c515d986581bd860a2184d7d64a7744b53acd0c6d7ed0327",
"path": "houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"sha256": "6fe377da376ecdf2bc8274bfe7ae2b68d08b9117ca977e52c174b0e8eb45ac58",
"rawBytes": 52035,
"gzipBytes": 16940,
"isEntry": false,
@@ -149,288 +149,288 @@
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-BCYl6SkQ.js",
"sha256": "6df593e8f6479b0bedf505c29a41a20b4bf53a5977b45e0bf3165400fd3769e0",
"rawBytes": 1030968,
"gzipBytes": 290958,
"path": "houseplan-assets/houseplan-card-bZxsrUlk.js",
"sha256": "cd98d8c4853c8319cbe23cbf4051601f3283a348e468c324ecd0ca25603eb391",
"rawBytes": 1037668,
"gzipBytes": 293203,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-C7gyFGpd.js",
"houseplan-assets/editor-9cyNd7R7.js",
"houseplan-assets/fr-BSn1zqYb.js",
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-editor-runtime-DFhn-zc9.js",
"houseplan-assets/houseplan-onboarding-runtime-BiiaK_3r.js",
"houseplan-assets/hp-zigbee-topology-overlay-D7siZQoq.js",
"houseplan-assets/iso-scene-render-xsesUj3A.js",
"houseplan-assets/live-interaction-runtime-DZWBYZP0.js",
"houseplan-assets/pdf-export-BYsRpVk_.js",
"houseplan-assets/summary-panel-runtime-loaded-gtNYqb9U.js"
"houseplan-assets/de-DHDD9RSi.js",
"houseplan-assets/editor-C20ayYMa.js",
"houseplan-assets/fr-Ckenu6AU.js",
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-editor-runtime-DO6W6BMI.js",
"houseplan-assets/houseplan-onboarding-runtime-BBCA2XHL.js",
"houseplan-assets/hp-zigbee-topology-overlay-Dl2pPJ8I.js",
"houseplan-assets/iso-scene-render--t3CP3hz.js",
"houseplan-assets/live-interaction-runtime-C1Lqtmd2.js",
"houseplan-assets/pdf-export-DkJQi1qx.js",
"houseplan-assets/summary-panel-runtime-loaded-DfBzT94s.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-DFhn-zc9.js",
"sha256": "c0a4a8e337a3e13b0df19eb57938c185d504e6ed89854d514585cd00b4f40197",
"rawBytes": 667315,
"gzipBytes": 186120,
"path": "houseplan-assets/houseplan-editor-runtime-DO6W6BMI.js",
"sha256": "c7176f391361aeb1fc7367851326614c8cc9bb2b5cc00c1ab36a469a628918fc",
"rawBytes": 667537,
"gzipBytes": 186196,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js"
],
"dynamicImports": [
"houseplan-assets/support-de-DkCHsIJX.js",
"houseplan-assets/support-fr-CF5yiuHl.js",
"houseplan-assets/support-ru-Bs7OI6GX.js",
"houseplan-assets/zigbee-topology-runtime-A7rG7kis.js"
"houseplan-assets/support-de-e4tT4coj.js",
"houseplan-assets/support-fr-MgvbVMC0.js",
"houseplan-assets/support-ru-C1DPLUn9.js",
"houseplan-assets/zigbee-topology-runtime-D4vnCsys.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-BiiaK_3r.js",
"sha256": "0d13b9bc17fc152738912ddfb30d0fd8247984c80286cbd6b82d6609c99bff48",
"path": "houseplan-assets/houseplan-onboarding-runtime-BBCA2XHL.js",
"sha256": "8f0f995a25353390d06019250a9e3e28d8b3493571199405cde461a30efc0266",
"rawBytes": 15886,
"gzipBytes": 4909,
"gzipBytes": 4906,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-D7siZQoq.js",
"sha256": "0254f89b26d8b337c1c4939931cf72938089a0ea326199235320348ff6e085f9",
"path": "houseplan-assets/hp-zigbee-topology-overlay-Dl2pPJ8I.js",
"sha256": "54909e305c1f4b630ca5090fd4d4c43e90009bd9e06e262feb3d86f74fff922a",
"rawBytes": 10958,
"gzipBytes": 3765,
"gzipBytes": 3763,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js",
"houseplan-assets/zigbee-topology-runtime-A7rG7kis.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js",
"houseplan-assets/zigbee-topology-runtime-D4vnCsys.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-xsesUj3A.js",
"sha256": "4f41caad95b99d01013048852c1aa4c147959a8ef10a906dde51f45808e87905",
"rawBytes": 51983,
"gzipBytes": 17643,
"path": "houseplan-assets/iso-scene-render--t3CP3hz.js",
"sha256": "aaf1a1936d043e252a00c1bf6aec427b46a6848262c30224d57f10bc2ce9a72e",
"rawBytes": 56457,
"gzipBytes": 19194,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-DZWBYZP0.js",
"sha256": "aac5a7823e6fd097be076d62534e9b9f1c4290f36b92033d59bf1cac891da300",
"path": "houseplan-assets/live-interaction-runtime-C1Lqtmd2.js",
"sha256": "4def845e9f45a32e1246534620b69bdde9a639dcb0f83cbdfa8ab0e2b63cd4ea",
"rawBytes": 8216,
"gzipBytes": 3207,
"gzipBytes": 3203,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/namespace-language-B2Cyshho.js",
"sha256": "5934f29831a1aecc9503f9afdc8559844dc39e09474b51d26cc917965f27faac",
"path": "houseplan-assets/namespace-language-CH9klpdW.js",
"sha256": "671c38708202959ac0a77814a2d1555372967d4dda7fe4b5c32d9902ec90a38e",
"rawBytes": 675,
"gzipBytes": 410,
"gzipBytes": 408,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-BYsRpVk_.js",
"sha256": "7a4a4d2130fb379cd99681cb6a843e10f81d954bf3c6146d1843bdc9b29027b9",
"path": "houseplan-assets/pdf-export-DkJQi1qx.js",
"sha256": "855a39c362621d9bb1e334934fdd77e880ce63ac5d1f241f1051f5e18608245f",
"rawBytes": 236264,
"gzipBytes": 109887,
"gzipBytes": 109883,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-de-BSeiuZ78.js",
"sha256": "e097b530727671f7473cc5288ae1d71124fa51afb4e4b26e35114d10b2b18e8d",
"rawBytes": 7248,
"gzipBytes": 2825,
"path": "houseplan-assets/settings-de-7bIn6fNv.js",
"sha256": "b0f3a58013cb87b75ef1204fc80c6def3994d6ada06af39a84491ada95ab3afb",
"rawBytes": 7378,
"gzipBytes": 2877,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-fr-Dqa7IIGC.js",
"sha256": "b5597e3b95028ddd220c4bf7b2566455aa5e403d9a3ad2a55dc110cecdc6a33f",
"rawBytes": 7483,
"gzipBytes": 2786,
"path": "houseplan-assets/settings-fr-3J0EZ_-8.js",
"sha256": "d050ba5296b7a18653cbe9776e43ff7d1200ef532ccd24b45ed009570b6f49d6",
"rawBytes": 7620,
"gzipBytes": 2838,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-ru-DTjpLI7z.js",
"sha256": "20b462a7368412ce5c2a5ad378177c963894c6afe8b2a642ae8686477f5e5771",
"rawBytes": 10128,
"gzipBytes": 3271,
"path": "houseplan-assets/settings-ru-B2uE9Qdz.js",
"sha256": "e4a8e3938f2b5d2e66ef2a0c2d31d4afadc51cfe983a0d909453313cb2771aa2",
"rawBytes": 10304,
"gzipBytes": 3323,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-BVcF5FC3.js",
"sha256": "3b55c2b18035ea7d9861e5c1516d9c3a6443a6c042c2943dc2064ef2a51ed09e",
"path": "houseplan-assets/summary-panel-editor-BFR2i2yH.js",
"sha256": "21c2ee89fcea66c547587c57c11beb637f4547fe69befcd1759dbb637e833d6f",
"rawBytes": 14862,
"gzipBytes": 3427,
"gzipBytes": 3423,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/summary-panel-runtime-loaded-gtNYqb9U.js"
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/summary-panel-runtime-loaded-DfBzT94s.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-D9g7eyWm.js",
"sha256": "ca53545e64213080520b779bd051d90e9a6e2d053656fdf2c2ca734b6b9e5982",
"path": "houseplan-assets/summary-panel-metrics-CWPDsUxL.js",
"sha256": "2379e09e9044ffe8f510ac9e46cfc23882b941c557af7be9eac415762e5135cf",
"rawBytes": 2611,
"gzipBytes": 1305,
"gzipBytes": 1304,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-gtNYqb9U.js",
"sha256": "352dc342aca3222c76a922e010001ddc35e22d04c412093d5b294e9b67ab36ff",
"path": "houseplan-assets/summary-panel-runtime-loaded-DfBzT94s.js",
"sha256": "2cb58d8d4a8372e3d6b77cd9e976b072b8bd4869e1fb8d87df14dbef1def50d7",
"rawBytes": 72956,
"gzipBytes": 20242,
"gzipBytes": 20240,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-BVcF5FC3.js",
"houseplan-assets/summary-panel-metrics-D9g7eyWm.js"
"houseplan-assets/summary-panel-editor-BFR2i2yH.js",
"houseplan-assets/summary-panel-metrics-CWPDsUxL.js"
]
},
{
"path": "houseplan-assets/support-de-DkCHsIJX.js",
"sha256": "9bcaa6f84b2df92ccf9b26714a4132d9973efa598b93b25a966ffd290f80c00f",
"path": "houseplan-assets/support-de-e4tT4coj.js",
"sha256": "c9122b8dbc222af6542450f69092286e5c03c06fb48ccfe21fabed394f40a1af",
"rawBytes": 6167,
"gzipBytes": 2396,
"gzipBytes": 2395,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/support-fr-CF5yiuHl.js",
"sha256": "967d72d645f5cd641e4a4d4fae7bf05a6b6a3752545a60c6981ae26c58c008b9",
"path": "houseplan-assets/support-fr-MgvbVMC0.js",
"sha256": "1897e5cded25ce49deb4083c47387c5b3ed84b13c10f37f574578480e7b21207",
"rawBytes": 6333,
"gzipBytes": 2430,
"gzipBytes": 2428,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/support-ru-Bs7OI6GX.js",
"sha256": "63db0be43cdf00a66f24704ecba11224d6cba775fde57b8121a541be991360c3",
"path": "houseplan-assets/support-ru-C1DPLUn9.js",
"sha256": "befc222fa2ea788903bf8fb92e43020c4eae257b057abf09b7ec45f77183bcea",
"rawBytes": 8376,
"gzipBytes": 2875,
"gzipBytes": 2874,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-de-BelPUGaW.js",
"sha256": "6278b6aa3c8ddbb36ebc7ce6fb2b506ab2e6071814e5c78cd6f5241ee81b646b",
"path": "houseplan-assets/topology-de-ClOOC81f.js",
"sha256": "9df4fc278b2f0292026839bc65714843db1c33fcd70e504f41e17840f07fc1be",
"rawBytes": 2698,
"gzipBytes": 1336,
"gzipBytes": 1335,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-fr-FvLCzTYk.js",
"sha256": "40ba15894ef18ef7566796a2cdb21bc8ad82f855c27556e4868d53f39e2fb146",
"path": "houseplan-assets/topology-fr-BEqsOvuh.js",
"sha256": "e5db08f5ade4a3cf6bc9e9d12cfe2d7a2b27b367447da7fe60e0a60d0f251d23",
"rawBytes": 2718,
"gzipBytes": 1354,
"gzipBytes": 1352,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-ru-DG2M1Xdq.js",
"sha256": "e885da0310e6fe62f7b26a3fc8559d857bc03a5c1164146227b59a0532c6994f",
"path": "houseplan-assets/topology-ru-DqFgQJka.js",
"sha256": "1b15021ed72287230896d924d7a229f21aa39ca7a20a8ca3ded1593001da6e1e",
"rawBytes": 3669,
"gzipBytes": 1614,
"gzipBytes": 1613,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-CvQsfSze.js",
"sha256": "e50d18bdc8333469cb81de65c7cbc1f7fc30f47820d90256835c20244e56c9fa",
"path": "houseplan-assets/zigbee-topology-CHnDBF-n.js",
"sha256": "0ff68cb954bbf16359a2c8990c0ddc4f39d7ffa3c51fca4c817eac85fb6e9aa7",
"rawBytes": 10958,
"gzipBytes": 4301,
"gzipBytes": 4297,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js"
],
"dynamicImports": [
"houseplan-assets/topology-de-BelPUGaW.js",
"houseplan-assets/topology-fr-FvLCzTYk.js",
"houseplan-assets/topology-ru-DG2M1Xdq.js"
"houseplan-assets/topology-de-ClOOC81f.js",
"houseplan-assets/topology-fr-BEqsOvuh.js",
"houseplan-assets/topology-ru-DqFgQJka.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-runtime-A7rG7kis.js",
"sha256": "ff4fa95e61e5b87f04b9dbfdb5e4db560039b705ce85a78e0f88c5cc3fe752bf",
"path": "houseplan-assets/zigbee-topology-runtime-D4vnCsys.js",
"sha256": "77d6b691983e517a1d03da1ef1ea3dd5ebe758a665ed1a895da5ce7c960ec177",
"rawBytes": 3983,
"gzipBytes": 1788,
"gzipBytes": 1786,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "da2699ffc51cdc95977a044aafa7ef32645f69eb58311b994d2d578b8697c2c0",
"sha256": "450c1b3ec296407b49219c48890fba431953641a025443e8b0ad27de9714c4ee",
"rawBytes": 1205,
"gzipBytes": 803,
"gzipBytes": 801,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "07baa17cfdd3db6f04aa5027c5796f623976bf6a4e5282255123474d79cd35b2",
"sha256": "ee244a5534da502ce154608cf98907560c7b4f78aba1721a4189b391b6d0d7bc",
"rawBytes": 6165,
"gzipBytes": 2326,
"gzipBytes": 2323,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,14 +1,14 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{aD as e,l as o,aG as t,ee as s,A as a,ef as i,eg as l,eh as n,E as r,c}from"./houseplan-card-BCYl6SkQ.js";class f extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,f={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},h=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{aD as e,l as o,aG as t,ek as s,A as a,el as i,em as l,en as n,E as r,c}from"./houseplan-card-bZxsrUlk.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
.computeLabel=${e=>f[e.name]||e.name}
.computeLabel=${e=>h[e.name]||e.name}
@value-changed=${this._valueChanged}
></ha-form>`;return c`
${d(h.slice(0,3))}
${d(f.slice(0,3))}
${_?c`<div class="default-floor-error" role="alert"
style="color:var(--error-color,#db4437);margin:-4px 0 12px;overflow-wrap:anywhere">
${t(s,"editor.default_floor_missing",{id:_})}
</div>`:a}
${d(h.slice(3))}
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}f.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",f);
${d(f.slice(3))}
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}h.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",h);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{ej as e,ek as a,eg as n}from"./houseplan-card-BCYl6SkQ.js";function o(n,o){return new e([{code:"en",dictionary:n},{code:"ru",loadDictionary:o.ru},{code:"de",loadDictionary:o.de},{code:"fr",loadDictionary:o.fr}],"5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051",console.warn,a)}function r(e){return function(e,a){return{state:n=>{const o=e.state(n);return"pending"!==o&&a.some(e=>"pending"===e.state(n))?"pending":o},dictionary:a=>e.dictionary(a),ensure:n=>Promise.all([e,...a].map(e=>e.ensure(n))).then(()=>{})}}(n,e)}export{o as n,r as s};
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{ep as e,eq as n,em as c}from"./houseplan-card-bZxsrUlk.js";function a(c,a){return new e([{code:"en",dictionary:c},{code:"ru",loadDictionary:a.ru},{code:"de",loadDictionary:a.de},{code:"fr",loadDictionary:a.fr}],"873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c",console.warn,n)}function o(e){return function(e,n){return{state:c=>{const a=e.state(c);return"pending"!==a&&n.some(e=>"pending"===e.state(c))?"pending":a},dictionary:n=>e.dictionary(n),ensure:c=>Promise.all([e,...n].map(e=>e.ensure(c))).then(()=>{})}}(c,e)}export{a as n,o as s};
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{c as a,A as e}from"./houseplan-card-BCYl6SkQ.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-gtNYqb9U.js";import"./form-kit.styles-BJpA5NGj.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{c as a,A as e}from"./houseplan-card-bZxsrUlk.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-DfBzT94s.js";import"./form-kit.styles-ZNkFBfYu.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{em as e,N as t,b2 as n,L as i,ae as o,ac as r,bY as s,bX as a,b1 as c,b0 as l,b3 as u,en as d,eo as f,b_ as m,ep as g}from"./houseplan-card-BCYl6SkQ.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,u="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*p(c,l,u=_){try{let d=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;d+=a(v)*_*_/1e4}return d}catch{return null}}function h(e,t,n=_){const i=p(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function b(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{p as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,b as summarySystemValue,h as totalCleanFloorAreaM2};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{es as e,N as t,b2 as n,L as i,ae as o,ac as r,bZ as s,bY as a,b1 as c,b0 as l,b3 as u,et as d,eu as f,b$ as m,ev as g}from"./houseplan-card-bZxsrUlk.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,u="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(c,l,u=_){try{let d=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;d+=a(v)*_*_/1e4}return d}catch{return null}}function h(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function p(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,p as summarySystemValue,h as totalCleanFloorAreaM2};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";var e={title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"};const n="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";export{e as dictionary,n as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";var e={title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"};const n="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";export{e as dictionary,n as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";var e={title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"};const s="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";export{e as dictionary,s as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";var e={title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"};const s="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";export{e as dictionary,s as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";var e={title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"};const a="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";export{e as dictionary,a as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";var e={title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"};const t="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";export{e as dictionary,t as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{n as t,c as n}from"./zigbee-topology-CvQsfSze.js";import{aM as e}from"./houseplan-card-BCYl6SkQ.js";import"./namespace-language-B2Cyshho.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function p(t){if(!0!==t?.user?.is_admin)throw a("permission")}function f(n){const e=i(n);return e?c(e,"zha",async()=>{if(p(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(p(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,f=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{f=t,g=n}),v=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&v.push(r);const p=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&f?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof p&&v.push(p),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const b=await m(w,s-Date.now()),_=d(b)?.status;if(_&&"ok"!==_)throw a("provider");return n(b,l)}finally{for(const t of v)try{t()}catch{}}})}export{f as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{n as t,c as n}from"./zigbee-topology-CHnDBF-n.js";import{aM as e}from"./houseplan-card-bZxsrUlk.js";import"./namespace-language-CH9klpdW.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function p(t){if(!0!==t?.user?.is_admin)throw a("permission")}function f(n){const e=i(n);return e?c(e,"zha",async()=>{if(p(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(p(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,f=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{f=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const p=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&f?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof p&&b.push(p),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{f as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";try{await import("./houseplan-assets/houseplan-card-BCYl6SkQ.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";try{await import("./houseplan-assets/houseplan-card-bZxsrUlk.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
File diff suppressed because one or more lines are too long
@@ -155,6 +155,9 @@ def _global_settings(value: object) -> dict[str, Any]:
show_room_tooltip = value.get("show_room_tooltip")
if isinstance(show_room_tooltip, bool):
out["show_room_tooltip"] = show_room_tooltip
volumetric_view = value.get("volumetric_view")
if isinstance(volumetric_view, bool):
out["volumetric_view"] = volumetric_view
fill_colors = value.get("fill_colors")
if isinstance(fill_colors, dict):
palette = {
@@ -2254,6 +2254,8 @@ CONFIG_SCHEMA = vol.All(
vol.Optional("sun_rays"): bool,
vol.Optional("sun_ray_origin"): _SUN_RAY_ORIGIN,
vol.Optional("show_room_tooltip"): bool,
# #649: installation-wide 2.5D View; absent/false keeps Flat.
vol.Optional("volumetric_view"): bool,
vol.Optional("summary_panel"): SUMMARY_PANEL_WIRE_SCHEMA,
vol.Optional("radar"): vol.Schema({}, extra=vol.ALLOW_EXTRA),
# Removed from the UI/runtime in 2026-08-08. Keep accepting the
+13 -1
View File
@@ -291,6 +291,9 @@ try {
fixture.config.spaces.map((space) => [space.id, 'iso']),
)));
history.replaceState(null, '', '?hp_alpha=1');
// #649: current bundles read the installation setting; the alpha
// storage above stays for comparison bundles before it.
fixture.config.settings = { ...(fixture.config.settings || {}), volumetric_view: true };
} else history.replaceState(null, '', location.pathname);
const host = document.getElementById('host');
const card = document.createElement('houseplan-card');
@@ -386,7 +389,7 @@ try {
throw new Error('large-house editor runtime did not preload');
if (isometric) await ensureIsoRuntime(card);
window.__hpAssertCardContract(card, cardContract);
if (requiresIsometric && (typeof card._setProjection !== 'function'
if (requiresIsometric && (typeof card._effectiveProjection !== 'function'
|| !(card._isoGeometryCache instanceof Map))) {
throw new Error('large-house-isometric-v1 candidate has no renderer contract');
}
@@ -445,11 +448,20 @@ try {
}
const viewToggle = isometric ? await duration(async () => {
if (typeof card._setProjection === 'function') {
// Comparison bundles before #649: the per-device alpha preference.
card._setProjection('flat');
await card.updateComplete;
card._setProjection('iso');
await ensureIsoRuntime(card);
await card.updateComplete;
} else if (typeof card._syncVolumetricSetting === 'function') {
// #649: the installation-wide General settings switch, as a save applies it.
const cfg = card._serverCfg;
card._serverCfg = { ...cfg, settings: { ...(cfg.settings || {}), volumetric_view: false } };
await card.updateComplete;
card._serverCfg = { ...cfg, settings: { ...(cfg.settings || {}), volumetric_view: true } };
await ensureIsoRuntime(card);
await card.updateComplete;
} else {
// Comparison SHAs before #89 intentionally ignore the Labs operation.
card.requestUpdate();
+21
View File
@@ -0,0 +1,21 @@
// #649 AC12: product frames for docs/design/649-25d-stage6/ACCEPTANCE.md.
// Diagnostic, not golden (#455): run on a built bundle, compare by eye with the
// lab frames of sketch 07.
//
// npm run build && npm run bundle:sync
// node demo/capture_stage6_acceptance_649.mjs [out-dir]
import { mkdirSync } from 'node:fs';
import { launch } from './serve.mjs';
import { goldenClip, prepareGoldenScenario } from './golden/harness.mjs';
import { STAGE6_ACCEPTANCE_SCENARIOS } from './golden/matrix.mjs';
const out = process.argv[2] || 'artifacts/stage6-acceptance';
mkdirSync(out, { recursive: true });
const { page, browser } = await launch({ width: 1000, height: 900 }, 1);
for (const scenario of STAGE6_ACCEPTANCE_SCENARIOS) {
await prepareGoldenScenario(page, scenario);
await page.waitForTimeout(2600); // the sun wash fades in over 2 s
await page.screenshot({ path: `${out}/${scenario.id}.png`, clip: await goldenClip(page, scenario.capture) });
console.log('captured', scenario.id);
}
await browser.close();
+14 -15
View File
@@ -696,6 +696,13 @@ export function prepareGoldenFixture(scenario) {
sun_ray_origin: scenario.sunRayOrigin,
};
}
// #649: the user's wall colour is global (General settings › Plan).
if (scenario.wallFill) {
fixture.config.settings = {
...(fixture.config.settings || {}),
fill_colors: { ...(fixture.config.settings?.fill_colors || {}), wall_fill: scenario.wallFill },
};
}
if (scenario.extraOpenings?.length) {
const space = requireSpace();
const known = new Set((space.openings || []).map((opening) => opening.id));
@@ -862,6 +869,11 @@ export function prepareGoldenFixture(scenario) {
}];
}
// #649: 2.5D is the installation-wide General settings switch, not alpha.
if (scenario.projection === 'iso') {
fixture.config.settings = { ...(fixture.config.settings || {}), volumetric_view: true };
}
return fixture;
}
@@ -911,15 +923,7 @@ export async function prepareGoldenScenario(page, scenario) {
document.getElementById('golden-pdf-page')?.remove();
localStorage.clear();
const scenarioPath = scenario.panelHost ? '/houseplan' : '/demo.html';
history.replaceState(null, '', `${scenarioPath}${scenario.alpha ? '?hp_alpha=1' : ''}`);
if (scenario.alpha) {
localStorage.setItem('houseplan_card_alpha_v1', '1');
}
if (scenario.projection && scenario.space) {
localStorage.setItem('houseplan_card_view_v1', JSON.stringify({
[scenario.space]: scenario.projection,
}));
}
history.replaceState(null, '', scenarioPath);
const host = document.getElementById('host');
const cardConfig = {
type: 'custom:houseplan-card', title: `Golden ${scenario.id}`,
@@ -1014,10 +1018,6 @@ export async function prepareGoldenScenario(page, scenario) {
throw new Error(`golden furniture artwork missing: ${scenario.id} (${drawn}/${expectedFurniture})`);
}
}
if (scenario.alpha
&& (window.__hpAlpha !== true || JSON.stringify(window.__hpLabs) !== '["iso"]')) {
throw new Error(`alpha contract did not activate isometric capability: ${scenario.id}`);
}
if (scenario.projection === 'iso' || scenario.stage3Golden) {
await ensureIsoRuntime(card);
}
@@ -1265,8 +1265,7 @@ export async function prepareGoldenScenario(page, scenario) {
throw new Error(`golden room-label parity core is incomplete: ${scenario.id}`);
}
}
if (scenario.projection === 'iso' && typeof card._setProjection === 'function') {
card._setProjection('iso');
if (scenario.projection === 'iso') {
await ensureIsoRuntime(card);
await card.updateComplete;
await frame();
+56 -12
View File
@@ -265,28 +265,28 @@ export const GOLDEN_SCENARIOS = Object.freeze([
cornerSplitWall: 'zero-taper', mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-geometry-view-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
// Stage 2 material/floor-edge plus door, window, gate and nested-room coverage.
alpha: true, projection: 'iso',
projection: 'iso',
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-geometry-view-light', fixture: 'visual', space: 'golden-geometry', mode: 'view',
alpha: true, projection: 'iso',
projection: 'iso',
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-live-layers-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
alpha: true, projection: 'iso',
projection: 'iso',
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-no-borders-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
alpha: true, projection: 'iso', showBorders: false, fillMode: 'custom',
projection: 'iso', showBorders: false, fillMode: 'custom',
customFill: { c: '#486a8f', a: 0.42 }, glowEnabled: true,
stage3Golden: { noBorders: true },
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-touch-kiosk-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
alpha: true, projection: 'iso', kiosk: true,
projection: 'iso', kiosk: true,
theme: 'dark', viewport: { width: 390, height: 760 }, ...stage },
{ id: 'isometric-large-warm-remount-dark', fixture: 'large', space: 'perf-floor-2', mode: 'view',
alpha: true, projection: 'iso', warmRemount: true,
projection: 'iso', warmRemount: true,
theme: 'dark', viewport: { width: 1180, height: 900 }, ...stage },
...['light', 'dark'].map((theme) => ({
id: `isometric-stage3-overlays-${theme}`, fixture: 'visual',
space: 'golden-lighting', mode: 'view', alpha: true, projection: 'iso',
space: 'golden-lighting', mode: 'view', projection: 'iso',
stage3Fixture: {
roomMetrics: true, lockOpening: 'light-door', lockState: 'locked',
newDevice: 'golden-presence',
@@ -331,7 +331,7 @@ export const GOLDEN_SCENARIOS = Object.freeze([
theme, viewport: { width: 1000, height: 900 }, ...stage,
})),
{ id: 'isometric-stage3-openings-dark', fixture: 'visual',
space: 'golden-lighting', mode: 'view', alpha: true, projection: 'iso',
space: 'golden-lighting', mode: 'view', projection: 'iso',
showNames: false, glowEnabled: false, sunRays: false,
stage3Fixture: { lockOpening: 'light-door', lockState: 'unlocked' },
extraOpenings: [{
@@ -345,7 +345,7 @@ export const GOLDEN_SCENARIOS = Object.freeze([
},
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-stage3-forced-colors-dark', fixture: 'visual',
space: 'golden-lighting', mode: 'view', alpha: true, projection: 'iso',
space: 'golden-lighting', mode: 'view', projection: 'iso',
forcedColors: true,
stage3Fixture: { roomMetrics: true, lockOpening: 'light-door', lockState: 'locked' },
stage3Golden: {
@@ -355,7 +355,7 @@ export const GOLDEN_SCENARIOS = Object.freeze([
layoutOverrides: stage3DenseLayout,
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-stage3-no-filter-dark', fixture: 'visual',
space: 'golden-lighting', mode: 'view', alpha: true, projection: 'iso',
space: 'golden-lighting', mode: 'view', projection: 'iso',
disableIsoFilters: true,
stage3Fixture: { roomMetrics: true, lockOpening: 'light-door', lockState: 'locked' },
stage3Golden: {
@@ -555,7 +555,7 @@ export const GOLDEN_SCENARIOS = Object.freeze([
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-wall-junctions-dark', fixture: 'visual',
space: 'golden-wall-junctions', wallJunctions: true, mode: 'view',
alpha: true, projection: 'iso',
projection: 'iso',
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'opening-placement-door-thick-wall-dark', fixture: 'visual', space: 'golden-geometry',
// The shared centre edge is a long 25 cm physical wall. It can contain the
@@ -582,7 +582,7 @@ export const GOLDEN_SCENARIOS = Object.freeze([
mode: 'view', openingSymbolContract: openingFlipContract,
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'isometric-opening-symbol-parity-dark', fixture: 'visual', space: 'golden-opening-symbols',
mode: 'view', alpha: true, projection: 'iso',
mode: 'view', projection: 'iso',
openingSymbolContract: openingIsoContract,
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
{ id: 'geometry-devices-editor-dark', fixture: 'visual', space: 'golden-geometry', mode: 'devices',
@@ -1195,3 +1195,47 @@ export const GOLDEN_SCENARIOS = Object.freeze([
cardEditorInvalidDefaultFloor: 'removed-floor', language: 'ru', theme: 'dark',
viewport: { width: 900, height: 760 }, ...page },
]);
/**
* #649 Stage 6 acceptance scenes (docs/design/649-25d-stage6/ACCEPTANCE.md):
* tiles, floor shadows, soft sun wash and theme-free walls in the four
* theme × floor combinations of the approved sketch 07 (attachments 09, 10,
* 12, 13) plus the lifted hover frame (attachment 11); sun as the lab default
* 10:00. They join GOLDEN_SCENARIOS in the same class D commit as their
* baselines captured on Linux CI (#455): every matrix scene needs a reviewed
* baseline (test/golden-wsl-artifact.test.mjs, #641), and a baseline cannot be
* captured before the scene exists. Until then they drive the diagnostic
* side-by-side frames only.
*/
export const STAGE6_ACCEPTANCE_SCENARIOS = Object.freeze([
...[['light', 'light'], ['light', 'dark'], ['dark', 'dark'], ['dark', 'light']].map(([theme, floor]) => ({
id: `isometric-stage6-${theme}-${floor}floor`, fixture: 'visual',
space: 'golden-lighting', mode: 'view', projection: 'iso',
stage3Fixture: { roomMetrics: true, lockOpening: 'light-door', lockState: 'locked' },
stage3Golden: { requiredKinds: stage3RequiredOverlays },
markerOverrides: stage3DenseMarkers,
layoutOverrides: stage3DenseLayout,
stateOverrides: {
'light.golden_light_one': { attributes: { lqi: 40 } },
'light.golden_light_two': { attributes: { lqi: 120 } },
'sensor.golden_right_linkquality': { state: '210' },
'sun.sun': { attributes: { azimuth: 150, elevation: 52 } },
},
fillMode: 'custom', customFill: { c: floor === 'light' ? '#eee8de' : '#737777', a: 1 },
glowEnabled: false, sunRays: true, northDeg: 180,
// The lab's walls are the default white; the colour is the user's either way.
wallFill: { c: '#ffffff', a: 1 },
theme, viewport: { width: 1000, height: 900 }, ...stage,
})),
{ id: 'isometric-stage6-hover-light', fixture: 'visual',
space: 'golden-lighting', mode: 'view', projection: 'iso',
stage3Fixture: { roomMetrics: true, lockOpening: 'light-door', lockState: 'locked' },
stage3Golden: { requiredKinds: stage3RequiredOverlays },
markerOverrides: stage3DenseMarkers,
layoutOverrides: stage3DenseLayout,
fillMode: 'custom', customFill: { c: '#eee8de', a: 1 },
glowEnabled: false, sunRays: false,
hoverDevice: 'golden-light-two',
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage,
},
]);
+19
View File
@@ -204,6 +204,25 @@ export function installHpTest(selectors) {
return rev;
},
/**
* #649: 2.5D is the installation-wide «General settings › Display» switch.
* Delivered the way another client's save arrives (setServerConfig keeps
* the card's current config); the oracle is the rendered stage class.
*/
async setVolumetricView(on = true) {
const c = need('setVolumetricView');
await facade.setServerConfig((cfg) => {
cfg.settings = { ...(cfg.settings || {}), volumetric_view: !!on };
return cfg;
});
const stage = () => rootOf(c)?.querySelector('.stage');
await waitFor('setVolumetricView',
() => !!stage() && stage().classList.contains('projection-iso') === !!on,
() => `вид не стал ${on ? '2.5D' : 'Flat'} (.stage: ${stage()?.className || 'нет'})`,
10000);
await settled();
},
/** То же для раскладки: событие houseplan_layout_updated (у карточки дебаунс 200 мс). */
async setLayout(next) {
const c = need('setLayout');
+18
View File
@@ -19,5 +19,23 @@ export async function installHarnessIsoRuntimeHelper(page) {
await new Promise((done) => requestAnimationFrame(() => requestAnimationFrame(done)));
return true;
};
/**
* #649: select Flat or 2.5D for geometry smokes. Current bundles read the
* installation-wide `settings.volumetric_view`; this assigns it exactly as a
* General settings save does (`_serverCfg = { ...cfg, settings }`, spaces
* untouched, so a smoke's local fixture edits survive). Bundles before
* #649 keep their per-device `_setProjection`.
*/
window.__hpHarnessProjection = async (card, projection) => {
if (typeof card._setProjection === 'function') card._setProjection(projection);
else {
const cfg = card._serverCfg;
card._serverCfg = { ...cfg, settings: { ...(cfg?.settings || {}), volumetric_view: projection === 'iso' } };
card.requestUpdate();
}
await card.updateComplete;
if (projection === 'iso') await window.__hpEnsureHarnessIsoRuntime(card);
await card.updateComplete;
};
});
}
+6 -2
View File
@@ -67,9 +67,13 @@ export const LARGE_HOUSE_CARD_CONTRACT = Object.freeze({
'_effectiveProjection', '_ensureIsoSceneRuntime',
'_isoGeometryCache', '_isoStructuralBuildCount', '_offerWallFaces',
'_liveEditorPaintCount', '_onLabsSnapshot',
'_planSnapGeometryCache', '_roomDialog', '_setProjection', '_wallFaceBatch',
'_planSnapGeometryCache', '_roomDialog', '_syncVolumetricSetting', '_wallFaceBatch',
'_wallFaceGraphCache',
]),
// #649: members that only comparison bundles own. The benchmark feature-probes
// them (`typeof card._setProjection === 'function'`); the current card no
// longer has them, so they are declared but never required.
legacyOnlyFields: Object.freeze(['_setProjection']),
// #380: v1.68.1 owns the same resize session directly on the card; newer
// bundles moved it into ResizeController. A comparison target must expose
// one of the two explicit shapes; the current member retains its object
@@ -111,7 +115,7 @@ export const LARGE_HOUSE_CARD_CONTRACT = Object.freeze({
_planSnapGeometryCache: 'object',
_roomDialog: 'boolean',
_resize: 'object',
_setProjection: 'function',
_syncVolumetricSetting: 'function',
_serverCfg: 'object',
_space: 'string',
_tool: 'string',
+4 -9
View File
@@ -101,13 +101,7 @@ await page.evaluate(async () => {
// raster pair and prove the precision ratio separately below.
runtime._gridLevels = mode === 'view' ? originalGridLevels : () => null;
card._gridLevels = () => runtime._gridLevels();
card._labs = {
...card._labs,
alpha: projection === 'iso',
active: projection === 'iso' ? ['iso'] : [],
};
if (projection === 'iso') await card._ensureIsoSceneRuntime();
card._viewPreference = { ...card._viewPreference, f1: projection };
await window.__hpHarnessProjection(card, projection);
card._isoFallback.clear();
card._isoGeometryCache.clear();
await settle();
@@ -469,9 +463,10 @@ const out = {
isoLightPixelsMatch: pixelEquivalent(isoLightDiff),
isoDarkCriticalMetricsMatch: metricPairsNear(isoDark.reference.metrics, isoDark.detailed.metrics),
isoDarkPixelsMatch: pixelEquivalent(isoDarkDiff),
isoRemainsLabsOnly: referenceView.metrics.projectionToggleCount === 0
// #649: 2.5D is the General settings switch; the card never shows a toggle.
isoHasNoCardToggle: referenceView.metrics.projectionToggleCount === 0
&& isoLight.reference.metrics.projection === 'iso'
&& isoLight.reference.metrics.projectionToggleCount === 1,
&& isoLight.reference.metrics.projectionToggleCount === 0,
};
if (Object.values(out).some((value) => !value)) {
+4 -9
View File
@@ -80,18 +80,14 @@ const out = await page.evaluate(async () => {
await waitMode();
const viewAfterPlanStillHidden = labels().length === 0;
// The Labs registry flag is intentionally expired; use the same dormant
// renderer fixture hook as the canonical Stage 2 smokes.
const active = Object.freeze(['iso']);
card._onLabsSnapshot({ active, space: '' });
window.__hpLabs = active;
// #649: 2.5D through the installation setting (shared harness helper).
await settle();
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
await settle();
const isoFalseHasNoLabels = !!root().querySelector('[data-hp="iso-walls"]')
&& labels().length === 0;
card._setProjection('flat');
await window.__hpHarnessProjection(card, 'flat');
await settle();
await customElements.whenDefined('houseplan-space-card');
@@ -131,8 +127,7 @@ const out = await page.evaluate(async () => {
&& JSON.stringify(card._layout[layoutKey]) === savedLayout;
host.remove();
card._onLabsSnapshot({ active: Object.freeze([]), space: '' });
window.__hpLabs = Object.freeze([]);
await window.__hpHarnessProjection(card, 'flat');
await settle();
return {
+140
View File
@@ -0,0 +1,140 @@
// #649 п.2 (docs/SUN.md «2.5D»): in the 2.5D View the Flat window wedges give
// way to a soft wash along the real sun — the same windows and gates as
// `sun_rays`, length from the elevation, a parallelogram along the sun vector,
// tone and streaks by floor lightness, a sill line. Flat keeps its wedges
// byte for byte; editors and night draw nothing.
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 900, height: 900 });
const res = await page.evaluate(async () => {
const out = {};
const c = window.__card;
const t = window.__hpTest;
const sr = () => c.renderRoot;
const setSun = async (azimuth, elevation) => {
c.hass = { ...c.hass, states: { ...c.hass.states, 'sun.sun': {
entity_id: 'sun.sun', state: elevation > 0 ? 'above_horizon' : 'below_horizon',
attributes: { azimuth, elevation, rising: azimuth <= 180 },
} } };
await t.settled();
};
const setFloor = (color) => t.setServerConfig((cfg) => {
const space = cfg.spaces.find((item) => item.id === 'f1');
space.settings = { ...(space.settings || {}), fill_mode: 'custom', custom_fill: { c: color, a: 1 } };
return cfg;
});
const flatWedges = () => [...sr().querySelectorAll('.sunlayer:not(.iso-sunwash) polygon')];
const wash = () => sr().querySelector('.sunlayer.iso-sunwash');
const beams = () => [...sr().querySelectorAll('.iso-sunwash .iso-sunbeam')];
const litIds = () => beams().map((b) => b.dataset.opening).sort();
const gradientOf = (beam) => {
if (!beam) return null;
const fill = beam.querySelector('.iso-sun-fill')?.getAttribute('fill') || '';
const id = fill.match(/url\(#([^)]+)\)/)?.[1];
return id ? sr().getElementById?.(id) ?? sr().querySelector(`#${id}`) : null;
};
const depthOf = (beam) => {
const g = gradientOf(beam);
if (!g) return NaN;
const n = (name) => Number(g.getAttribute(name));
return Math.hypot(n('x2') - n('x1'), n('y2') - n('y1'));
};
const firstStop = (beam) => {
const stop = gradientOf(beam)?.querySelector('stop');
return stop ? [stop.getAttribute('stop-color'), Number(stop.getAttribute('stop-opacity'))] : null;
};
const shiftSign = (beam) => {
if (!beam) return 0;
// Far edge of the parallelogram relative to its base, along the base line.
const pts = (beam.querySelector('.iso-sun-fill')?.getAttribute('points') || '')
.trim().split(/\s+/).map((p) => p.split(',').map(Number));
const sill = beam.querySelector('.iso-sun-sill');
if (!sill) return 0;
const ax = Number(sill.getAttribute('x1')), bx = Number(sill.getAttribute('x2'));
const cx = pts.reduce((sum, p) => sum + p[0], 0) / (pts.length || 1);
return Math.sign(cx - (ax + bx) / 2);
};
await t.setServerConfig((cfg) => {
const space = cfg.spaces.find((item) => item.id === 'f1');
space.openings = [
{ id: 'wN', type: 'window', x: 0.30, y: 0.14, angle: 0, length: 0.08 },
{ id: 'wE', type: 'window', x: 0.96, y: 0.60, angle: 90, length: 0.08 },
{ id: 'wS', type: 'window', x: 0.30, y: 0.86, angle: 0, length: 0.08 },
{ id: 'wW', type: 'window', x: 0.04, y: 0.30, angle: 90, length: 0.08 },
{ id: 'wI', type: 'window', x: 0.55, y: 0.30, angle: 90, length: 0.08 },
{ id: 'dS', type: 'door', x: 0.20, y: 0.86, angle: 0, length: 0.1 },
];
space.settings = { ...(space.settings || {}), show_borders: true };
cfg.settings = { ...(cfg.settings || {}), sun_rays: true, north_deg: 0 };
return cfg;
});
await setFloor('#737777');
// Flat reference: the wedges and their exact markup.
await setSun(180, 30);
const flatLit = (c._sunRaysCache?.rays || []).map((r) => r.openingId).sort();
const flatMarkup = sr().querySelector('.sunlayer')?.outerHTML ?? '';
out.flatHasWedges = flatWedges().length > 0 && !wash();
await t.setVolumetricView(true);
await setSun(180, 30);
out.washReplacesWedges = !!wash() && flatWedges().length === 0;
out.sameWindowsAsSunRays = JSON.stringify(litIds()) === JSON.stringify(flatLit) && flatLit.length > 0;
out.interiorWindowDark = !litIds().includes('wI');
// Length from the elevation: L(e) ∝ clamp(1.865·(0.55 + 1.4·(1 − e/90)^1.6), 0.98, 4.16).
const L = (e) => Math.min(4.16, Math.max(0.98, 1.865 * (0.55 + 1.4 * (1 - e / 90) ** 1.6)));
await setSun(180, 10);
const low = depthOf(beams().find((b) => b.dataset.opening === 'wS'));
await setSun(180, 60);
const high = depthOf(beams().find((b) => b.dataset.opening === 'wS'));
out.lengthFollowsElevation = Math.abs(low / high - L(10) / L(60)) < 0.01;
// Parallelogram along the sun: the far edge slides the other way when the sun crosses south.
await setSun(150, 30);
const east = shiftSign(beams().find((b) => b.dataset.opening === 'wS'));
await setSun(210, 30);
const west = shiftSign(beams().find((b) => b.dataset.opening === 'wS'));
out.shearFollowsSun = east !== 0 && west === -east;
out.clippedToRoom = beams().every((b) => /url\(#hp-iso-sun-clip-/.test(b.getAttribute('clip-path') || ''));
// Tone by the floor: dark floor warm-white, no streaks; light floor amber with two streaks.
const dark = beams()[0];
out.darkFloorStops = !!dark && JSON.stringify(firstStop(dark)) === JSON.stringify(['#ffe9b4', 0.62])
&& dark.dataset.floor === 'dark';
out.darkFloorNoStreaks = beams().every((b) => b.querySelectorAll('.iso-sun-streak').length === 0);
out.darkFloorSill = beams().every((b) => b.querySelector('.iso-sun-sill')?.getAttribute('stroke') === '#fff3cf');
await setFloor('#eee8de');
await setSun(210, 30);
const light = beams()[0];
out.lightFloorStops = !!light && JSON.stringify(firstStop(light)) === JSON.stringify(['#e2b95e', 0.46])
&& light.dataset.floor === 'light';
out.lightFloorTwoStreaks = beams().length > 0 && beams().every((b) => b.querySelectorAll('.iso-sun-streak').length === 2);
out.lightFloorSill = beams().every((b) => b.querySelector('.iso-sun-sill')?.getAttribute('stroke') === '#efd493');
// Gates of sun_rays: below 3° nothing, night nothing, feature off nothing.
await setSun(180, 2);
out.lowSunHidden = !wash() || wash().classList.contains('out') || beams().length === 0;
await setSun(180, -8);
out.nightEmpty = beams().length === 0 && flatWedges().length === 0;
await t.setServerConfig((cfg) => { cfg.settings = { ...cfg.settings, sun_rays: false }; return cfg; });
await setSun(180, 30);
out.featureOffEmpty = beams().length === 0;
await t.setServerConfig((cfg) => { cfg.settings = { ...cfg.settings, sun_rays: true }; return cfg; });
await setSun(180, 30);
// Editors draw no light.
await t.setMode('plan');
out.editorNoLight = beams().length === 0 && flatWedges().length === 0;
await t.setMode('view');
// Back to Flat: the same wedges, byte for byte.
await setFloor('#737777');
await t.setVolumetricView(false);
await setSun(180, 30);
out.flatWedgesUnchanged = !wash() && (sr().querySelector('.sunlayer')?.outerHTML ?? '') === flatMarkup;
return out;
});
checkAll(res);
await finish(browser, res);
+108
View File
@@ -0,0 +1,108 @@
// #649 п.3 (docs/ISOMETRIC.md, Stage 6): the 2.5D View paints walls in the
// user's wall colour, the theme never repaints walls, openings, the floor edge
// or room labels, and furniture keeps its Flat line width (3a).
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 1000, height: 850 });
const WALL = '#d9c8b4';
await page.evaluate((wall) => window.__hpTest.setServerConfig((cfg) => {
const space = cfg.spaces.find((item) => item.id === 'f1');
space.settings = { ...(space.settings || {}), show_borders: true, show_names: true };
// A wall body of the plan model (room outlines alone raise no 2.5D wall here).
space.partitions = [{ id: 'tw-wall', a: [0.15, 0.12], b: [0.85, 0.12], cm: 15 }];
space.openings = [
{ id: 'tw-door', type: 'door', x: 0.325, y: 0.12, angle: 0, length: 0.08,
host: { kind: 'partition', id: 'tw-wall', t: 0.25 } },
{ id: 'tw-window', type: 'window', x: 0.5, y: 0.12, angle: 0, length: 0.08,
host: { kind: 'partition', id: 'tw-wall', t: 0.5 } },
];
space.decor = [
{ id: 'tw-sofa', kind: 'furniture', symbol: 'sofa', x: 0.62, y: 0.55,
w: 0.2, h: 0.12, color: '#667788', opacity: 0.7, width_cm: 2 },
];
// Half-transparent on purpose: Flat keeps the opacity, the 2.5D prism is opaque.
cfg.settings = { ...(cfg.settings || {}), fill_colors: { ...(cfg.settings?.fill_colors || {}), wall_fill: { c: wall, a: 0.5 } } };
return cfg;
}), WALL);
const snapshot = () => page.evaluate(() => {
const root = window.__card.renderRoot;
const style = (el) => {
const cs = getComputedStyle(el);
return [cs.fill, cs.stroke, cs.opacity, cs.fillOpacity, cs.stopColor, cs.color].join('|');
};
const sig = [...root.querySelectorAll(
'.iso-walls *, .iso-openings *, .iso-underlay *, [class^="iso-side"], [class^="iso-top"]',
)].filter((el) => !el.classList.contains('iso-ambient-shadow')).map((el) => `${el.tagName}.${el.getAttribute('class') || ''}:${style(el)}`);
const stop = (cls) => {
const el = root.querySelector(`stop.${cls}`);
return el ? getComputedStyle(el).stopColor : null;
};
const top = root.querySelector('.iso-wall-top');
const furn = root.querySelector('.dfurn[data-id="tw-sofa"]');
const label = root.querySelector('.roomlabel');
return {
iso: root.querySelector('.stage')?.classList.contains('projection-iso') ?? false,
sig,
stops: ['iso-top-hi', 'iso-top-lo', 'iso-side-hi', 'iso-side-mid', 'iso-side-lo'].map(stop),
faces: root.querySelectorAll('.iso-wall-top, .iso-wall-side').length,
topOpacity: top ? [getComputedStyle(top).opacity, getComputedStyle(top).fillOpacity] : null,
label: label ? [getComputedStyle(label).color, getComputedStyle(label).textShadow] : null,
furnitureStroke: furn ? Number(furn.getAttribute('stroke-width')) : NaN,
furnitureVector: furn?.getAttribute('vector-effect') ?? null,
stageSize: (() => { const s = root.querySelector('.stage'); return [s.clientWidth, s.clientHeight]; })(),
};
});
const setTheme = (dark) => page.evaluate(async (isDark) => {
const c = window.__card;
c.hass = { ...c.hass, themes: { ...(c.hass.themes || {}), darkMode: isDark } };
await window.__hpTest.settled();
await new Promise((done) => setTimeout(done, 450));
}, dark);
await setTheme(false);
const flat = await snapshot();
await page.evaluate(async () => { await window.__hpTest.setVolumetricView(true); });
await page.waitForTimeout(250);
const light = await snapshot();
await setTheme(true);
const dark = await snapshot();
// No theme from Home Assistant: the browser's dark scheme must not repaint either.
await page.evaluate(async () => {
const c = window.__card;
const { darkMode, ...themes } = c.hass.themes || {};
c.hass = { ...c.hass, themes };
await window.__hpTest.settled();
});
await page.emulateMedia({ colorScheme: 'dark' });
await page.waitForTimeout(450);
const scheme = await snapshot();
await page.emulateMedia({ colorScheme: 'light' });
const rgb = (hex, k = 1) => `rgb(${[1, 3, 5].map((i) => Math.round(parseInt(hex.slice(i, i + 2), 16) * k)).join(', ')})`;
const res = {};
res.isoOn = light.iso && dark.iso;
res.topIsUserColour = light.stops[0] === rgb(WALL) && light.stops[1] === rgb(WALL, 0.93);
res.sideDerivedFromUserColour = light.stops[2] === rgb(WALL, 0.77) && light.stops[3] === rgb(WALL, 0.68)
&& light.stops[4] === rgb(WALL, 0.6);
res.wallFacesDrawn = light.faces > 0;
res.prismOpaque = !!light.topOpacity && light.topOpacity.every((v) => Number(v) === 1);
res.themeKeepsWalls = light.sig.length > 10 && JSON.stringify(light.sig) === JSON.stringify(dark.sig);
res.colourSchemeKeepsWalls = JSON.stringify(light.sig) === JSON.stringify(scheme.sig);
res.themeKeepsStops = JSON.stringify(light.stops) === JSON.stringify(dark.stops);
// Labels: the Flat label colour of the theme, not a 2.5D override.
res.labelsLikeFlat = !!light.label && light.label[0] === flat.label?.[0];
// 3a: the same stage → the same furniture line width in CSS px as Flat.
res.furnitureSameWidth = Number.isFinite(flat.furnitureStroke)
&& Math.abs(light.furnitureStroke - flat.furnitureStroke) <= 0.05
&& JSON.stringify(light.stageSize) === JSON.stringify(flat.stageSize);
res.furnitureNonScaling = light.furnitureVector === 'non-scaling-stroke';
// Flat is untouched: back to Flat, the same wall opacity var and label.
await setTheme(false);
await page.evaluate(async () => { await window.__hpTest.setVolumetricView(false); });
const back = await snapshot();
res.flatBack = !back.iso && back.furnitureStroke === flat.furnitureStroke
&& JSON.stringify(back.label) === JSON.stringify(flat.label);
checkAll(res);
await finish(browser, { ...res, stops: light.stops, stroke: [flat.furnitureStroke, light.furnitureStroke] });
+228
View File
@@ -0,0 +1,228 @@
// #649 п.1 (docs/ISOMETRIC.md, Stage 6): device markers are raised tiles in the
// 2.5D View — no ring, rounded body, solid edge below, 1.12 × Flat, the whole
// marker lifted, one floor-shadow layer under every marker (theme × floor
// table of the ТЗ), a frame that hugs tile and edge with the icon-package
// colours and priority, forced colours without edge and shadow. Flat keeps its
// circles; editors stay Flat.
import { launch, check, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 1000, height: 850 });
const WHITE = 'd_lamp';
const TINTED = 'd_light1'; // state on → #F0A00C
// Two markers one above the other: the upper shadow falls where the lower tile is.
await page.evaluate(() => window.__hpTest.setLayout((layout) => {
layout.d_lamp = { s: 'f1', x: 0.22, y: 0.175 };
return layout;
}));
const read = (ids) => page.evaluate(([white, tinted]) => {
const c = window.__card;
const root = c.renderRoot;
const px = (v) => Number.parseFloat(v) || 0;
const marker = (id) => root.querySelector(`.devlayer .dev:not(.iso-tile-shadow)[data-id="${id}"]`);
const twin = (id) => root.querySelector(`.iso-tile-shadows .iso-tile-shadow[data-shadow-of="${id}"]`);
const shadow = (id) => {
const s = twin(id)?.querySelector('.device-core');
const m = s && getComputedStyle(s).boxShadow
.match(/rgba?\(28, 32, 28(?:, ([\d.]+))?\) (-?[\d.]+)px (-?[\d.]+)px ([\d.]+)px (-?[\d.]+)px/);
return m ? { a: Number(m[1] ?? 1), dx: +m[2], dy: +m[3], blur: +m[4], spread: +m[5] } : null;
};
const tile = (id) => {
const dev = marker(id);
const core = dev?.querySelector('.device-core');
if (!core) return null;
const cs = getComputedStyle(core);
const edge = cs.boxShadow.match(/^(rgba?\([^)]*\)) 0px ([\d.]+)px 0px/);
const frame = dev.querySelector('.device-shell-frame');
const rect = core.getBoundingClientRect();
const twinCore = twin(id)?.querySelector('.device-core')?.getBoundingClientRect();
return {
w: rect.width, h: rect.height, top: rect.top,
radius: px(cs.borderTopLeftRadius), bg: cs.backgroundColor,
edgeColor: edge?.[1] ?? null, edgeDepth: edge ? +edge[2] : 0,
ring: frame ? getComputedStyle(frame).borderTopColor : null,
lift: twinCore ? twinCore.top - rect.top : null,
floorLight: dev.classList.contains('iso-floor-light'),
shadow: shadow(id),
frameColor: getComputedStyle(core, '::after').borderTopColor,
hit: (() => { const b = getComputedStyle(dev, '::before'); return [px(b.width), px(b.height)]; })(),
};
};
const shadows = root.querySelector('.iso-tile-shadows');
return {
iso: root.querySelector('.stage')?.classList.contains('projection-iso') ?? false,
white: tile(white), tinted: tile(tinted),
layer: !!shadows,
layerDisplay: shadows ? getComputedStyle(shadows).display : 'none',
twinsInLayerOnly: [...root.querySelectorAll('.iso-tile-shadow')].every((s) => s.parentElement === shadows),
twinsInert: [...root.querySelectorAll('.iso-tile-shadow')].every((s) => getComputedStyle(s).pointerEvents === 'none'
&& s.getAttribute('aria-hidden') === 'true' && !s.hasAttribute('tabindex')),
badgeGap: (() => {
const dev = marker('d_temp');
const core = dev?.querySelector('.device-core')?.getBoundingClientRect();
const badge = dev?.querySelector('.value-badge')?.getBoundingClientRect();
if (!core || !badge) return null;
return badge.left >= core.right ? badge.left - core.right
: badge.top >= core.bottom ? badge.top - core.bottom : core.left - badge.right;
})(),
badgeEdge: (() => {
const b = marker('d_temp')?.querySelector('.value-badge');
return b ? getComputedStyle(b).boxShadow.match(/0px ([\d.]+)px 0px/)?.[1] ?? null : null;
})(),
markerCount: root.querySelectorAll('.devlayer .dev:not(.iso-tile-shadow)').length,
twinCount: root.querySelectorAll('.iso-tile-shadows .dev.iso-tile-shadow').length,
};
}, ids);
const setTheme = (dark) => page.evaluate(async (isDark) => {
const c = window.__card;
c.hass = { ...c.hass, themes: { ...(c.hass.themes || {}), darkMode: isDark } };
await window.__hpTest.settled();
await new Promise((done) => setTimeout(done, 450)); // colour transitions settle
}, dark);
// Floor colour = the space's custom room fill over the paper (ТЗ «Светлый пол»).
const setFloor = (color) => page.evaluate((c) => window.__hpTest.setServerConfig((cfg) => {
const space = cfg.spaces.find((item) => item.id === 'f1');
space.settings = { ...(space.settings || {}), fill_mode: 'custom', custom_fill: { c, a: 1 } };
return cfg;
}), color);
const near = (a, b, tol) => Number.isFinite(a) && Math.abs(a - b) <= tol;
await setTheme(false);
await setFloor('#737777');
const flat = await read([WHITE, TINTED]);
const flatCircle = !flat.iso && !!flat.white && flat.white.radius >= flat.white.w / 2 - 0.5
&& !/rgba\(0, 0, 0, 0\)/.test(flat.white.ring) && !flat.layer;
await page.evaluate(async () => { await window.__hpTest.setVolumetricView(true); });
await page.waitForTimeout(250);
// ---- AC2/AC3: tile geometry, light theme · dark floor ----------------------
const iso = await read([WHITE, TINTED]);
const D = iso.white?.w ?? NaN;
const res = { flatStaysCircleWithRing: flatCircle };
res.isoOn = iso.iso;
res.scale112 = near(D / flat.white.w, 1.12, 0.01);
res.noRing = /rgba\(0, 0, 0, 0\)/.test(iso.white.ring) && /rgba\(0, 0, 0, 0\)/.test(iso.tinted.ring);
res.radiusFormula = near(iso.white.radius, Math.min(0.275 * D, 0.3 * iso.white.h), 0.05);
res.edgeDepth = near(iso.white.edgeDepth, 0.1 * D, 0.05) && near(iso.tinted.edgeDepth, 0.1 * D, 0.05);
// brightness(.7) saturate(.85): white → #b3b3b3, #F0A00C → rgb(160, 113, 25).
res.edgeColourWhite = iso.white.edgeColor === 'rgb(179, 179, 179)';
res.edgeColourTinted = iso.tinted.edgeColor === 'rgb(160, 113, 25)';
res.lifted = near(iso.white.lift, 0.075 * D, 0.1);
res.badgeGap = near(iso.badgeGap, 0.075 * D, 0.3);
res.badgeOwnEdge = near(Number(iso.badgeEdge), 0.1 * D, 0.05);
res.hitTarget44 = iso.white.hit[0] >= 44 && iso.white.hit[1] >= 44;
// ---- AC4: one shadow layer, table per theme × floor -------------------------
res.oneShadowLayer = iso.layer && iso.twinsInLayerOnly && iso.twinCount === iso.markerCount;
res.shadowsInert = iso.twinsInert;
const TABLE = {
'light-dark': { dy: 0.375, sigma: 0.275, white: 0.34, tinted: 0.5 },
'light-light': { dy: 0.425, sigma: 0.1375, white: 0.3, tinted: 0.42 },
'dark-dark': { dy: 0.375, sigma: 0.275, white: 0.4, tinted: 0.4 },
'dark-light': { dy: 0.425, sigma: 0.1375, white: 0.4, tinted: 0.4 },
};
const shadowMatches = (s, row, a) => !!s && near(s.a, a, 0.005) && near(s.dx, 0.1 * D, 0.05)
&& near(s.dy, (row.dy + 0.1) * D, 0.05) && near(s.blur, 2 * row.sigma * D, 0.05)
&& near(s.spread, -0.0375 * D, 0.05);
const combos = {};
for (const [key, row] of Object.entries(TABLE)) {
const [theme, floor] = key.split('-');
await setTheme(theme === 'dark');
await setFloor(floor === 'light' ? '#eee8de' : '#737777');
const now = await read([WHITE, TINTED]);
combos[key] = now;
res[`shadow_${key}`] = now.white.floorLight === (floor === 'light')
&& shadowMatches(now.white.shadow, row, row.white) && shadowMatches(now.tinted.shadow, row, row.tinted);
}
// Light floor: lighter edge brightness(.82) saturate(.8) → #d1d1d1; dark theme → #4a4a4a.
res.edgeLightFloor = combos['light-light'].white.edgeColor === 'rgb(209, 209, 209)';
res.edgeDarkTheme = combos['dark-dark'].white.edgeColor === 'rgb(74, 74, 74)'
&& combos['dark-light'].white.edgeColor === 'rgb(74, 74, 74)';
res.tintedBodyThemeFree = combos['dark-dark'].tinted.bg === 'rgb(240, 160, 12)';
// No shadow ever lands on a neighbour's tile: the lower tile's inside is the
// same with and without the shadow layer (the upper marker casts onto it).
await setTheme(false);
await setFloor('#737777');
const lowerClip = await page.evaluate((id) => {
const r = window.__card.renderRoot.querySelector(`.devlayer .dev:not(.iso-tile-shadow)[data-id="${id}"] .device-core`)
.getBoundingClientRect();
const inset = r.width * 0.3;
return { x: r.left + inset, y: r.top + inset, width: r.width - 2 * inset, height: r.height - 2 * inset };
}, TINTED);
const withShadows = await page.screenshot({ clip: lowerClip });
await page.evaluate(() => { window.__card.renderRoot.querySelector('.iso-tile-shadows').style.display = 'none'; });
const withoutShadows = await page.screenshot({ clip: lowerClip });
await page.evaluate(() => { window.__card.renderRoot.querySelector('.iso-tile-shadows').style.display = ''; });
res.shadowNeverOnNeighbourTile = Buffer.compare(withShadows, withoutShadows) === 0;
// ---- AC5: frames — hover, focus, selected, alert; the body is not repainted --
const centre = await page.evaluate((id) => {
const r = window.__card.renderRoot.querySelector(`.devlayer .dev:not(.iso-tile-shadow)[data-id="${id}"] .device-core`)
.getBoundingClientRect();
return [r.left + r.width / 2, r.top + r.height / 2];
}, WHITE);
const before = (await read([WHITE, TINTED])).white;
await page.mouse.move(centre[0], centre[1]);
await page.waitForTimeout(80);
const hovered = (await read([WHITE, TINTED])).white;
res.hoverFrameBlue = hovered.frameColor === 'rgb(12, 130, 240)';
res.hoverBodyUnchanged = hovered.bg === before.bg;
res.frameIdleInvisible = /rgba\(0, 0, 0, 0\)/.test(before.frameColor);
await page.mouse.move(5, 5);
const frames = await page.evaluate(async (id) => {
const dev = window.__card.renderRoot.querySelector(`.devlayer .dev:not(.iso-tile-shadow)[data-id="${id}"]`);
const core = dev.querySelector('.device-core');
const colour = () => getComputedStyle(core, '::after').borderTopColor;
const frame = () => {
const a = getComputedStyle(core, '::after');
const r = core.getBoundingClientRect();
return { w: Number.parseFloat(a.width), h: Number.parseFloat(a.height), coreW: r.width, coreH: r.height,
radius: Number.parseFloat(a.borderTopLeftRadius), coreRadius: Number.parseFloat(getComputedStyle(core).borderTopLeftRadius) };
};
const out = {};
dev.classList.add('sel');
out.selected = colour();
out.geometry = frame();
dev.focus({ focusVisible: true });
out.focusVisible = dev.matches(':focus-visible');
out.focusOverSelected = colour();
dev.classList.add('alarm');
out.alarmOverFocus = colour();
dev.classList.remove('alarm', 'sel');
out.focusOnly = colour();
dev.blur();
return out;
}, WHITE);
res.selectedAmber = frames.selected === 'rgb(240, 160, 12)';
res.focusBeatsSelected = !frames.focusVisible || frames.focusOverSelected === 'rgb(12, 130, 240)';
res.alarmBeatsFocus = frames.alarmOverFocus === 'rgb(240, 65, 12)';
res.focusBlue = !frames.focusVisible || frames.focusOnly === 'rgb(12, 130, 240)';
// Frame: tile bbox + 0.075 D per side (outset 6 + half stroke 2.5 lab units), height + edge.
const g = frames.geometry;
res.frameHugsTileAndEdge = near(g.w - g.coreW, 2 * (6 + 2.5) / 80 * D, 0.1)
&& near(g.h - g.coreH, 2 * (6 + 2.5) / 80 * D + 0.1 * D, 0.1)
&& near(g.radius - g.coreRadius, (6 + 2.5) / 80 * D, 0.1);
// ---- AC6: forced colours — no edge, no shadow; size and frames stay ---------
await page.emulateMedia({ forcedColors: 'active' });
const forced = await read([WHITE, TINTED]);
res.forcedNoShadow = forced.layerDisplay === 'none';
res.forcedNoEdge = forced.white.edgeColor === null;
res.forcedKeepsSize = near(forced.white.w, D, 0.05);
await page.emulateMedia({ forcedColors: 'none' });
// ---- editors are Flat; switching off restores Flat --------------------------
await page.evaluate(() => window.__hpTest.setMode('plan'));
const editor = await read([WHITE, TINTED]);
res.editorFlat = !editor.iso && !editor.layer;
await page.evaluate(() => window.__hpTest.setMode('view'));
await page.evaluate(async () => { await window.__hpTest.setVolumetricView(false); });
const back = await read([WHITE, TINTED]);
res.offRestoresFlat = !back.iso && !back.layer && near(back.white.w, flat.white.w, 0.05)
&& back.white.radius >= back.white.w / 2 - 0.5;
checkAll(res);
await finish(browser, { ...res, D, gap: iso.badgeGap, badgeEdge: iso.badgeEdge });
+42 -45
View File
@@ -1,4 +1,4 @@
// #122/#160/#570 Stage 4: alpha lifecycle, visual handoff and flat editor boundary.
// #122/#160/#570 Stage 4 + #649: settings lifecycle, visual handoff and flat editor boundary.
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 1000, height: 850 });
@@ -45,10 +45,12 @@ const out = await page.evaluate(async () => {
return hit === element || !!hit && element.contains(hit);
});
};
// #649: 2.5D is the installation-wide General settings switch.
// The switch arrives as a server config push: re-bind the space the smoke edits.
const rebind = () => { configSpace = card._serverCfg.spaces.find((space) => space.id === 'f1'); };
const enable = async () => {
history.replaceState(null, '', '#space=f1&hp_alpha=1');
dispatchEvent(new HashChangeEvent('hashchange'));
await card.updateComplete;
await window.__hpTest.setVolumetricView(true);
rebind();
await ensureIsoRuntime();
await frame();
};
@@ -59,7 +61,7 @@ const out = await page.evaluate(async () => {
&& ![...root().querySelector('.stage').classList]
.some((name) => name.startsWith('projection-'));
result.cleanAlphaOffSkipsIsoRuntimeRequest = isoRuntimeRequests() === 0;
const configSpace = card._serverCfg.spaces.find((space) => space.id === 'f1');
let configSpace = card._serverCfg.spaces.find((space) => space.id === 'f1');
configSpace.settings = {
...(configSpace.settings || {}), show_borders: true, show_names: true,
};
@@ -80,8 +82,18 @@ const out = await page.evaluate(async () => {
card._cfgEpoch++;
card.requestUpdate();
await card.updateComplete;
// #649 AC11: the alpha switch no longer enables 2.5D and loads nothing.
history.replaceState(null, '', '#space=f1&hp_alpha=1');
dispatchEvent(new HashChangeEvent('hashchange'));
await card.updateComplete;
await frame();
result.alphaDoesNotEnableIso = window.__hpAlpha === true && JSON.stringify(window.__hpLabs) === '[]'
&& !root().querySelector('[data-hp="iso-walls"]') && isoRuntimeRequests() === 0;
history.replaceState(null, '', '#space=f1&hp_alpha=0');
dispatchEvent(new HashChangeEvent('hashchange'));
await card.updateComplete;
await enable();
result.alphaOnLoadsIsoRuntimeOnce = isoRuntimeRequests() === 1;
result.settingLoadsIsoRuntimeOnce = isoRuntimeRequests() === 1;
const openingBases = card._isoSource()?.build().openings || [];
const basis = (id) => openingBases.find((opening) => opening.id === id);
const centredDoor = basis('iso-centred-door');
@@ -111,27 +123,13 @@ const out = await page.evaluate(async () => {
&& flippedGate.leaves.every((leaf) => Math.abs(leaf.turnDeg) === 10);
result.isoGateFlipReversesTurn = centredGate?.leaves[0]?.turnDeg
=== -flippedGate?.leaves[0]?.turnDeg;
const toggle = root().querySelector('[data-hp="projection-toggle"]');
result.alphaSnapshotFrozen = window.__hpAlpha === true && Object.isFrozen(window.__hpLabs)
&& JSON.stringify(window.__hpLabs) === '["iso"]';
result.alphaStored = localStorage.getItem('houseplan_card_alpha_v1') === '1';
result.toggleShown = !!toggle;
result.toggleMinHitTarget = toggle && toggle.getBoundingClientRect().width >= 44
&& toggle.getBoundingClientRect().height >= 44;
result.flatDefault = toggle?.getAttribute('aria-pressed') === 'false'
&& !root().querySelector('[data-hp="iso-walls"]');
toggle?.click();
await ensureIsoRuntime();
await card.updateComplete;
await frame();
const isoToggle = root().querySelector('[data-hp="projection-toggle"]');
result.settingStored = card._serverCfg.settings?.volumetric_view === true;
result.noCardToggle = !root().querySelector('[data-hp="projection-toggle"]');
const device = root().querySelector('[data-hp="device"]');
const roomLabel = root().querySelector('[data-hp="room-label"]');
const openingLock = root().querySelector('.oplock');
const stage = root().querySelector('.stage');
result.isoRendered = isoToggle?.getAttribute('aria-pressed') === 'true'
&& !!root().querySelector('[data-hp="iso-underlay"] .iso-floor-side')
result.isoRendered = !!root().querySelector('[data-hp="iso-underlay"] .iso-floor-side')
&& !!root().querySelector('[data-hp="iso-walls"] .iso-wall-top');
result.stage4RevisionAdvertised = stage?.getAttribute('data-hp-iso-stage') === '4';
result.sharedProjectionSnapshot = [
@@ -187,7 +185,7 @@ const out = await page.evaluate(async () => {
result.raisedFootprintsStayInvisible = !root().querySelector(
'.iso-overlay-plate, .iso-overlay-plate-texture, #hp-iso-overlay-texture',
);
result.preferenceStored = JSON.parse(localStorage.getItem('houseplan_card_view_v1') || '{}').f1 === 'iso';
result.noDevicePreference = localStorage.getItem('houseplan_card_view_v1') === null;
result.anchorsFinite = [device, roomLabel, openingLock].every((node) => node
&& center(node).every((value) => Number.isFinite(value)));
card._fitAll();
@@ -335,7 +333,7 @@ const out = await page.evaluate(async () => {
const areaLink = root().querySelector('.roomlabel[data-id="r1"] .rlgo');
areaLink?.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
const areaPath = location.pathname;
history.replaceState(null, '', '/#space=f1&hp_alpha=1');
history.replaceState(null, '', '/#space=f1');
const lockRoot = root().querySelector('.oplock');
lockRoot?.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
result.raisedActionsRemainOwned = moreInfoCalls === 1 && keyboardOpenedDeviceCard
@@ -354,7 +352,7 @@ const out = await page.evaluate(async () => {
card._setMode('view');
await card.updateComplete;
while (card._modeTransitionBusy) await frame();
result.viewRestoresIso = root().querySelector('[data-hp="projection-toggle"]')?.getAttribute('aria-pressed') === 'true'
result.viewRestoresIso = !!root().querySelector('.stage.projection-iso')
&& !!root().querySelector('[data-hp="iso-walls"]');
const nativeCssSupports = CSS.supports;
@@ -403,8 +401,9 @@ const out = await page.evaluate(async () => {
await card.updateComplete;
result.latchedFallbackKeepsFlatCamera = JSON.stringify(card._view) === JSON.stringify(fallbackFlatCamera);
card._isoSource = healthySource;
card._setProjection('iso');
await card.updateComplete;
await window.__hpTest.setVolumetricView(false);
await window.__hpTest.setVolumetricView(true);
rebind();
result.invalidSourceExplicitRetryRestoresIso = !card._isoFallback.has(firstInvalidKey)
&& !!root().querySelector('[data-hp="iso-walls"]');
@@ -459,15 +458,16 @@ const out = await page.evaluate(async () => {
await card.updateComplete;
result.fallbackLatched = attempts === 1
&& card._viewModeSnap === null
&& root().querySelector('[data-hp="projection-toggle"]')?.getAttribute('aria-pressed') === 'false'
&& !root().querySelector('.stage.projection-iso')
&& !root().querySelector('[data-hp="iso-walls"]')
&& JSON.parse(localStorage.getItem('houseplan_card_view_v1') || '{}').f1 === 'iso';
&& card._serverCfg.settings?.volumetric_view === true;
shouldFail = false;
card._setProjection('iso');
await card.updateComplete;
result.explicitRetryRestoresIso = attempts === 2
await window.__hpTest.setVolumetricView(false);
await window.__hpTest.setVolumetricView(true);
rebind();
result.explicitRetryRestoresIso = attempts >= 2
&& !!root().querySelector('[data-hp="iso-walls"]')
&& root().querySelector('[data-hp="projection-toggle"]')?.getAttribute('aria-pressed') === 'true';
&& !!root().querySelector('.stage.projection-iso');
card._isoSource = source;
card._isoGeometryCache.delete(fallbackKey);
card._isoFallback.delete(fallbackKey);
@@ -532,28 +532,25 @@ const out = await page.evaluate(async () => {
&& /"terminal":true/.test(fallbackWarnings[0])
&& !/(private_identifier|sensor\.|https?:|token=|stack)/i.test(fallbackWarnings[0])
&& !root().querySelector('[data-hp="iso-walls"]')
&& JSON.parse(localStorage.getItem('houseplan_card_view_v1') || '{}').f1 === 'iso';
&& card._serverCfg.settings?.volumetric_view === true;
card._isoSceneRuntime = runtime;
card._setProjection('iso');
await card.updateComplete;
await window.__hpTest.setVolumetricView(false);
await window.__hpTest.setVolumetricView(true);
rebind();
result.lateFailureExplicitRetryRestoresIso = !!root().querySelector('[data-hp="iso-walls"]');
console.warn = warning;
history.replaceState(null, '', '#space=f1&hp_alpha=0');
dispatchEvent(new HashChangeEvent('hashchange'));
await card.updateComplete;
await window.__hpTest.setVolumetricView(false);
await frame();
result.removalIsImmediateFlat = window.__hpAlpha === false
&& localStorage.getItem('houseplan_card_alpha_v1') === '0'
&& JSON.stringify(window.__hpLabs) === '[]'
result.removalIsImmediateFlat = card._serverCfg.settings?.volumetric_view === false
&& !root().querySelector('[data-hp="projection-toggle"]')
&& !root().querySelector('[data-hp="iso-walls"]')
&& !root().querySelector('[id^="hp-iso-"]')
&& ![...root().querySelector('.stage').classList]
.some((name) => name.startsWith('projection-'));
await enable();
result.reenableRestoresPreference = window.__hpAlpha === true
&& root().querySelector('[data-hp="projection-toggle"]')?.getAttribute('aria-pressed') === 'true'
result.reenableRestoresIso = !!root().querySelector('.stage.projection-iso')
&& !!root().querySelector('[data-hp="iso-walls"]');
return result;
});
+23 -20
View File
@@ -17,11 +17,9 @@ const out = await page.evaluate(async () => {
await card.updateComplete;
await frame();
};
history.replaceState(null, '', '?hp_alpha=1#space=f1');
dispatchEvent(new HashChangeEvent('hashchange'));
await original.updateComplete;
history.replaceState(null, '', '#space=f1');
await ensureIsoRuntime(original);
const configSpace = original._serverCfg.spaces.find((space) => space.id === 'f1');
let configSpace = original._serverCfg.spaces.find((space) => space.id === 'f1');
configSpace.settings = {
...(configSpace.settings || {}), fill_mode: 'custom',
custom_fill: { c: '#31465f', a: 0.42 }, glow_enabled: true,
@@ -109,7 +107,9 @@ const out = await page.evaluate(async () => {
const flat = layers();
const flatSpillParts = [...root(original).querySelectorAll('.glow-pool')]
.map((node) => node.getAttribute('data-lit-parts'));
root(original).querySelector('[data-hp="projection-toggle"]')?.click();
// #649: the General settings switch, delivered as a server config push.
await window.__hpTest.setVolumetricView(true);
configSpace = original._serverCfg.spaces.find((space) => space.id === 'f1');
await ensureIsoRuntime(original);
await original.updateComplete;
await frame();
@@ -390,14 +390,13 @@ const out = await page.evaluate(async () => {
await original.updateComplete;
root(original).querySelector('[data-entity="light.ceiling"]')?.click();
await frame();
original._setProjection('flat');
await original.updateComplete;
await window.__hpTest.setVolumetricView(false);
root(original).querySelector('[data-entity="light.ceiling"]')?.click();
await frame();
result.flatIsoActionParity = calls.length === 2
&& JSON.stringify(calls[0]) === JSON.stringify(calls[1]);
original._setProjection('iso');
await original.updateComplete;
await window.__hpTest.setVolumetricView(true);
configSpace = original._serverCfg.spaces.find((space) => space.id === 'f1');
const stage = root(original).querySelector('.stage');
const stageRect = stage.getBoundingClientRect();
@@ -444,15 +443,15 @@ const out = await page.evaluate(async () => {
original._closeInfoCard();
} else result.touchLongPressHitsDevice = false;
// #649: one installation-wide switch — every space is 2.5D, no per-space choice.
original._pickSpace('garden');
await wait(230);
original._setProjection('iso');
await original.updateComplete;
const gardenIso = original._space === 'garden'
&& root(original).querySelector('[data-hp="projection-toggle"]')?.getAttribute('aria-pressed') === 'true';
&& !!root(original).querySelector('.stage.projection-iso');
original._pickSpace('f1');
await wait(230);
result.touchSpaceSwitchKeepsPerSpaceIso = gardenIso && original._space === 'f1'
result.touchSpaceSwitchKeepsIso = gardenIso && original._space === 'f1'
&& !!root(original).querySelector('[data-hp="iso-walls"]');
const ownVisibilityState = Object.getOwnPropertyDescriptor(document, 'visibilityState');
@@ -488,10 +487,11 @@ const out = await page.evaluate(async () => {
const warm = await mount(false);
result.warmRemountIso = !warm._booting
&& !!root(warm).querySelector('[data-hp="iso-walls"]')
&& root(warm).querySelector('[data-hp="projection-toggle"]')?.getAttribute('aria-pressed') === 'true';
&& !!root(warm).querySelector('.stage.projection-iso')
&& !root(warm).querySelector('[data-hp="projection-toggle"]');
warm.remove();
const kiosk = await mount(true);
result.kioskReadsPreference = !!root(kiosk).querySelector('[data-hp="iso-walls"]');
result.kioskReadsSetting = !!root(kiosk).querySelector('[data-hp="iso-walls"]');
result.kioskHasNoToggle = !root(kiosk).querySelector('[data-hp="projection-toggle"]');
const kioskStage = root(kiosk).querySelector('.stage');
const kioskRect = kioskStage?.getBoundingClientRect();
@@ -521,15 +521,18 @@ out.orientationResizeKeepsIso = await page.evaluate(async () => {
return !!card.renderRoot.querySelector('[data-hp="iso-walls"]')
&& !!anchor && [anchor.left, anchor.top, anchor.width, anchor.height].every(Number.isFinite);
});
out.kioskEmergencyOffIsFlat = await page.evaluate(async () => {
out.kioskSettingOffIsFlat = await page.evaluate(async () => {
const card = document.querySelector('houseplan-card');
history.replaceState(null, '', '?hp_alpha=0#space=f1');
dispatchEvent(new HashChangeEvent('hashchange'));
// #649: the admin switches 2.5D off in General settings; the kiosk follows the push.
const cfg = structuredClone(card._serverCfg);
cfg.settings = { ...(cfg.settings || {}), volumetric_view: false };
const rev = window.__pushServerConfig(cfg);
const started = performance.now();
while (card._cfgRev < rev && performance.now() - started < 5000) await new Promise((done) => setTimeout(done, 30));
await card.updateComplete;
await new Promise((done) => requestAnimationFrame(() => requestAnimationFrame(done)));
return window.__hpAlpha === false
&& localStorage.getItem('houseplan_card_alpha_v1') === '0'
&& !card.renderRoot.querySelector('[data-hp="iso-walls"]')
return !card.renderRoot.querySelector('[data-hp="iso-walls"]')
&& !card.renderRoot.querySelector('.stage.projection-iso')
&& !card.renderRoot.querySelector('[data-hp="projection-toggle"]');
});
+2 -7
View File
@@ -208,12 +208,7 @@ const result = await page.evaluate(async (spaceFixture) => {
staticCard.renderRoot?.querySelector('[data-hp="wall"]'), finiteRayDoorApproachProbe,
);
staticCard.remove();
const labs = Object.freeze(['iso']);
card._onLabsSnapshot({ alpha: true, active: labs, space: '' });
window.__hpAlpha = true;
window.__hpLabs = labs;
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
await update(false);
const isoWalls = card._isoSource().build().walls;
@@ -238,7 +233,7 @@ const result = await page.evaluate(async (spaceFixture) => {
angle: 0, length: 0.025,
}];
card._serverCfg = openingCfg;
card._setProjection('flat');
await window.__hpHarnessProjection(card, 'flat');
card._setMode('plan');
await update(true);
const openingSource = JSON.stringify(card._serverCfg.spaces[0]);
+4 -5
View File
@@ -450,16 +450,15 @@ for (const dayCycle of [false, true]) {
}
await page.evaluate(async () => {
history.replaceState(null, '', '?hp_alpha=1#space=f1');
dispatchEvent(new HashChangeEvent('hashchange'));
history.replaceState(null, '', '#space=f1');
const card = document.querySelector('houseplan-card');
await card.updateComplete;
await window.__hpEnsureHarnessIsoRuntime(card);
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await card.updateComplete;
await new Promise((done) => requestAnimationFrame(() => requestAnimationFrame(done)));
});
checks.alphaIsoEnabled = await page.evaluate(() => {
checks.isoEnabled = await page.evaluate(() => {
const card = document.querySelector('houseplan-card');
return card._effectiveProjection() === 'iso'
&& card.renderRoot.querySelector('.stage')?.getAttribute('data-hp-iso-stage') === '4';
@@ -469,7 +468,7 @@ await runTouchZoomOut({ name: 'isoTouchZoomOut' });
await page.evaluate(async () => {
const card = document.querySelector('houseplan-card');
card._setProjection('flat');
await window.__hpHarnessProjection(card, 'flat');
card.setConfig({ type: 'custom:houseplan-card', kiosk: true });
await card.updateComplete;
await new Promise((done) => requestAnimationFrame(() => requestAnimationFrame(done)));
+1 -1
View File
@@ -30,7 +30,7 @@ const header = () => page.evaluate(() => {
zoom: shown(head.querySelector(':scope > .zoomctl')),
gear: shown(gear),
gear44: !!g && g.width >= 44 && g.height >= 44,
hiddenInline: ['.modes', '.header-action', '.summary-control', '.projection-toggle', '.tabedit', '.tabadd']
hiddenInline: ['.modes', '.header-action', '.summary-control', '.tabedit', '.tabadd']
.filter((selector) => [...head.querySelectorAll(selector)].some(shown)),
tabEditInDom: !!head.querySelector('.tabedit, .tabadd'),
inlineVisible: ['.header-action', '.summary-control'].filter((selector) => [...head.querySelectorAll(selector)].some(shown)),
+1 -6
View File
@@ -199,12 +199,7 @@ const result = await page.evaluate(async (source) => {
staticCard.renderRoot?.querySelector('[data-hp="wall"]'), node,
) === 0;
staticCard.remove();
const labs = Object.freeze(['iso']);
card._onLabsSnapshot({ alpha: true, active: labs, space: '' });
window.__hpAlpha = true;
window.__hpLabs = labs;
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
await update(false);
const isoWalls = card._isoSource().build().walls;
+2 -7
View File
@@ -209,18 +209,13 @@ const result = await page.evaluate(async (source) => {
=== path?.getAttribute('d');
out[`${prefix}_static_has_all_strips`] = svgMisses(staticPath, samples) === 0;
staticCard.remove();
const labs = Object.freeze(['iso']);
card._onLabsSnapshot({ alpha: true, active: labs, space: '' });
window.__hpAlpha = true;
window.__hpLabs = labs;
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
await update(false);
const isoWalls = card._isoSource().build().walls;
out[`${prefix}_hidden_iso_has_all_strips`] = samples.every((point) =>
pointInGeometry(point, isoWalls));
card._setProjection('plan');
await window.__hpHarnessProjection(card, 'flat');
out[`${prefix}_render_never_writes_config`] = JSON.stringify(
card._serverCfg.spaces[0],
) === persisted;
+1 -3
View File
@@ -241,9 +241,7 @@ const out = await page.evaluate(async () => {
c.style.width = '1000px';
await new Promise((resolve) => setTimeout(resolve, 100));
c._clearRoomFocus(true);
c._onLabsSnapshot({ active: Object.freeze(['iso']), space: '' });
await c.updateComplete;
c._setProjection('iso');
await window.__hpHarnessProjection(c, 'iso');
await window.__hpEnsureHarnessIsoRuntime(c);
await c.updateComplete;
pointer(roomNode(), 'pointerdown', 15207);
+2 -8
View File
@@ -144,16 +144,10 @@ const out = await page.evaluate(async () => {
card._reducedMotion = false;
// Projection owns an atomic structural conversion and cancels the camera.
card._labs = {
...card._labs,
alpha: true,
active: [...new Set([...card._labs.active, 'iso'])],
};
card._viewPreference = { ...card._viewPreference, [card._space]: 'flat' };
directBaseline(1);
card._stepZoom(1);
await frame();
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
const projectionCancelled = !card._cameraTransition.active;
await card.updateComplete;
@@ -165,7 +159,7 @@ const out = await page.evaluate(async () => {
card._stepZoom(1);
await settle();
const isoFinal = camera();
card._setProjection('flat');
await window.__hpHarnessProjection(card, 'flat');
// Hidden commits the user's target and no old RAF resumes later.
directBaseline(1);
+3 -5
View File
@@ -110,15 +110,13 @@ const res = await page.evaluate(async () => {
out.kioskParity = sr().querySelector('.wallbody')?.getAttribute('d') === planD;
c._config.kiosk = kioskBefore;
history.replaceState(null, '', `?hp_alpha=1#space=${encodeURIComponent(c._space)}`);
dispatchEvent(new HashChangeEvent('hashchange'));
await c.updateComplete;
c._setProjection('iso');
history.replaceState(null, '', `#space=${encodeURIComponent(c._space)}`);
await window.__hpHarnessProjection(c, 'iso');
await window.__hpEnsureHarnessIsoRuntime(c);
await update();
out.isoUsesCanonicalBody = !!sr().querySelector('.iso-walls .iso-wall-top')
&& c._isoSource().build().walls.flat(2).length > 0;
c._setProjection('flat');
await window.__hpHarnessProjection(c, 'flat');
await update();
await customElements.whenDefined('houseplan-space-card');
+90
View File
@@ -0,0 +1,90 @@
// #649 п.4 (docs/ISOMETRIC.md, Stage 6): 2.5D is the installation-wide switch
// «General settings › Display», third after «Show live presence on the plan».
// Saving it changes the View at once in every space and in the kiosk; editors
// stay Flat; «Reset» turns it off; there is no card toggle and no alpha entry.
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 1280, height: 900 });
const res = await page.evaluate(async () => {
const out = {};
const c = window.__card;
const t = window.__hpTest;
const sr = () => c.renderRoot;
const iso = (root = sr()) => !!root.querySelector('.stage')?.classList.contains('projection-iso');
const dlg = () => sr().querySelector('hp-dialog[data-kind="settings"]');
const q = (sel) => dlg()?.querySelector(sel);
const waitFor = async (predicate, ms = 8000) => {
const end = performance.now() + ms;
while (!predicate()) {
if (performance.now() > end) return false;
await new Promise((done) => setTimeout(done, 25));
}
return true;
};
const openSettings = async () => {
sr().querySelector('[data-hp="settings"]').click();
await t.settled();
return waitFor(() => !!q('#gs-volumetric-view'));
};
const save = async () => {
q('[data-hp="dialog-confirm"]').click();
await t.settled();
await waitFor(() => !dlg());
};
out.noCardToggle = !sr().querySelector('[data-hp="projection-toggle"], .projection-toggle');
out.startsFlat = !iso();
out.dialogOpens = await openSettings();
const display = q('.hpf-card[data-card="display"]');
const ids = [...display.querySelectorAll('.hpf-toggle > input[type="checkbox"]')].map((i) => i.id);
out.thirdInDisplay = JSON.stringify(ids) === JSON.stringify(['gs-room-tooltip', 'gs-radar-live', 'gs-volumetric-view']);
const row = q('#gs-volumetric-view').closest('.hpf-toggle')?.parentElement ?? null;
out.rowTitleAndIcon = !!row && row.textContent.includes(c._t('gs.volumetric_view'))
&& !!row.querySelector('ha-icon[icon="mdi:cube-outline"]');
out.offByDefault = q('#gs-volumetric-view').checked === false;
q('#gs-volumetric-view').click();
await t.settled();
out.previewDoesNotSwitch = !iso();
await save();
out.saveSwitchesAtOnce = await waitFor(() => iso());
out.storedAsTrue = c._serverCfg.settings.volumetric_view === true;
// Every space follows the one setting.
await t.switchSpace('garden');
out.otherSpaceIso = await waitFor(() => iso());
await t.switchSpace('f1');
out.backSpaceIso = await waitFor(() => iso());
// Editors are Flat, View returns to 2.5D.
await t.setMode('plan');
out.editorFlat = !iso();
await t.setMode('view');
out.viewIsoAgain = await waitFor(() => iso());
// The kiosk reads the same installation setting. The fixture does not keep
// writes, so the saved config is published as the server's state first.
await t.setServerConfig((cfg) => cfg);
const kiosk = document.createElement('houseplan-card');
kiosk.setConfig({ type: 'custom:houseplan-card', kiosk: true, cycle: 0 });
kiosk.hass = c.hass;
kiosk.style.cssText = 'position:fixed;left:0;top:0;width:900px;height:700px;z-index:99';
document.body.appendChild(kiosk);
out.kioskIso = await waitFor(() => !!kiosk.renderRoot?.querySelector('.stage')
&& iso(kiosk.renderRoot), 10000);
kiosk.remove();
// Reset turns it off; saving returns Flat without a reload.
await openSettings();
out.dialogShowsOn = q('#gs-volumetric-view').checked === true;
[...dlg().querySelectorAll('.dialog-action-footer .btn')]
.find((b) => b.textContent.trim() === c._t('gs.reset')).click();
await t.settled();
out.resetUnchecks = q('#gs-volumetric-view').checked === false;
await save();
out.resetSavesFlat = await waitFor(() => !iso());
out.falseNotStored = !('volumetric_view' in (c._serverCfg.settings || {}));
return out;
});
checkAll(res);
await finish(browser, res);
+3 -5
View File
@@ -117,15 +117,13 @@ const out = await page.evaluate(async () => {
await update();
result.planViewParity = !!planD && root().querySelector('.wallbody')?.getAttribute('d') === planD;
history.replaceState(null, '', '?hp_alpha=1#space=junctions');
dispatchEvent(new HashChangeEvent('hashchange'));
await card.updateComplete;
card._setProjection('iso');
history.replaceState(null, '', '#space=junctions');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
await update();
result.isoUsesJoinedFootprint = !!root().querySelector('.iso-walls .iso-wall-top')
&& card._isoSource().build().walls.flat(2).length > 0;
card._setProjection('flat');
await window.__hpHarnessProjection(card, 'flat');
await update();
await customElements.whenDefined('houseplan-space-card');
+2 -7
View File
@@ -46,7 +46,7 @@ const result = await page.evaluate(async (source) => {
card._serverCfg = structuredClone(cfg);
card._layout = {};
card._space = space.id;
card._setProjection('flat');
await window.__hpHarnessProjection(card, 'flat');
card._setMode('plan');
card._tool = 'select';
await update(true);
@@ -112,12 +112,7 @@ const result = await page.evaluate(async (source) => {
out[`${prefix}static_matches_plan`] = staticCard.renderRoot
?.querySelector('[data-hp="wall"]')?.getAttribute('d') === planD;
staticCard.remove();
const labs = Object.freeze(['iso']);
card._onLabsSnapshot({ alpha: true, active: labs, space: '' });
window.__hpAlpha = true;
window.__hpLabs = labs;
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
await update(false);
out[`${prefix}hidden_iso_uses_masonry`] = !!root().querySelector('[data-hp="iso-walls"]')
+1 -5
View File
@@ -130,11 +130,7 @@ const result = await page.evaluate(async () => {
out.staticMatchesPlan = staticPath?.getAttribute('d') === planD
&& !containsPath(staticPath, 700, 96) && containsPath(staticPath, 300, 96);
staticCard.remove();
const active = Object.freeze(['iso']);
card._onLabsSnapshot({ active, space: '' });
window.__hpLabs = active;
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
await settle();
const isoWalls = card._isoSource().build().walls;
+2 -7
View File
@@ -71,12 +71,7 @@ const result = await page.evaluate(async (fixtureConfig) => {
'.wallbody[data-component]',
)].map((path) => path.getAttribute('d')).sort()) === JSON.stringify(planPaths);
staticCard.remove();
const labs = Object.freeze(['iso']);
card._onLabsSnapshot({ alpha: true, active: labs, space: '' });
window.__hpAlpha = true;
window.__hpLabs = labs;
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
card.requestUpdate();
await settle();
@@ -91,7 +86,7 @@ const result = await page.evaluate(async (fixtureConfig) => {
if (message.type === 'houseplan/config/set') { writes++; return { rev: 9 }; }
return baseCall(message);
} };
card._setProjection('flat');
await window.__hpHarnessProjection(card, 'flat');
card._setMode('plan');
await settle();
card._geometryHistory.clear();
+3 -5
View File
@@ -129,15 +129,13 @@ const res = await page.evaluate(async () => {
out.kioskParity = sr().querySelector('.wallbody')?.getAttribute('d') === planD;
c._config.kiosk = kioskBefore;
history.replaceState(null, '', `?hp_alpha=1#space=${encodeURIComponent(c._space)}`);
dispatchEvent(new HashChangeEvent('hashchange'));
await c.updateComplete;
c._setProjection('iso');
history.replaceState(null, '', `#space=${encodeURIComponent(c._space)}`);
await window.__hpHarnessProjection(c, 'iso');
await window.__hpEnsureHarnessIsoRuntime(c);
await update();
out.isoUsesCanonicalBody = !!sr().querySelector('.iso-walls .iso-wall-top')
&& c._isoSource().build().walls.flat(2).length > 0;
c._setProjection('flat');
await window.__hpHarnessProjection(c, 'flat');
await update();
await customElements.whenDefined('houseplan-space-card');
+2 -5
View File
@@ -126,10 +126,7 @@ const result = await page.evaluate(async () => {
card._cfgEpoch++;
card.requestUpdate();
await card.updateComplete;
history.replaceState(null, '', '#space=f1&hp_alpha=1');
dispatchEvent(new HashChangeEvent('hashchange'));
await wait(() => card._labsIso === true, 'alpha enabled');
card._setProjection('iso');
await window.__hpHarnessProjection(card, 'iso');
await window.__hpEnsureHarnessIsoRuntime(card);
await wait(() => !!root().querySelector('[data-hp="iso-walls"]'), 'Iso walls');
const isoBeforePanZoom = await isoTopologyGeometry();
@@ -151,7 +148,7 @@ const result = await page.evaluate(async () => {
) > 1;
currentSource.dispatchEvent(mouse('pointerout', root().querySelector('.stage')));
card._setProjection('flat');
await window.__hpHarnessProjection(card, 'flat');
await card.updateComplete;
await frame();
+210 -210
View File
@@ -1,147 +1,147 @@
{
"schema": 1,
"fingerprint": "5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051",
"fingerprint": "873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 291761,
"initialViewGzipBytes": 294004,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 293284,
"initialPanelGzipBytes": 295526,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2326,
"initialPanelOnlyGzipBytes": 2323,
"lazyFiles": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/de-C7gyFGpd.js",
"houseplan-assets/editor-9cyNd7R7.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/fr-BSn1zqYb.js",
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-editor-runtime-DFhn-zc9.js",
"houseplan-assets/houseplan-onboarding-runtime-BiiaK_3r.js",
"houseplan-assets/hp-zigbee-topology-overlay-D7siZQoq.js",
"houseplan-assets/iso-scene-render-xsesUj3A.js",
"houseplan-assets/live-interaction-runtime-DZWBYZP0.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/pdf-export-BYsRpVk_.js",
"houseplan-assets/summary-panel-runtime-loaded-gtNYqb9U.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js",
"houseplan-assets/zigbee-topology-runtime-A7rG7kis.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/de-DHDD9RSi.js",
"houseplan-assets/editor-C20ayYMa.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/fr-Ckenu6AU.js",
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-editor-runtime-DO6W6BMI.js",
"houseplan-assets/houseplan-onboarding-runtime-BBCA2XHL.js",
"houseplan-assets/hp-zigbee-topology-overlay-Dl2pPJ8I.js",
"houseplan-assets/iso-scene-render--t3CP3hz.js",
"houseplan-assets/live-interaction-runtime-C1Lqtmd2.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/pdf-export-DkJQi1qx.js",
"houseplan-assets/summary-panel-runtime-loaded-DfBzT94s.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js",
"houseplan-assets/zigbee-topology-runtime-D4vnCsys.js"
],
"lazyGzipBytes": 449074,
"lazyGzipBytes": 450707,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/editor-9cyNd7R7.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-editor-runtime-DFhn-zc9.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/editor-C20ayYMa.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-editor-runtime-DO6W6BMI.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js"
],
"lazyEditorGzipBytes": 231934,
"lazyEditorGzipBytes": 232048,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-onboarding-runtime-BiiaK_3r.js",
"houseplan-assets/namespace-language-B2Cyshho.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-onboarding-runtime-BBCA2XHL.js",
"houseplan-assets/namespace-language-CH9klpdW.js"
],
"lazyOnboardingGzipBytes": 27899,
"lazyOnboardingGzipBytes": 27942,
"lazyLocaleFiles": [
"houseplan-assets/de-C7gyFGpd.js",
"houseplan-assets/fr-BSn1zqYb.js"
"houseplan-assets/de-DHDD9RSi.js",
"houseplan-assets/fr-Ckenu6AU.js"
],
"lazyLocaleGzipBytes": 55699,
"lazyLocaleGzipBytes": 55684,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-xsesUj3A.js"
"houseplan-assets/iso-scene-render--t3CP3hz.js"
],
"lazyIsometricGzipBytes": 17643,
"lazyIsometricGzipBytes": 19194,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js"
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js"
],
"lazyFurnitureArtGzipBytes": 16940,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/pdf-export-BYsRpVk_.js"
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/pdf-export-DkJQi1qx.js"
],
"lazyPdfGzipBytes": 126827,
"lazyPdfGzipBytes": 126823,
"lazyNamespaceLocaleFiles": [
"houseplan-assets/settings-de-BSeiuZ78.js",
"houseplan-assets/settings-fr-Dqa7IIGC.js",
"houseplan-assets/settings-ru-DTjpLI7z.js",
"houseplan-assets/support-de-DkCHsIJX.js",
"houseplan-assets/support-fr-CF5yiuHl.js",
"houseplan-assets/support-ru-Bs7OI6GX.js",
"houseplan-assets/topology-de-BelPUGaW.js",
"houseplan-assets/topology-fr-FvLCzTYk.js",
"houseplan-assets/topology-ru-DG2M1Xdq.js"
"houseplan-assets/settings-de-7bIn6fNv.js",
"houseplan-assets/settings-fr-3J0EZ_-8.js",
"houseplan-assets/settings-ru-B2uE9Qdz.js",
"houseplan-assets/support-de-e4tT4coj.js",
"houseplan-assets/support-fr-MgvbVMC0.js",
"houseplan-assets/support-ru-C1DPLUn9.js",
"houseplan-assets/topology-de-ClOOC81f.js",
"houseplan-assets/topology-fr-BEqsOvuh.js",
"houseplan-assets/topology-ru-DqFgQJka.js"
],
"lazyNamespaceLocaleGzipBytes": 20887,
"lazyNamespaceLocaleGzipBytes": 21035,
"files": [
{
"path": "houseplan-assets/backdrop-pick-D3-yn5HD.js",
"sha256": "9979ee2d9318b8f709993cc91c77968c12ecfb3c3692a16d2ac3a268d5a752c2",
"rawBytes": 53888,
"gzipBytes": 17524,
"path": "houseplan-assets/backdrop-pick-BpwckQhw.js",
"sha256": "73faa27d8d6147f1853699a33b0e82acc8e71b9b023c7ffdadcd3a8add360d1f",
"rawBytes": 54017,
"gzipBytes": 17573,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js"
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js"
],
"dynamicImports": [
"houseplan-assets/settings-de-BSeiuZ78.js",
"houseplan-assets/settings-fr-Dqa7IIGC.js",
"houseplan-assets/settings-ru-DTjpLI7z.js"
"houseplan-assets/settings-de-7bIn6fNv.js",
"houseplan-assets/settings-fr-3J0EZ_-8.js",
"houseplan-assets/settings-ru-B2uE9Qdz.js"
]
},
{
"path": "houseplan-assets/de-C7gyFGpd.js",
"sha256": "eed3905d3c370c5071e7074d4753a769efd3d37d263f21cee2a135ef0dbd6a2c",
"rawBytes": 93083,
"gzipBytes": 28075,
"path": "houseplan-assets/de-DHDD9RSi.js",
"sha256": "9bdaeed82764cae9cfa892d5d25fd256521529734c8b8f926f5cbd02158ef81a",
"rawBytes": 93055,
"gzipBytes": 28066,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-9cyNd7R7.js",
"sha256": "e49468af916efc53baab7dd87825f20b2b2b957dbcae134cfa493e0c9b08ae3a",
"path": "houseplan-assets/editor-C20ayYMa.js",
"sha256": "8febc098ce99ba98bf63839018a796f3f352f2475f00f39b7fe6a4640e71e238",
"rawBytes": 3833,
"gzipBytes": 1583,
"gzipBytes": 1579,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/form-kit.styles-BJpA5NGj.js",
"sha256": "e07f6da05bf8bff00363bc559c8f9ac2c7acc93d0141d37a7570bd02ec1192ca",
"path": "houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"sha256": "74900fd040f932d8c4100fb9576fa0b8313c3a8c130c185c8404ed1f676c24bf",
"rawBytes": 25600,
"gzipBytes": 5056,
"gzipBytes": 5055,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-BSn1zqYb.js",
"sha256": "f0b4b416865b978983c49e1b3321ca3d6f3956a43f7b1576d23e2d81b1a80148",
"rawBytes": 95424,
"gzipBytes": 27624,
"path": "houseplan-assets/fr-Ckenu6AU.js",
"sha256": "6c5a42ee80df955da1453e54ae1ba57b4bf747e21f5574e354a7bef7a867c5b5",
"rawBytes": 95410,
"gzipBytes": 27618,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"sha256": "b5e9e8743651feb5c515d986581bd860a2184d7d64a7744b53acd0c6d7ed0327",
"path": "houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"sha256": "6fe377da376ecdf2bc8274bfe7ae2b68d08b9117ca977e52c174b0e8eb45ac58",
"rawBytes": 52035,
"gzipBytes": 16940,
"isEntry": false,
@@ -149,288 +149,288 @@
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-BCYl6SkQ.js",
"sha256": "6df593e8f6479b0bedf505c29a41a20b4bf53a5977b45e0bf3165400fd3769e0",
"rawBytes": 1030968,
"gzipBytes": 290958,
"path": "houseplan-assets/houseplan-card-bZxsrUlk.js",
"sha256": "cd98d8c4853c8319cbe23cbf4051601f3283a348e468c324ecd0ca25603eb391",
"rawBytes": 1037668,
"gzipBytes": 293203,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-C7gyFGpd.js",
"houseplan-assets/editor-9cyNd7R7.js",
"houseplan-assets/fr-BSn1zqYb.js",
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-editor-runtime-DFhn-zc9.js",
"houseplan-assets/houseplan-onboarding-runtime-BiiaK_3r.js",
"houseplan-assets/hp-zigbee-topology-overlay-D7siZQoq.js",
"houseplan-assets/iso-scene-render-xsesUj3A.js",
"houseplan-assets/live-interaction-runtime-DZWBYZP0.js",
"houseplan-assets/pdf-export-BYsRpVk_.js",
"houseplan-assets/summary-panel-runtime-loaded-gtNYqb9U.js"
"houseplan-assets/de-DHDD9RSi.js",
"houseplan-assets/editor-C20ayYMa.js",
"houseplan-assets/fr-Ckenu6AU.js",
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-editor-runtime-DO6W6BMI.js",
"houseplan-assets/houseplan-onboarding-runtime-BBCA2XHL.js",
"houseplan-assets/hp-zigbee-topology-overlay-Dl2pPJ8I.js",
"houseplan-assets/iso-scene-render--t3CP3hz.js",
"houseplan-assets/live-interaction-runtime-C1Lqtmd2.js",
"houseplan-assets/pdf-export-DkJQi1qx.js",
"houseplan-assets/summary-panel-runtime-loaded-DfBzT94s.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-DFhn-zc9.js",
"sha256": "c0a4a8e337a3e13b0df19eb57938c185d504e6ed89854d514585cd00b4f40197",
"rawBytes": 667315,
"gzipBytes": 186120,
"path": "houseplan-assets/houseplan-editor-runtime-DO6W6BMI.js",
"sha256": "c7176f391361aeb1fc7367851326614c8cc9bb2b5cc00c1ab36a469a628918fc",
"rawBytes": 667537,
"gzipBytes": 186196,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js"
],
"dynamicImports": [
"houseplan-assets/support-de-DkCHsIJX.js",
"houseplan-assets/support-fr-CF5yiuHl.js",
"houseplan-assets/support-ru-Bs7OI6GX.js",
"houseplan-assets/zigbee-topology-runtime-A7rG7kis.js"
"houseplan-assets/support-de-e4tT4coj.js",
"houseplan-assets/support-fr-MgvbVMC0.js",
"houseplan-assets/support-ru-C1DPLUn9.js",
"houseplan-assets/zigbee-topology-runtime-D4vnCsys.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-BiiaK_3r.js",
"sha256": "0d13b9bc17fc152738912ddfb30d0fd8247984c80286cbd6b82d6609c99bff48",
"path": "houseplan-assets/houseplan-onboarding-runtime-BBCA2XHL.js",
"sha256": "8f0f995a25353390d06019250a9e3e28d8b3493571199405cde461a30efc0266",
"rawBytes": 15886,
"gzipBytes": 4909,
"gzipBytes": 4906,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-D3-yn5HD.js",
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js"
"houseplan-assets/backdrop-pick-BpwckQhw.js",
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-D7siZQoq.js",
"sha256": "0254f89b26d8b337c1c4939931cf72938089a0ea326199235320348ff6e085f9",
"path": "houseplan-assets/hp-zigbee-topology-overlay-Dl2pPJ8I.js",
"sha256": "54909e305c1f4b630ca5090fd4d4c43e90009bd9e06e262feb3d86f74fff922a",
"rawBytes": 10958,
"gzipBytes": 3765,
"gzipBytes": 3763,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js",
"houseplan-assets/zigbee-topology-runtime-A7rG7kis.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js",
"houseplan-assets/zigbee-topology-runtime-D4vnCsys.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-xsesUj3A.js",
"sha256": "4f41caad95b99d01013048852c1aa4c147959a8ef10a906dde51f45808e87905",
"rawBytes": 51983,
"gzipBytes": 17643,
"path": "houseplan-assets/iso-scene-render--t3CP3hz.js",
"sha256": "aaf1a1936d043e252a00c1bf6aec427b46a6848262c30224d57f10bc2ce9a72e",
"rawBytes": 56457,
"gzipBytes": 19194,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-DZWBYZP0.js",
"sha256": "aac5a7823e6fd097be076d62534e9b9f1c4290f36b92033d59bf1cac891da300",
"path": "houseplan-assets/live-interaction-runtime-C1Lqtmd2.js",
"sha256": "4def845e9f45a32e1246534620b69bdde9a639dcb0f83cbdfa8ab0e2b63cd4ea",
"rawBytes": 8216,
"gzipBytes": 3207,
"gzipBytes": 3203,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/namespace-language-B2Cyshho.js",
"sha256": "5934f29831a1aecc9503f9afdc8559844dc39e09474b51d26cc917965f27faac",
"path": "houseplan-assets/namespace-language-CH9klpdW.js",
"sha256": "671c38708202959ac0a77814a2d1555372967d4dda7fe4b5c32d9902ec90a38e",
"rawBytes": 675,
"gzipBytes": 410,
"gzipBytes": 408,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-BYsRpVk_.js",
"sha256": "7a4a4d2130fb379cd99681cb6a843e10f81d954bf3c6146d1843bdc9b29027b9",
"path": "houseplan-assets/pdf-export-DkJQi1qx.js",
"sha256": "855a39c362621d9bb1e334934fdd77e880ce63ac5d1f241f1051f5e18608245f",
"rawBytes": 236264,
"gzipBytes": 109887,
"gzipBytes": 109883,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-jmH3jfDa.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/furniture-plan-art.generated-tE3teqBw.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-de-BSeiuZ78.js",
"sha256": "e097b530727671f7473cc5288ae1d71124fa51afb4e4b26e35114d10b2b18e8d",
"rawBytes": 7248,
"gzipBytes": 2825,
"path": "houseplan-assets/settings-de-7bIn6fNv.js",
"sha256": "b0f3a58013cb87b75ef1204fc80c6def3994d6ada06af39a84491ada95ab3afb",
"rawBytes": 7378,
"gzipBytes": 2877,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-fr-Dqa7IIGC.js",
"sha256": "b5597e3b95028ddd220c4bf7b2566455aa5e403d9a3ad2a55dc110cecdc6a33f",
"rawBytes": 7483,
"gzipBytes": 2786,
"path": "houseplan-assets/settings-fr-3J0EZ_-8.js",
"sha256": "d050ba5296b7a18653cbe9776e43ff7d1200ef532ccd24b45ed009570b6f49d6",
"rawBytes": 7620,
"gzipBytes": 2838,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-ru-DTjpLI7z.js",
"sha256": "20b462a7368412ce5c2a5ad378177c963894c6afe8b2a642ae8686477f5e5771",
"rawBytes": 10128,
"gzipBytes": 3271,
"path": "houseplan-assets/settings-ru-B2uE9Qdz.js",
"sha256": "e4a8e3938f2b5d2e66ef2a0c2d31d4afadc51cfe983a0d909453313cb2771aa2",
"rawBytes": 10304,
"gzipBytes": 3323,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-BVcF5FC3.js",
"sha256": "3b55c2b18035ea7d9861e5c1516d9c3a6443a6c042c2943dc2064ef2a51ed09e",
"path": "houseplan-assets/summary-panel-editor-BFR2i2yH.js",
"sha256": "21c2ee89fcea66c547587c57c11beb637f4547fe69befcd1759dbb637e833d6f",
"rawBytes": 14862,
"gzipBytes": 3427,
"gzipBytes": 3423,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/summary-panel-runtime-loaded-gtNYqb9U.js"
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/summary-panel-runtime-loaded-DfBzT94s.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-D9g7eyWm.js",
"sha256": "ca53545e64213080520b779bd051d90e9a6e2d053656fdf2c2ca734b6b9e5982",
"path": "houseplan-assets/summary-panel-metrics-CWPDsUxL.js",
"sha256": "2379e09e9044ffe8f510ac9e46cfc23882b941c557af7be9eac415762e5135cf",
"rawBytes": 2611,
"gzipBytes": 1305,
"gzipBytes": 1304,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-gtNYqb9U.js",
"sha256": "352dc342aca3222c76a922e010001ddc35e22d04c412093d5b294e9b67ab36ff",
"path": "houseplan-assets/summary-panel-runtime-loaded-DfBzT94s.js",
"sha256": "2cb58d8d4a8372e3d6b77cd9e976b072b8bd4869e1fb8d87df14dbef1def50d7",
"rawBytes": 72956,
"gzipBytes": 20242,
"gzipBytes": 20240,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BJpA5NGj.js",
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/form-kit.styles-ZNkFBfYu.js",
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-BVcF5FC3.js",
"houseplan-assets/summary-panel-metrics-D9g7eyWm.js"
"houseplan-assets/summary-panel-editor-BFR2i2yH.js",
"houseplan-assets/summary-panel-metrics-CWPDsUxL.js"
]
},
{
"path": "houseplan-assets/support-de-DkCHsIJX.js",
"sha256": "9bcaa6f84b2df92ccf9b26714a4132d9973efa598b93b25a966ffd290f80c00f",
"path": "houseplan-assets/support-de-e4tT4coj.js",
"sha256": "c9122b8dbc222af6542450f69092286e5c03c06fb48ccfe21fabed394f40a1af",
"rawBytes": 6167,
"gzipBytes": 2396,
"gzipBytes": 2395,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/support-fr-CF5yiuHl.js",
"sha256": "967d72d645f5cd641e4a4d4fae7bf05a6b6a3752545a60c6981ae26c58c008b9",
"path": "houseplan-assets/support-fr-MgvbVMC0.js",
"sha256": "1897e5cded25ce49deb4083c47387c5b3ed84b13c10f37f574578480e7b21207",
"rawBytes": 6333,
"gzipBytes": 2430,
"gzipBytes": 2428,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/support-ru-Bs7OI6GX.js",
"sha256": "63db0be43cdf00a66f24704ecba11224d6cba775fde57b8121a541be991360c3",
"path": "houseplan-assets/support-ru-C1DPLUn9.js",
"sha256": "befc222fa2ea788903bf8fb92e43020c4eae257b057abf09b7ec45f77183bcea",
"rawBytes": 8376,
"gzipBytes": 2875,
"gzipBytes": 2874,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-de-BelPUGaW.js",
"sha256": "6278b6aa3c8ddbb36ebc7ce6fb2b506ab2e6071814e5c78cd6f5241ee81b646b",
"path": "houseplan-assets/topology-de-ClOOC81f.js",
"sha256": "9df4fc278b2f0292026839bc65714843db1c33fcd70e504f41e17840f07fc1be",
"rawBytes": 2698,
"gzipBytes": 1336,
"gzipBytes": 1335,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-fr-FvLCzTYk.js",
"sha256": "40ba15894ef18ef7566796a2cdb21bc8ad82f855c27556e4868d53f39e2fb146",
"path": "houseplan-assets/topology-fr-BEqsOvuh.js",
"sha256": "e5db08f5ade4a3cf6bc9e9d12cfe2d7a2b27b367447da7fe60e0a60d0f251d23",
"rawBytes": 2718,
"gzipBytes": 1354,
"gzipBytes": 1352,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-ru-DG2M1Xdq.js",
"sha256": "e885da0310e6fe62f7b26a3fc8559d857bc03a5c1164146227b59a0532c6994f",
"path": "houseplan-assets/topology-ru-DqFgQJka.js",
"sha256": "1b15021ed72287230896d924d7a229f21aa39ca7a20a8ca3ded1593001da6e1e",
"rawBytes": 3669,
"gzipBytes": 1614,
"gzipBytes": 1613,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-CvQsfSze.js",
"sha256": "e50d18bdc8333469cb81de65c7cbc1f7fc30f47820d90256835c20244e56c9fa",
"path": "houseplan-assets/zigbee-topology-CHnDBF-n.js",
"sha256": "0ff68cb954bbf16359a2c8990c0ddc4f39d7ffa3c51fca4c817eac85fb6e9aa7",
"rawBytes": 10958,
"gzipBytes": 4301,
"gzipBytes": 4297,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js"
],
"dynamicImports": [
"houseplan-assets/topology-de-BelPUGaW.js",
"houseplan-assets/topology-fr-FvLCzTYk.js",
"houseplan-assets/topology-ru-DG2M1Xdq.js"
"houseplan-assets/topology-de-ClOOC81f.js",
"houseplan-assets/topology-fr-BEqsOvuh.js",
"houseplan-assets/topology-ru-DqFgQJka.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-runtime-A7rG7kis.js",
"sha256": "ff4fa95e61e5b87f04b9dbfdb5e4db560039b705ce85a78e0f88c5cc3fe752bf",
"path": "houseplan-assets/zigbee-topology-runtime-D4vnCsys.js",
"sha256": "77d6b691983e517a1d03da1ef1ea3dd5ebe758a665ed1a895da5ce7c960ec177",
"rawBytes": 3983,
"gzipBytes": 1788,
"gzipBytes": 1786,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js",
"houseplan-assets/namespace-language-B2Cyshho.js",
"houseplan-assets/zigbee-topology-CvQsfSze.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js",
"houseplan-assets/namespace-language-CH9klpdW.js",
"houseplan-assets/zigbee-topology-CHnDBF-n.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "da2699ffc51cdc95977a044aafa7ef32645f69eb58311b994d2d578b8697c2c0",
"sha256": "450c1b3ec296407b49219c48890fba431953641a025443e8b0ad27de9714c4ee",
"rawBytes": 1205,
"gzipBytes": 803,
"gzipBytes": 801,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "07baa17cfdd3db6f04aa5027c5796f623976bf6a4e5282255123474d79cd35b2",
"sha256": "ee244a5534da502ce154608cf98907560c7b4f78aba1721a4189b391b6d0d7bc",
"rawBytes": 6165,
"gzipBytes": 2326,
"gzipBytes": 2323,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-BCYl6SkQ.js"
"houseplan-assets/houseplan-card-bZxsrUlk.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,14 +1,14 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{aD as e,l as o,aG as t,ee as s,A as a,ef as i,eg as l,eh as n,E as r,c}from"./houseplan-card-BCYl6SkQ.js";class f extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,f={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},h=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{aD as e,l as o,aG as t,ek as s,A as a,el as i,em as l,en as n,E as r,c}from"./houseplan-card-bZxsrUlk.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
.computeLabel=${e=>f[e.name]||e.name}
.computeLabel=${e=>h[e.name]||e.name}
@value-changed=${this._valueChanged}
></ha-form>`;return c`
${d(h.slice(0,3))}
${d(f.slice(0,3))}
${_?c`<div class="default-floor-error" role="alert"
style="color:var(--error-color,#db4437);margin:-4px 0 12px;overflow-wrap:anywhere">
${t(s,"editor.default_floor_missing",{id:_})}
</div>`:a}
${d(h.slice(3))}
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}f.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",f);
${d(f.slice(3))}
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}h.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",h);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{ej as e,ek as a,eg as n}from"./houseplan-card-BCYl6SkQ.js";function o(n,o){return new e([{code:"en",dictionary:n},{code:"ru",loadDictionary:o.ru},{code:"de",loadDictionary:o.de},{code:"fr",loadDictionary:o.fr}],"5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051",console.warn,a)}function r(e){return function(e,a){return{state:n=>{const o=e.state(n);return"pending"!==o&&a.some(e=>"pending"===e.state(n))?"pending":o},dictionary:a=>e.dictionary(a),ensure:n=>Promise.all([e,...a].map(e=>e.ensure(n))).then(()=>{})}}(n,e)}export{o as n,r as s};
+1
View File
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{ep as e,eq as n,em as c}from"./houseplan-card-bZxsrUlk.js";function a(c,a){return new e([{code:"en",dictionary:c},{code:"ru",loadDictionary:a.ru},{code:"de",loadDictionary:a.de},{code:"fr",loadDictionary:a.fr}],"873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c",console.warn,n)}function o(e){return function(e,n){return{state:c=>{const a=e.state(c);return"pending"!==a&&n.some(e=>"pending"===e.state(c))?"pending":a},dictionary:n=>e.dictionary(n),ensure:c=>Promise.all([e,...n].map(e=>e.ensure(c))).then(()=>{})}}(c,e)}export{a as n,o as s};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{c as a,A as e}from"./houseplan-card-BCYl6SkQ.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-gtNYqb9U.js";import"./form-kit.styles-BJpA5NGj.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{c as a,A as e}from"./houseplan-card-bZxsrUlk.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-DfBzT94s.js";import"./form-kit.styles-ZNkFBfYu.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";import{em as e,N as t,b2 as n,L as i,ae as o,ac as r,bY as s,bX as a,b1 as c,b0 as l,b3 as u,en as d,eo as f,b_ as m,ep as g}from"./houseplan-card-BCYl6SkQ.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,u="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*p(c,l,u=_){try{let d=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;d+=a(v)*_*_/1e4}return d}catch{return null}}function h(e,t,n=_){const i=p(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function b(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{p as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,b as summarySystemValue,h as totalCleanFloorAreaM2};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";import{es as e,N as t,b2 as n,L as i,ae as o,ac as r,bZ as s,bY as a,b1 as c,b0 as l,b3 as u,et as d,eu as f,b$ as m,ev as g}from"./houseplan-card-bZxsrUlk.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,u="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(c,l,u=_){try{let d=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;d+=a(v)*_*_/1e4}return d}catch{return null}}function h(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function p(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,p as summarySystemValue,h as totalCleanFloorAreaM2};
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";var e={title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"};const n="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";export{e as dictionary,n as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";var e={title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"};const n="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";export{e as dictionary,n as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";var e={title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"};const s="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";export{e as dictionary,s as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";var e={title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"};const s="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";export{e as dictionary,s as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";var e={title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"};const a="5c8df099f4dfec9208859aaf7e0462e397d6695e1e9cc1f21a972a698af9e051";export{e as dictionary,a as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";var e={title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"};const t="873dae7f093c03ee384c27ce1e23e1503f2ec0b37ace64383db47d13361ee77c";export{e as dictionary,t as fingerprint};

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