perf: bound isometric overlay collision work

Issue: #160
User-Visible: no
This commit is contained in:
Sergey Matyunin
2026-09-06 09:17:54 +03:00
parent de2155787d
commit f1b9bbf33e
34 changed files with 555 additions and 434 deletions
@@ -1,199 +1,199 @@
{
"schema": 1,
"fingerprint": "f5cac791d009713cb86ce941810e43fba4976300e3e5f0310074b65d585e42f2",
"fingerprint": "58505e23c334e756bdb941b6dd18d00de39044d1b1b52028c2bc1ee04332807a",
"entry": "houseplan-card.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js",
"houseplan-assets/houseplan-card-QFWZI8m6.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 299501,
"initialViewGzipBytes": 299511,
"lazyFiles": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/de-CFmFuWzq.js",
"houseplan-assets/editor-D3B9FzoG.js",
"houseplan-assets/fr-DL7YEG9b.js",
"houseplan-assets/houseplan-editor-runtime-B1Pz5Qxl.js",
"houseplan-assets/houseplan-onboarding-runtime-w3Taqb-I.js",
"houseplan-assets/hp-zigbee-topology-overlay-CsCY64EP.js",
"houseplan-assets/iso-scene-render-BJIdcXVS.js",
"houseplan-assets/live-interaction-runtime-DMHKsxrG.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js",
"houseplan-assets/zigbee-topology-runtime-C-ybyrNs.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/de-DQe-XVD7.js",
"houseplan-assets/editor-CGanHiHV.js",
"houseplan-assets/fr-BYryILXY.js",
"houseplan-assets/houseplan-editor-runtime-BHXdF80I.js",
"houseplan-assets/houseplan-onboarding-runtime-Dsp5UfQ0.js",
"houseplan-assets/hp-zigbee-topology-overlay-B8bTARmd.js",
"houseplan-assets/iso-scene-render-CPJ_aYf_.js",
"houseplan-assets/live-interaction-runtime-CMojDls2.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js",
"houseplan-assets/zigbee-topology-runtime-CVqwFK1r.js"
],
"lazyGzipBytes": 263425,
"lazyGzipBytes": 263852,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/editor-D3B9FzoG.js",
"houseplan-assets/houseplan-editor-runtime-B1Pz5Qxl.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/editor-CGanHiHV.js",
"houseplan-assets/houseplan-editor-runtime-BHXdF80I.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js"
],
"lazyEditorGzipBytes": 186635,
"lazyEditorGzipBytes": 186643,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/houseplan-onboarding-runtime-w3Taqb-I.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/houseplan-onboarding-runtime-Dsp5UfQ0.js"
],
"lazyOnboardingGzipBytes": 14326,
"lazyOnboardingGzipBytes": 14331,
"lazyLocaleFiles": [
"houseplan-assets/de-CFmFuWzq.js",
"houseplan-assets/fr-DL7YEG9b.js"
"houseplan-assets/de-DQe-XVD7.js",
"houseplan-assets/fr-BYryILXY.js"
],
"lazyLocaleGzipBytes": 50157,
"lazyLocaleGzipBytes": 50152,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-BJIdcXVS.js"
"houseplan-assets/iso-scene-render-CPJ_aYf_.js"
],
"lazyIsometricGzipBytes": 12043,
"lazyIsometricGzipBytes": 12457,
"files": [
{
"path": "houseplan-assets/backdrop-pick-BdfZNhPk.js",
"sha256": "0a8698a964c832d2c3bb0511bd8ba8b6c61815d3446efe137827d27341b4f22a",
"path": "houseplan-assets/backdrop-pick-My-VJARv.js",
"sha256": "cd656539e7e819187ffee1c886b20e3af24e0db065955485d7f03f0c8cec3b5d",
"rawBytes": 21592,
"gzipBytes": 7359,
"gzipBytes": 7360,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-CFmFuWzq.js",
"sha256": "13e330d5f6bf8eb869b16b908ad22e86a2b43950b74b8a27713dadc8926857c2",
"path": "houseplan-assets/de-DQe-XVD7.js",
"sha256": "e4404e40fa899cc1ea6f0ade19b8cb5e7154236569b7efedc33a5e9abfbdb61f",
"rawBytes": 84232,
"gzipBytes": 25356,
"gzipBytes": 25353,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-D3B9FzoG.js",
"sha256": "46b0c5cbb84829f75d00f69765f82399cc8b5e6c54bba54a27ce4bb9210467cf",
"path": "houseplan-assets/editor-CGanHiHV.js",
"sha256": "2b1070116961c26c7c20a1d7ff5fd31bd0f8f26e11e8b0cf74f095efa6d7be21",
"rawBytes": 3831,
"gzipBytes": 1586,
"gzipBytes": 1587,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-DL7YEG9b.js",
"sha256": "93194b66ec63e5923a0da05b8d93f7ca5cbee2f896cbaa291d3225b15bb3dd13",
"path": "houseplan-assets/fr-BYryILXY.js",
"sha256": "9b926d6d212cfc1419433fc683371114670b6622de716a32ec9e4ab029880402",
"rawBytes": 86273,
"gzipBytes": 24801,
"gzipBytes": 24799,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-D6Qc0AL6.js",
"sha256": "9d84d3866d723ee7edad4c49f4f83f4c6a35331c5b4b942470d3745752ee0a9c",
"rawBytes": 1072059,
"gzipBytes": 298704,
"path": "houseplan-assets/houseplan-card-QFWZI8m6.js",
"sha256": "1c901826c5ba5b6aaca02fa1b270fc2b27fee2a72a9c30b8c33004ce9c32eb1a",
"rawBytes": 1072087,
"gzipBytes": 298713,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-CFmFuWzq.js",
"houseplan-assets/editor-D3B9FzoG.js",
"houseplan-assets/fr-DL7YEG9b.js",
"houseplan-assets/houseplan-editor-runtime-B1Pz5Qxl.js",
"houseplan-assets/houseplan-onboarding-runtime-w3Taqb-I.js",
"houseplan-assets/hp-zigbee-topology-overlay-CsCY64EP.js",
"houseplan-assets/iso-scene-render-BJIdcXVS.js",
"houseplan-assets/live-interaction-runtime-DMHKsxrG.js"
"houseplan-assets/de-DQe-XVD7.js",
"houseplan-assets/editor-CGanHiHV.js",
"houseplan-assets/fr-BYryILXY.js",
"houseplan-assets/houseplan-editor-runtime-BHXdF80I.js",
"houseplan-assets/houseplan-onboarding-runtime-Dsp5UfQ0.js",
"houseplan-assets/hp-zigbee-topology-overlay-B8bTARmd.js",
"houseplan-assets/iso-scene-render-CPJ_aYf_.js",
"houseplan-assets/live-interaction-runtime-CMojDls2.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-B1Pz5Qxl.js",
"sha256": "6b4ac9f766aa97c463707544e20e18b9e5a8513fdfb481dbd38e881afa4b23c8",
"path": "houseplan-assets/houseplan-editor-runtime-BHXdF80I.js",
"sha256": "bb2ca6b3feb7367ee6edceaccca0fed6926998873fba75bfca98eb871d664c7d",
"rawBytes": 639587,
"gzipBytes": 170265,
"gzipBytes": 170270,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/houseplan-card-D6Qc0AL6.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/houseplan-card-QFWZI8m6.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js"
],
"dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-C-ybyrNs.js"
"houseplan-assets/zigbee-topology-runtime-CVqwFK1r.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-w3Taqb-I.js",
"sha256": "908d4ad5f067a7dfcb299e810c790063bce1e8b32e9b40c509e829510a330478",
"path": "houseplan-assets/houseplan-onboarding-runtime-Dsp5UfQ0.js",
"sha256": "7f1813a03a58789b6ec850652433a30b14d591ef7f254ffe942bd6c1a159b0c9",
"rawBytes": 28071,
"gzipBytes": 6967,
"gzipBytes": 6971,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-CsCY64EP.js",
"sha256": "f2393f6191fe920e57df088e39332e9aafc7367b63cb49e08f9054ec94a4be1c",
"path": "houseplan-assets/hp-zigbee-topology-overlay-B8bTARmd.js",
"sha256": "12af34c9a9d09074b420dd03aafd30fb7f181893548cfd2f2a662b8ef6bc47f7",
"rawBytes": 11034,
"gzipBytes": 3732,
"gzipBytes": 3735,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js",
"houseplan-assets/zigbee-topology-runtime-C-ybyrNs.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js",
"houseplan-assets/zigbee-topology-runtime-CVqwFK1r.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-BJIdcXVS.js",
"sha256": "10d7c04fb74c4a70252bc2a218459a18beb1fc4e6c1316da9a08a66bc80bd05f",
"rawBytes": 35885,
"gzipBytes": 12043,
"path": "houseplan-assets/iso-scene-render-CPJ_aYf_.js",
"sha256": "abcf3a4a0ed1b1eb6043de6a8819613a710ee23c12f4e52e7b33f2b27f4c131c",
"rawBytes": 36988,
"gzipBytes": 12457,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-DMHKsxrG.js",
"sha256": "63d582dfee60251af1f1afb393328fdc86a44379d0fe7536c5f7e71a26c3c5c0",
"path": "houseplan-assets/live-interaction-runtime-CMojDls2.js",
"sha256": "87f0e123ab282a98b66c68cd9d5a161466949ea0f855b12e36d96a67e32c5d45",
"rawBytes": 5196,
"gzipBytes": 2127,
"gzipBytes": 2129,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-hm8kNj1e.js",
"sha256": "7f91d6086813f4ad1a8644943080b53a4474bb698b81328a2ee8bf288558cd62",
"path": "houseplan-assets/zigbee-topology-C-2fV84O.js",
"sha256": "48d42fbd437350b034a9e687b9ea6ce3138db244f6787a062db56dd587f272ea",
"rawBytes": 18961,
"gzipBytes": 7425,
"gzipBytes": 7426,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-runtime-C-ybyrNs.js",
"sha256": "fb63090585f8d45e8a0c0fddc10d4f37682126fe2b54717bb4c73d0314a4888b",
"path": "houseplan-assets/zigbee-topology-runtime-CVqwFK1r.js",
"sha256": "251314c84ae9696ffde45790623dfed78b0720bf59e793e8b6b12fa78a5081b3",
"rawBytes": 3941,
"gzipBytes": 1764,
"gzipBytes": 1765,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "75189cf8f3426b9235fcf3c844e53293670633f06eca9fb852ec61463b75e240",
"sha256": "2e0896981cddc78cead21b868d3bd39a3c4cdd76d9c50420f2a7c00fe53cfd37",
"rawBytes": 1183,
"gzipBytes": 797,
"gzipBytes": 798,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
@@ -1,14 +1,14 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f5cac791d009713cb86ce941810e43fba4976300e3e5f0310074b65d585e42f2";import{v as e,l as o,z as t,dK as s,A as a,dL as i,dM as l,dN as n,E as r,c}from"./houseplan-card-D6Qc0AL6.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
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="58505e23c334e756bdb941b6dd18d00de39044d1b1b52028c2bc1ee04332807a";import{v as e,l as o,z as t,dK as s,A as a,dL as i,dM as l,dN as n,E as r,c}from"./houseplan-card-QFWZI8m6.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")},_=this._schema,f=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=>h[e.name]||e.name}
@value-changed=${this._valueChanged}
></ha-form>`;return c`
${d(f.slice(0,3))}
${_?c`<div class="default-floor-error" role="alert"
${d(_.slice(0,3))}
${f?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:_})}
${t(s,"editor.default_floor_missing",{id:f})}
</div>`:a}
${d(f.slice(3))}
${d(_.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
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f5cac791d009713cb86ce941810e43fba4976300e3e5f0310074b65d585e42f2";import{n as t,b as n}from"./zigbee-topology-hm8kNj1e.js";import{I as e}from"./houseplan-card-D6Qc0AL6.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};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="58505e23c334e756bdb941b6dd18d00de39044d1b1b52028c2bc1ee04332807a";import{n as t,b as n}from"./zigbee-topology-C-2fV84O.js";import{I as e}from"./houseplan-card-QFWZI8m6.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__="f5cac791d009713cb86ce941810e43fba4976300e3e5f0310074b65d585e42f2";try{await import("./houseplan-assets/houseplan-card-D6Qc0AL6.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 entry: the main chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="58505e23c334e756bdb941b6dd18d00de39044d1b1b52028c2bc1ee04332807a";try{await import("./houseplan-assets/houseplan-card-QFWZI8m6.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 entry: the main chunk is unavailable",e)}
+93 -93
View File
@@ -1,199 +1,199 @@
{
"schema": 1,
"fingerprint": "f5cac791d009713cb86ce941810e43fba4976300e3e5f0310074b65d585e42f2",
"fingerprint": "58505e23c334e756bdb941b6dd18d00de39044d1b1b52028c2bc1ee04332807a",
"entry": "houseplan-card.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js",
"houseplan-assets/houseplan-card-QFWZI8m6.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 299501,
"initialViewGzipBytes": 299511,
"lazyFiles": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/de-CFmFuWzq.js",
"houseplan-assets/editor-D3B9FzoG.js",
"houseplan-assets/fr-DL7YEG9b.js",
"houseplan-assets/houseplan-editor-runtime-B1Pz5Qxl.js",
"houseplan-assets/houseplan-onboarding-runtime-w3Taqb-I.js",
"houseplan-assets/hp-zigbee-topology-overlay-CsCY64EP.js",
"houseplan-assets/iso-scene-render-BJIdcXVS.js",
"houseplan-assets/live-interaction-runtime-DMHKsxrG.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js",
"houseplan-assets/zigbee-topology-runtime-C-ybyrNs.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/de-DQe-XVD7.js",
"houseplan-assets/editor-CGanHiHV.js",
"houseplan-assets/fr-BYryILXY.js",
"houseplan-assets/houseplan-editor-runtime-BHXdF80I.js",
"houseplan-assets/houseplan-onboarding-runtime-Dsp5UfQ0.js",
"houseplan-assets/hp-zigbee-topology-overlay-B8bTARmd.js",
"houseplan-assets/iso-scene-render-CPJ_aYf_.js",
"houseplan-assets/live-interaction-runtime-CMojDls2.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js",
"houseplan-assets/zigbee-topology-runtime-CVqwFK1r.js"
],
"lazyGzipBytes": 263425,
"lazyGzipBytes": 263852,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/editor-D3B9FzoG.js",
"houseplan-assets/houseplan-editor-runtime-B1Pz5Qxl.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/editor-CGanHiHV.js",
"houseplan-assets/houseplan-editor-runtime-BHXdF80I.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js"
],
"lazyEditorGzipBytes": 186635,
"lazyEditorGzipBytes": 186643,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/houseplan-onboarding-runtime-w3Taqb-I.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/houseplan-onboarding-runtime-Dsp5UfQ0.js"
],
"lazyOnboardingGzipBytes": 14326,
"lazyOnboardingGzipBytes": 14331,
"lazyLocaleFiles": [
"houseplan-assets/de-CFmFuWzq.js",
"houseplan-assets/fr-DL7YEG9b.js"
"houseplan-assets/de-DQe-XVD7.js",
"houseplan-assets/fr-BYryILXY.js"
],
"lazyLocaleGzipBytes": 50157,
"lazyLocaleGzipBytes": 50152,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-BJIdcXVS.js"
"houseplan-assets/iso-scene-render-CPJ_aYf_.js"
],
"lazyIsometricGzipBytes": 12043,
"lazyIsometricGzipBytes": 12457,
"files": [
{
"path": "houseplan-assets/backdrop-pick-BdfZNhPk.js",
"sha256": "0a8698a964c832d2c3bb0511bd8ba8b6c61815d3446efe137827d27341b4f22a",
"path": "houseplan-assets/backdrop-pick-My-VJARv.js",
"sha256": "cd656539e7e819187ffee1c886b20e3af24e0db065955485d7f03f0c8cec3b5d",
"rawBytes": 21592,
"gzipBytes": 7359,
"gzipBytes": 7360,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-CFmFuWzq.js",
"sha256": "13e330d5f6bf8eb869b16b908ad22e86a2b43950b74b8a27713dadc8926857c2",
"path": "houseplan-assets/de-DQe-XVD7.js",
"sha256": "e4404e40fa899cc1ea6f0ade19b8cb5e7154236569b7efedc33a5e9abfbdb61f",
"rawBytes": 84232,
"gzipBytes": 25356,
"gzipBytes": 25353,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-D3B9FzoG.js",
"sha256": "46b0c5cbb84829f75d00f69765f82399cc8b5e6c54bba54a27ce4bb9210467cf",
"path": "houseplan-assets/editor-CGanHiHV.js",
"sha256": "2b1070116961c26c7c20a1d7ff5fd31bd0f8f26e11e8b0cf74f095efa6d7be21",
"rawBytes": 3831,
"gzipBytes": 1586,
"gzipBytes": 1587,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-DL7YEG9b.js",
"sha256": "93194b66ec63e5923a0da05b8d93f7ca5cbee2f896cbaa291d3225b15bb3dd13",
"path": "houseplan-assets/fr-BYryILXY.js",
"sha256": "9b926d6d212cfc1419433fc683371114670b6622de716a32ec9e4ab029880402",
"rawBytes": 86273,
"gzipBytes": 24801,
"gzipBytes": 24799,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-D6Qc0AL6.js",
"sha256": "9d84d3866d723ee7edad4c49f4f83f4c6a35331c5b4b942470d3745752ee0a9c",
"rawBytes": 1072059,
"gzipBytes": 298704,
"path": "houseplan-assets/houseplan-card-QFWZI8m6.js",
"sha256": "1c901826c5ba5b6aaca02fa1b270fc2b27fee2a72a9c30b8c33004ce9c32eb1a",
"rawBytes": 1072087,
"gzipBytes": 298713,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-CFmFuWzq.js",
"houseplan-assets/editor-D3B9FzoG.js",
"houseplan-assets/fr-DL7YEG9b.js",
"houseplan-assets/houseplan-editor-runtime-B1Pz5Qxl.js",
"houseplan-assets/houseplan-onboarding-runtime-w3Taqb-I.js",
"houseplan-assets/hp-zigbee-topology-overlay-CsCY64EP.js",
"houseplan-assets/iso-scene-render-BJIdcXVS.js",
"houseplan-assets/live-interaction-runtime-DMHKsxrG.js"
"houseplan-assets/de-DQe-XVD7.js",
"houseplan-assets/editor-CGanHiHV.js",
"houseplan-assets/fr-BYryILXY.js",
"houseplan-assets/houseplan-editor-runtime-BHXdF80I.js",
"houseplan-assets/houseplan-onboarding-runtime-Dsp5UfQ0.js",
"houseplan-assets/hp-zigbee-topology-overlay-B8bTARmd.js",
"houseplan-assets/iso-scene-render-CPJ_aYf_.js",
"houseplan-assets/live-interaction-runtime-CMojDls2.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-B1Pz5Qxl.js",
"sha256": "6b4ac9f766aa97c463707544e20e18b9e5a8513fdfb481dbd38e881afa4b23c8",
"path": "houseplan-assets/houseplan-editor-runtime-BHXdF80I.js",
"sha256": "bb2ca6b3feb7367ee6edceaccca0fed6926998873fba75bfca98eb871d664c7d",
"rawBytes": 639587,
"gzipBytes": 170265,
"gzipBytes": 170270,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/houseplan-card-D6Qc0AL6.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/houseplan-card-QFWZI8m6.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js"
],
"dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-C-ybyrNs.js"
"houseplan-assets/zigbee-topology-runtime-CVqwFK1r.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-w3Taqb-I.js",
"sha256": "908d4ad5f067a7dfcb299e810c790063bce1e8b32e9b40c509e829510a330478",
"path": "houseplan-assets/houseplan-onboarding-runtime-Dsp5UfQ0.js",
"sha256": "7f1813a03a58789b6ec850652433a30b14d591ef7f254ffe942bd6c1a159b0c9",
"rawBytes": 28071,
"gzipBytes": 6967,
"gzipBytes": 6971,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-BdfZNhPk.js",
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/backdrop-pick-My-VJARv.js",
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-CsCY64EP.js",
"sha256": "f2393f6191fe920e57df088e39332e9aafc7367b63cb49e08f9054ec94a4be1c",
"path": "houseplan-assets/hp-zigbee-topology-overlay-B8bTARmd.js",
"sha256": "12af34c9a9d09074b420dd03aafd30fb7f181893548cfd2f2a662b8ef6bc47f7",
"rawBytes": 11034,
"gzipBytes": 3732,
"gzipBytes": 3735,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js",
"houseplan-assets/zigbee-topology-runtime-C-ybyrNs.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js",
"houseplan-assets/zigbee-topology-runtime-CVqwFK1r.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-BJIdcXVS.js",
"sha256": "10d7c04fb74c4a70252bc2a218459a18beb1fc4e6c1316da9a08a66bc80bd05f",
"rawBytes": 35885,
"gzipBytes": 12043,
"path": "houseplan-assets/iso-scene-render-CPJ_aYf_.js",
"sha256": "abcf3a4a0ed1b1eb6043de6a8819613a710ee23c12f4e52e7b33f2b27f4c131c",
"rawBytes": 36988,
"gzipBytes": 12457,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-DMHKsxrG.js",
"sha256": "63d582dfee60251af1f1afb393328fdc86a44379d0fe7536c5f7e71a26c3c5c0",
"path": "houseplan-assets/live-interaction-runtime-CMojDls2.js",
"sha256": "87f0e123ab282a98b66c68cd9d5a161466949ea0f855b12e36d96a67e32c5d45",
"rawBytes": 5196,
"gzipBytes": 2127,
"gzipBytes": 2129,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-hm8kNj1e.js",
"sha256": "7f91d6086813f4ad1a8644943080b53a4474bb698b81328a2ee8bf288558cd62",
"path": "houseplan-assets/zigbee-topology-C-2fV84O.js",
"sha256": "48d42fbd437350b034a9e687b9ea6ce3138db244f6787a062db56dd587f272ea",
"rawBytes": 18961,
"gzipBytes": 7425,
"gzipBytes": 7426,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-runtime-C-ybyrNs.js",
"sha256": "fb63090585f8d45e8a0c0fddc10d4f37682126fe2b54717bb4c73d0314a4888b",
"path": "houseplan-assets/zigbee-topology-runtime-CVqwFK1r.js",
"sha256": "251314c84ae9696ffde45790623dfed78b0720bf59e793e8b6b12fa78a5081b3",
"rawBytes": 3941,
"gzipBytes": 1764,
"gzipBytes": 1765,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js",
"houseplan-assets/zigbee-topology-hm8kNj1e.js"
"houseplan-assets/houseplan-card-QFWZI8m6.js",
"houseplan-assets/zigbee-topology-C-2fV84O.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "75189cf8f3426b9235fcf3c844e53293670633f06eca9fb852ec61463b75e240",
"sha256": "2e0896981cddc78cead21b868d3bd39a3c4cdd76d9c50420f2a7c00fe53cfd37",
"rawBytes": 1183,
"gzipBytes": 797,
"gzipBytes": 798,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-D6Qc0AL6.js"
"houseplan-assets/houseplan-card-QFWZI8m6.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__="f5cac791d009713cb86ce941810e43fba4976300e3e5f0310074b65d585e42f2";import{v as e,l as o,z as t,dK as s,A as a,dL as i,dM as l,dN as n,E as r,c}from"./houseplan-card-D6Qc0AL6.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
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="58505e23c334e756bdb941b6dd18d00de39044d1b1b52028c2bc1ee04332807a";import{v as e,l as o,z as t,dK as s,A as a,dL as i,dM as l,dN as n,E as r,c}from"./houseplan-card-QFWZI8m6.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")},_=this._schema,f=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=>h[e.name]||e.name}
@value-changed=${this._valueChanged}
></ha-form>`;return c`
${d(f.slice(0,3))}
${_?c`<div class="default-floor-error" role="alert"
${d(_.slice(0,3))}
${f?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:_})}
${t(s,"editor.default_floor_missing",{id:f})}
</div>`:a}
${d(f.slice(3))}
${d(_.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 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f5cac791d009713cb86ce941810e43fba4976300e3e5f0310074b65d585e42f2";import{n as t,b as n}from"./zigbee-topology-hm8kNj1e.js";import{I as e}from"./houseplan-card-D6Qc0AL6.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};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="58505e23c334e756bdb941b6dd18d00de39044d1b1b52028c2bc1ee04332807a";import{n as t,b as n}from"./zigbee-topology-C-2fV84O.js";import{I as e}from"./houseplan-card-QFWZI8m6.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
View File
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f5cac791d009713cb86ce941810e43fba4976300e3e5f0310074b65d585e42f2";try{await import("./houseplan-assets/houseplan-card-D6Qc0AL6.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 entry: the main chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="58505e23c334e756bdb941b6dd18d00de39044d1b1b52028c2bc1ee04332807a";try{await import("./houseplan-assets/houseplan-card-QFWZI8m6.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 entry: the main chunk is unavailable",e)}
+3 -1
View File
@@ -6119,7 +6119,7 @@ export class HouseplanCard extends LitElement {
const overlays = this._isoOverlayScene(
space, this._renderDevices.filter((device) => device.space === space.id && !device.hidden),
baseView, disp, runtime.resolveIsoDecorationLayers(disp), scene, iconPct, effectiveDeviceBaseSize(iconPct),
disp.showLqi ?? this._config?.show_signal ?? true);
disp.showLqi ?? this._config?.show_signal ?? true, false);
const envelope = overlays && runtime.resolveIsoOverlayFitEnvelope({
baseBounds: scene.frame, entries: overlays.entries, stageSize, targetView: (bounds) =>
fitView([bounds.x, bounds.y, bounds.w, bounds.h], aspect) });
@@ -6179,12 +6179,14 @@ export class HouseplanCard extends LitElement {
iconPct: number,
deviceBasePct: number,
showLqi: boolean,
resolveCollisions = true,
): IsoOverlayRenderScene | null {
const runtime = this._isoSceneRuntime;
if (!runtime || !layers?.structural || !structural) return null;
return runtime.buildIsoOverlayRenderScene({
space, devices: devs, openings: this._openingsR, view, display: disp, layers,
wallSilhouettes: structural.wallSilhouettes,
resolveCollisions,
iconPct, deviceBasePct, showLqi, cellCm: this._cellCm,
kioskIconScale: this._kiosk ? this._kioskScale.icon : 1,
kioskFontScale: this._kiosk ? this._kioskScale.font : 1,
+48 -6
View File
@@ -43,11 +43,15 @@ export interface IsoOverlayOwnerInput {
rooms: readonly IsoOverlayRoom[];
/** Device binding, room label owner, or the room selected by opening-host geometry. */
preferredRoomId?: string | null;
/** Internal fast path for room rows already normalised by isoOverlayRooms(). */
roomsValidated?: boolean;
}
export interface IsoOverlayPlacementInput extends IsoOverlayOwnerInput {
showBorders: boolean;
wallSilhouettes: readonly IsoWallSilhouette[];
/** Internal fast path for silhouettes produced by the cached structural scene. */
wallGeometryValidated?: boolean;
/** Half-size of the floor-parallel plate in plan units. */
plateHalfSize: PlanPoint;
wallHeight?: number;
@@ -225,7 +229,7 @@ const stableIdCompare = (a: string, b: string): number => a < b ? -1 : a > b ? 1
export function resolveIsoOverlayOwner(input: IsoOverlayOwnerInput): IsoOverlayOwner | null {
if (!finitePoint(input.floorAnchor)) return null;
const rooms = input.rooms.filter(validRoom);
const rooms = input.roomsValidated ? input.rooms : input.rooms.filter(validRoom);
const preferred = input.preferredRoomId
? rooms.find((room) => room.id === input.preferredRoomId) || null
: null;
@@ -241,7 +245,12 @@ export function resolveIsoOverlayOwner(input: IsoOverlayOwnerInput): IsoOverlayO
// a saved label may legitimately lie outside that room.
room = preferred;
}
return room ? { id: room.id, area: roomArea(room), safePoint: isoRoomSafePoint(room) } : null;
return room ? {
id: room.id,
area: roomArea(room),
safePoint: input.roomsValidated && room.safePoint
? [room.safePoint[0], room.safePoint[1]] : isoRoomSafePoint(room),
} : null;
}
export function isoOverlayPlane(kind: IsoOverlayKind, showBorders: boolean): IsoOverlayPlane {
@@ -300,9 +309,39 @@ function pointInSilhouette(point: ScenePoint, silhouette: IsoWallSilhouette): bo
return !(silhouette.holes || []).some((hole) => pointInRing(point, hole));
}
type Bounds = readonly [minX: number, minY: number, maxX: number, maxY: number];
const silhouetteBoundsCache = new WeakMap<IsoWallSilhouette, Bounds | null>();
function ringBounds(ring: readonly (readonly number[])[]): Bounds | null {
if (!ring.length) return null;
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
for (const point of ring) {
if (!finitePoint(point)) return null;
minX = Math.min(minX, point[0]); minY = Math.min(minY, point[1]);
maxX = Math.max(maxX, point[0]); maxY = Math.max(maxY, point[1]);
}
return [minX, minY, maxX, maxY];
}
function silhouetteBounds(silhouette: IsoWallSilhouette, cache: boolean): Bounds | null {
if (!cache) return ringBounds(silhouette.outer);
if (silhouetteBoundsCache.has(silhouette)) return silhouetteBoundsCache.get(silhouette) ?? null;
const bounds = ringBounds(silhouette.outer);
silhouetteBoundsCache.set(silhouette, bounds);
return bounds;
}
function boundsNear(a: Bounds, b: Bounds, gap: number): boolean {
return a[0] <= b[2] + gap && a[2] >= b[0] - gap
&& a[1] <= b[3] + gap && a[3] >= b[1] - gap;
}
function plateNearSilhouette(
plate: readonly ScenePoint[], silhouette: IsoWallSilhouette, gap: number,
plate: readonly ScenePoint[], plateBounds: Bounds,
silhouette: IsoWallSilhouette, gap: number, cacheBounds: boolean,
): boolean {
const wallBounds = silhouetteBounds(silhouette, cacheBounds);
if (!wallBounds || !boundsNear(plateBounds, wallBounds, gap)) return false;
if (plate.some((point) => pointInSilhouette(point, silhouette))) return true;
if (silhouette.outer.some((point) => pointInRing(point, plate))) return true;
for (const wallRing of [silhouette.outer, ...(silhouette.holes || [])]) {
@@ -380,12 +419,15 @@ export function resolveIsoOverlayPlacement(input: IsoOverlayPlacementInput): Iso
const raisedHeight = wallHeight + visualOffset;
const raisedScene = projectPlanPoint(floorAnchor, raisedHeight, camera);
const owner = resolveIsoOverlayOwner(input);
const geometryValid = input.wallSilhouettes.every(validSilhouette);
const geometryValid = input.wallGeometryValidated ?? input.wallSilhouettes.every(validSilhouette);
const gapUnits = safetyGap * unitsPerPixel;
const basePlate = buildIsoPlatePolygon(floorAnchor, input.plateHalfSize,
raisedHeight, camera);
const isNear = (plate: readonly ScenePoint[]): boolean =>
input.wallSilhouettes.some((wall) => plateNearSilhouette(plate, wall, gapUnits));
const isNear = (plate: readonly ScenePoint[]): boolean => {
const bounds = ringBounds(plate);
return !!bounds && input.wallSilhouettes.some((wall) =>
plateNearSilhouette(plate, bounds, wall, gapUnits, input.wallGeometryValidated === true));
};
const nearWallBefore = geometryValid ? isNear(basePlate) : true;
let distanceCss = 0;
+41 -17
View File
@@ -685,6 +685,8 @@ export interface IsoOverlaySceneInput {
display: SpaceDisplay;
layers: IsoDecorationLayers;
wallSilhouettes: readonly IsoWallSilhouette[];
/** Fit-envelope probes need unnudged bounds only, not wall collision search. */
resolveCollisions?: boolean;
iconPct: number;
deviceBasePct: number;
showLqi: boolean;
@@ -705,6 +707,11 @@ export interface IsoOverlaySceneInput {
type IsoOverlayRoomRow = { room: RoomCfg; overlayRoom: IsoOverlayRoom };
const isoOverlayRoomCache = new WeakMap<readonly RoomCfg[], readonly IsoOverlayRoomRow[]>();
type IsoOverlayPlacementCacheEntry = { signature: string; placement: IsoOverlayPlacement };
export const ISO_OVERLAY_PLACEMENT_CACHE_LIMIT = 2048;
const isoOverlayPlacementCache = new WeakMap<
readonly IsoWallSilhouette[], Map<string, IsoOverlayPlacementCacheEntry>
>();
/** Build legal island-room holes once per immutable room snapshot. */
export function isoOverlayRooms(space: SpaceModel): readonly IsoOverlayRoomRow[] {
@@ -740,6 +747,11 @@ export function buildIsoOverlayRenderScene(input: IsoOverlaySceneInput): IsoOver
const roomPlacements = new Map<RoomCfg, IsoOverlayPlacement>();
const locks = new Map<string, IsoOverlayPlacement>();
const entries: IsoOverlayRenderEntry[] = [];
let placements = isoOverlayPlacementCache.get(input.wallSilhouettes);
if (!placements) {
placements = new Map();
isoOverlayPlacementCache.set(input.wallSilhouettes, placements);
}
const baseIconUnits = input.iconPct * iconUnit(input.space) * input.kioskIconScale / 100;
const baseDeviceUnits = input.deviceBasePct * iconUnit(input.space) * input.kioskIconScale / 100;
const place = (
@@ -749,23 +761,35 @@ export function buildIsoOverlayRenderScene(input: IsoOverlaySceneInput): IsoOver
plateHalfSize: PlanPoint,
preferredRoomId?: string | null,
selected = false,
): IsoOverlayPlacement => resolveIsoOverlayPlacement({
kind,
floorAnchor,
rooms,
preferredRoomId,
showBorders: true,
wallSilhouettes: input.wallSilhouettes,
plateHalfSize,
wallHeight,
visualOffset,
sceneUnitsPerCssPixel: unitsPerPixel,
filtersSupported: input.layers.shadows,
// A persistent tether keeps ownership explicit without a second hover-only
// render pipeline for the inert raised geometry.
hovered: true,
selected,
});
): IsoOverlayPlacement => {
const collisionMode = input.resolveCollisions === false ? 'fit' : 'live';
const cacheKey = `${collisionMode}\u0000${kind}\u0000${id}`;
const signature = [floorAnchor[0], floorAnchor[1], plateHalfSize[0], plateHalfSize[1],
preferredRoomId || '', wallHeight, visualOffset, unitsPerPixel,
input.layers.shadows ? 1 : 0, selected ? 1 : 0].join('|');
const cached = lruRead(placements!, cacheKey);
if (cached.hit && cached.value.signature === signature) return cached.value.placement;
const placement = resolveIsoOverlayPlacement({
kind,
floorAnchor,
rooms, roomsValidated: true,
preferredRoomId,
showBorders: true,
wallSilhouettes: input.resolveCollisions === false ? [] : input.wallSilhouettes,
wallGeometryValidated: true,
plateHalfSize,
wallHeight,
visualOffset,
sceneUnitsPerCssPixel: unitsPerPixel,
filtersSupported: input.layers.shadows,
// A persistent tether keeps ownership explicit without a second hover-only
// render pipeline for the inert raised geometry.
hovered: true,
selected,
});
lruWrite(placements!, cacheKey, { signature, placement }, ISO_OVERLAY_PLACEMENT_CACHE_LIMIT);
return placement;
};
for (const device of input.devices) {
const pos = input.positionOf(device);
+53
View File
@@ -23,6 +23,7 @@ import { ISO_OPENING_GEOMETRY_POLICY } from '../test-build/iso-openings.js';
import { buildIsoWallGeometry } from '../test-build/iso-walls.js';
import { wallKey } from '../test-build/wall-thickness.js';
import {
buildIsoPlatePolygon,
resolveIsoOverlayOwner,
resolveIsoOverlayPlacement,
} from '../test-build/iso-overlays.js';
@@ -337,6 +338,58 @@ test('opening lock without a canonical host owner never guesses from point conta
assert.equal(placement?.tether.visible, true);
});
test('Stage 3 reuses pure overlay placements and fit probes skip collision search', () => {
const owner = room('owner', 0, 0, 100, 100);
const space = {
id: 'floor', title: 'Floor', cellCm: 5, vb: [0, 0, 100, 100], bg: null,
rooms: [owner], wall_segments: [], room_drafts: [], partitions: [], wall_columns: [],
};
const wallSilhouettes = [{
outer: buildIsoPlatePolygon([50, 50], [8, 60], ISO_WALL_HEIGHT),
}];
const input = {
space,
devices: [{ id: 'device', space: 'floor', marker: { room_id: 'owner' } }],
openings: [],
view: { x: 0, y: 0, w: 100, h: 100 },
display: { showNames: false, cardFontScale: 1 },
layers: { structural: true, shadows: true },
wallSilhouettes,
iconPct: 3.4,
deviceBasePct: 3.4,
showLqi: false,
cellCm: 5,
kioskIconScale: 1,
kioskFontScale: 1,
stageSize: { width: 100, height: 100 },
positionOf: () => ({ x: 50, y: 50 }),
presentationOf: () => ({
scale: 1, valueText: null, valueFullText: '', valueBadge: null,
tempText: null, humText: null, lqiText: null,
pulse: { animated: false, diameterScale: 1 },
}),
labelPositionOf: () => ({ x: 0, y: 0 }),
labelScaleOf: () => 1,
openingEntityAvailable: () => false,
openingWallIndex: () => ({ adjacencyEps: 0.1, edges: [] }),
};
const live = buildIsoOverlayRenderScene(input);
const repeated = buildIsoOverlayRenderScene(input);
assert.strictEqual(repeated.devices.get('device'), live.devices.get('device'),
'unchanged HA/render passes reuse the exact pure placement result');
assert.equal(live.devices.get('device')?.nearWallBefore, true);
const fit = buildIsoOverlayRenderScene({ ...input, resolveCollisions: false });
assert.equal(fit.devices.get('device')?.nearWallBefore, false,
'fit envelope uses unnudged bounds without running wall collision search');
assert.notStrictEqual(fit.devices.get('device'), live.devices.get('device'),
'fit and live placements use separate bounded cache entries');
const zoomed = buildIsoOverlayRenderScene({ ...input, view: { x: 0, y: 0, w: 120, h: 120 } });
assert.notStrictEqual(zoomed.devices.get('device'), live.devices.get('device'),
'view scale invalidates the placement signature');
});
test('visible wall side quads participate in overlay collision', () => {
const walls = [[[[45, 20], [55, 20], [55, 80], [45, 80]]]];
const scene = resolveIsoScene({