fix: satisfy validation gates for support reports (#43)

Issue: #43
User-Visible: no
This commit is contained in:
Sergey Matyunin
2026-09-02 02:28:38 +03:00
parent 1ba5363038
commit ffddc38376
22 changed files with 329 additions and 163 deletions
@@ -1,125 +1,125 @@
{
"schema": 1,
"fingerprint": "087d27ff0b95debda974220d6caa06c83df26b0c798e8298eddc1c90ee6353f6",
"fingerprint": "c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6",
"entry": "houseplan-card.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-5sP7gmz1.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 290370,
"initialViewGzipBytes": 290374,
"lazyFiles": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/de-CTrgjw4G.js",
"houseplan-assets/editor-m5cOb3Eu.js",
"houseplan-assets/fr-CZcUQIQ6.js",
"houseplan-assets/houseplan-editor-runtime-dBvEi_Y4.js",
"houseplan-assets/houseplan-onboarding-runtime-X9KZW5U_.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/fr-yr6HN0On.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
],
"lazyGzipBytes": 205776,
"lazyGzipBytes": 205802,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/editor-m5cOb3Eu.js",
"houseplan-assets/houseplan-editor-runtime-dBvEi_Y4.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js"
],
"lazyEditorGzipBytes": 148681,
"lazyEditorGzipBytes": 148714,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/houseplan-onboarding-runtime-X9KZW5U_.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
],
"lazyOnboardingGzipBytes": 14026,
"lazyLocaleFiles": [
"houseplan-assets/de-CTrgjw4G.js",
"houseplan-assets/fr-CZcUQIQ6.js"
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/fr-yr6HN0On.js"
],
"lazyLocaleGzipBytes": 50138,
"lazyLocaleGzipBytes": 50132,
"files": [
{
"path": "houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"sha256": "999099104d79952b9c9cdc9a71d044e510398366a0526ddb1d091e4697560828",
"path": "houseplan-assets/backdrop-pick-y86gdzEv.js",
"sha256": "753369b21d0b9d1b2e5c780452c3b41ae29bbb00ef5787c859e2d11dac2aa6d8",
"rawBytes": 20636,
"gzipBytes": 7069,
"gzipBytes": 7070,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-CTrgjw4G.js",
"sha256": "f91434ee331ed288d117ba5500c0051ece177d99c05615ff2511e610701b2cf8",
"path": "houseplan-assets/de-5bH7Tqw5.js",
"sha256": "67422f19ed35403583f3b438f6f3efc83ede77164f79d612754660b19090ef58",
"rawBytes": 83981,
"gzipBytes": 25340,
"gzipBytes": 25337,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-m5cOb3Eu.js",
"sha256": "9dedbdd213bba49452e19f9d1c1c507d0af5d32003d9976eccac889f2cde85be",
"path": "houseplan-assets/editor-CXgHU1PF.js",
"sha256": "df251d831416ffa58a648577024f66f8e3f05a2890d338d0772870e7dff202fc",
"rawBytes": 3826,
"gzipBytes": 1579,
"gzipBytes": 1580,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-CZcUQIQ6.js",
"sha256": "0795dff649cec998870462d21df351bfad990f31550f90d2660471b2c01f51cb",
"path": "houseplan-assets/fr-yr6HN0On.js",
"sha256": "8a9bf182a81ea57869accbba27e97029f554d624b0fc68d59688279b023b2b3a",
"rawBytes": 86212,
"gzipBytes": 24798,
"gzipBytes": 24795,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-5sP7gmz1.js",
"sha256": "45fdd464fac57f508f180fb5e14674425a48e1d32cc374a0482bd684f0962acd",
"path": "houseplan-assets/houseplan-card-D2QbRkX7.js",
"sha256": "98224a3ef6c2b7fa837fd0771cee732a2e4ed88127dd7b83283728d93bc477ed",
"rawBytes": 1032271,
"gzipBytes": 289576,
"gzipBytes": 289578,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-CTrgjw4G.js",
"houseplan-assets/editor-m5cOb3Eu.js",
"houseplan-assets/fr-CZcUQIQ6.js",
"houseplan-assets/houseplan-editor-runtime-dBvEi_Y4.js",
"houseplan-assets/houseplan-onboarding-runtime-X9KZW5U_.js"
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/fr-yr6HN0On.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-dBvEi_Y4.js",
"sha256": "832daf3acccdf2f18112adba65874123084209bb1e11f54d89553f905cef1338",
"rawBytes": 543198,
"gzipBytes": 140033,
"path": "houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"sha256": "0cece0a10a2d63fbd1dadfd1e0837049c79041c66662d1b63e71b4bd61669d72",
"rawBytes": 543272,
"gzipBytes": 140064,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-X9KZW5U_.js",
"sha256": "d09f3965b43df77d543f03723306d7d3a5c79b325d244ad22213d2860dcda1d7",
"path": "houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js",
"sha256": "9a654161d364ab4a9e40036401f400cb7ba39412a9024b4b4f30a7d5cec32da9",
"rawBytes": 28088,
"gzipBytes": 6957,
"gzipBytes": 6956,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "9fd734e140645820dacb371bd8adfc8c28ad25b8130588d781639dd926941355",
"sha256": "eb53af1be3c6e20eb7a948f738a9efd1e11ae1322592b9f27955020cf70d983e",
"rawBytes": 1183,
"gzipBytes": 794,
"gzipBytes": 796,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="087d27ff0b95debda974220d6caa06c83df26b0c798e8298eddc1c90ee6353f6";import{b as e,l as o,t,d8 as s,A as a,d9 as i,da as l,db as n,E as r,c}from"./houseplan-card-5sP7gmz1.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__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";import{b as e,l as o,t,d8 as s,A as a,d9 as i,da as l,db as n,E as r,c}from"./houseplan-card-D2QbRkX7.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}
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="087d27ff0b95debda974220d6caa06c83df26b0c798e8298eddc1c90ee6353f6";try{await import("./houseplan-assets/houseplan-card-5sP7gmz1.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__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";try{await import("./houseplan-assets/houseplan-card-D2QbRkX7.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)}
+55 -55
View File
@@ -1,125 +1,125 @@
{
"schema": 1,
"fingerprint": "087d27ff0b95debda974220d6caa06c83df26b0c798e8298eddc1c90ee6353f6",
"fingerprint": "c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6",
"entry": "houseplan-card.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-5sP7gmz1.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 290370,
"initialViewGzipBytes": 290374,
"lazyFiles": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/de-CTrgjw4G.js",
"houseplan-assets/editor-m5cOb3Eu.js",
"houseplan-assets/fr-CZcUQIQ6.js",
"houseplan-assets/houseplan-editor-runtime-dBvEi_Y4.js",
"houseplan-assets/houseplan-onboarding-runtime-X9KZW5U_.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/fr-yr6HN0On.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
],
"lazyGzipBytes": 205776,
"lazyGzipBytes": 205802,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/editor-m5cOb3Eu.js",
"houseplan-assets/houseplan-editor-runtime-dBvEi_Y4.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js"
],
"lazyEditorGzipBytes": 148681,
"lazyEditorGzipBytes": 148714,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/houseplan-onboarding-runtime-X9KZW5U_.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
],
"lazyOnboardingGzipBytes": 14026,
"lazyLocaleFiles": [
"houseplan-assets/de-CTrgjw4G.js",
"houseplan-assets/fr-CZcUQIQ6.js"
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/fr-yr6HN0On.js"
],
"lazyLocaleGzipBytes": 50138,
"lazyLocaleGzipBytes": 50132,
"files": [
{
"path": "houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"sha256": "999099104d79952b9c9cdc9a71d044e510398366a0526ddb1d091e4697560828",
"path": "houseplan-assets/backdrop-pick-y86gdzEv.js",
"sha256": "753369b21d0b9d1b2e5c780452c3b41ae29bbb00ef5787c859e2d11dac2aa6d8",
"rawBytes": 20636,
"gzipBytes": 7069,
"gzipBytes": 7070,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-CTrgjw4G.js",
"sha256": "f91434ee331ed288d117ba5500c0051ece177d99c05615ff2511e610701b2cf8",
"path": "houseplan-assets/de-5bH7Tqw5.js",
"sha256": "67422f19ed35403583f3b438f6f3efc83ede77164f79d612754660b19090ef58",
"rawBytes": 83981,
"gzipBytes": 25340,
"gzipBytes": 25337,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-m5cOb3Eu.js",
"sha256": "9dedbdd213bba49452e19f9d1c1c507d0af5d32003d9976eccac889f2cde85be",
"path": "houseplan-assets/editor-CXgHU1PF.js",
"sha256": "df251d831416ffa58a648577024f66f8e3f05a2890d338d0772870e7dff202fc",
"rawBytes": 3826,
"gzipBytes": 1579,
"gzipBytes": 1580,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-CZcUQIQ6.js",
"sha256": "0795dff649cec998870462d21df351bfad990f31550f90d2660471b2c01f51cb",
"path": "houseplan-assets/fr-yr6HN0On.js",
"sha256": "8a9bf182a81ea57869accbba27e97029f554d624b0fc68d59688279b023b2b3a",
"rawBytes": 86212,
"gzipBytes": 24798,
"gzipBytes": 24795,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-5sP7gmz1.js",
"sha256": "45fdd464fac57f508f180fb5e14674425a48e1d32cc374a0482bd684f0962acd",
"path": "houseplan-assets/houseplan-card-D2QbRkX7.js",
"sha256": "98224a3ef6c2b7fa837fd0771cee732a2e4ed88127dd7b83283728d93bc477ed",
"rawBytes": 1032271,
"gzipBytes": 289576,
"gzipBytes": 289578,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-CTrgjw4G.js",
"houseplan-assets/editor-m5cOb3Eu.js",
"houseplan-assets/fr-CZcUQIQ6.js",
"houseplan-assets/houseplan-editor-runtime-dBvEi_Y4.js",
"houseplan-assets/houseplan-onboarding-runtime-X9KZW5U_.js"
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/fr-yr6HN0On.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-dBvEi_Y4.js",
"sha256": "832daf3acccdf2f18112adba65874123084209bb1e11f54d89553f905cef1338",
"rawBytes": 543198,
"gzipBytes": 140033,
"path": "houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"sha256": "0cece0a10a2d63fbd1dadfd1e0837049c79041c66662d1b63e71b4bd61669d72",
"rawBytes": 543272,
"gzipBytes": 140064,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-X9KZW5U_.js",
"sha256": "d09f3965b43df77d543f03723306d7d3a5c79b325d244ad22213d2860dcda1d7",
"path": "houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js",
"sha256": "9a654161d364ab4a9e40036401f400cb7ba39412a9024b4b4f30a7d5cec32da9",
"rawBytes": 28088,
"gzipBytes": 6957,
"gzipBytes": 6956,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-DDeYL4Ri.js",
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "9fd734e140645820dacb371bd8adfc8c28ad25b8130588d781639dd926941355",
"sha256": "eb53af1be3c6e20eb7a948f738a9efd1e11ae1322592b9f27955020cf70d983e",
"rawBytes": 1183,
"gzipBytes": 794,
"gzipBytes": 796,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-5sP7gmz1.js"
"houseplan-assets/houseplan-card-D2QbRkX7.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,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="087d27ff0b95debda974220d6caa06c83df26b0c798e8298eddc1c90ee6353f6";import{b as e,l as o,t,d8 as s,A as a,d9 as i,da as l,db as n,E as r,c}from"./houseplan-card-5sP7gmz1.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__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";import{b as e,l as o,t,d8 as s,A as a,d9 as i,da as l,db as n,E as r,c}from"./houseplan-card-D2QbRkX7.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}
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
View File
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="087d27ff0b95debda974220d6caa06c83df26b0c798e8298eddc1c90ee6353f6";try{await import("./houseplan-assets/houseplan-card-5sP7gmz1.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__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";try{await import("./houseplan-assets/houseplan-card-D2QbRkX7.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)}
+11 -11
View File
@@ -3,7 +3,7 @@
"fixture": "synthetic-only",
"chromium": "151.0.7922.34",
"oxipng": "oxipng 10.2.0",
"sourceFingerprint": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceFingerprint": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"captureScriptSha256": "135dd9a566653b05cae3010d7861fca6453daef0ecdcdf1ba10059e65f0d4de8",
"command": "npm run build && node demo/docs/capture.mjs",
"scenarios": {
@@ -15,7 +15,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "f4ecb7fd1f107ccda6c8a1e90be1bce0f2690f93e5e42776ca783297f4143135"
},
"view-touch": {
@@ -26,7 +26,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "946801f6475a40c0e31a70e4b67eaa34c6f70df5329a63915f445e6e4811ca6a"
},
"space-create": {
@@ -37,7 +37,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "617b51b3648498787b5039980c9f3eceb75ba56ed63a1a20e616bc05bc304362"
},
"room-contour-close": {
@@ -48,7 +48,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "9a79b7e517741e74701d1172ec3c66a340aaa9049a7f7a7b2fe86f4c3a2eccf0"
},
"plan-context-tray": {
@@ -59,7 +59,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "8fb569f326627700e08156c1ca35a4042bcb529a955663b54228d04357c881d0"
},
"device-editor": {
@@ -70,7 +70,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "720fc3aa2070d1fcf6907091941751c623f30cc6a001ff95e22de9be998136df"
},
"device-display-preview": {
@@ -81,7 +81,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "b2294c6de0b18ef386b5a2d18422a866b84d095f133d31e56e307664e31e5bc0"
},
"background-editor": {
@@ -92,7 +92,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "8dbc5864124c4bddbe076722a1503e666c40f432cfe7fff86e6d196c428365f3"
},
"room-card": {
@@ -103,7 +103,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "d09709ae1479cfaa1902068cb2a6015dfee3b58f1bbd349bafaa2c0592812463"
},
"device-info": {
@@ -114,7 +114,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7faa6c2eb29239ed511cc4b351d1f0f38b3fff92cf2039b77b823ef090528a4d",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"imageSha256": "c0b20a31c2987c8737e7b746c7d358e6c97231ea7e06d73050a2d3aebb216558"
}
},
+17 -11
View File
@@ -9196,21 +9196,26 @@ private async _buildSupportPreview(draftId: string): Promise<void> {
|| this.host._haIntegrationVersion !== CARD_VERSION) return;
this._supportPatch(draftId, { status: 'building', errorCode: '' });
try {
const response: any = await this.host.hass.callWS({
const response: unknown = await this.host.hass.callWS({
type: 'houseplan/support/preview',
card_version: CARD_VERSION,
...this._supportFacts(),
draft_id: draftId,
});
const payload = response && typeof response === 'object'
? response as Partial<Record<
'text' | 'size' | 'expires_in' | 'spaces' | 'token' | 'sha256' | 'version' | 'format',
unknown
>> : {};
const now = Date.now();
const text = typeof response?.text === 'string' ? response.text : '';
const size = Number(response?.size);
const expiresIn = Number(response?.expires_in);
const spaces = Number(response?.spaces);
const token = String(response?.token || '');
const sha256 = String(response?.sha256 || '');
const version = Number(response?.version);
const format = String(response?.format || '');
const text = typeof payload.text === 'string' ? payload.text : '';
const size = Number(payload.size);
const expiresIn = Number(payload.expires_in);
const spaces = Number(payload.spaces);
const token = String(payload.token || '');
const sha256 = String(payload.sha256 || '');
const version = Number(payload.version);
const format = String(payload.format || '');
const byteSize = new TextEncoder().encode(text).byteLength;
if (!/^[0-9a-f]{48}$/.test(token) || !/^[0-9a-f]{64}$/.test(sha256)
|| format !== 'houseplan-support-package' || version !== 1
@@ -9314,14 +9319,15 @@ public async _submitSupport(): Promise<void> {
if (!supportCanSubmit(current)) return;
this._supportPatch(current.draftId, { status: 'sending', errorCode: '' });
try {
const response: any = await this.host.hass.callWS({
const response: unknown = await this.host.hass.callWS({
type: 'houseplan/support/submit',
message: current.message.trim(),
contact: current.contact.trim(),
...(current.attach && current.preview ? { preview_token: current.preview.token } : {}),
idempotency_key: current.idempotencyKey,
});
const reportId = String(response?.report_id || '');
const reportId = response && typeof response === 'object' && 'report_id' in response
? String((response as { report_id?: unknown }).report_id || '') : '';
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(reportId)) {
throw { code: 'support_unavailable' };
}
+4 -3
View File
@@ -121,7 +121,8 @@ export function supportRuntimeFacts(
const now = options.now ?? Date.now();
const last = Number(options.registryLastSuccess || 0);
const age = last <= 0 ? 'unknown' : now - last <= 10 * 60_000 ? 'fresh' : 'stale';
const language = (['en', 'ru', 'de', 'fr'] as const).includes(options.language as any)
const languages: readonly string[] = ['en', 'ru', 'de', 'fr'];
const language = languages.includes(options.language)
? options.language as SupportRuntimeFacts['language'] : 'en';
const media = globalThis.matchMedia?.bind(globalThis);
return {
@@ -137,8 +138,8 @@ export function supportRuntimeFacts(
}
export function supportErrorCode(value: unknown): string {
const code = value && typeof value === 'object'
? String((value as any).code || '') : '';
const code = value && typeof value === 'object' && 'code' in value
? String((value as { code?: unknown }).code || '') : '';
return new Set([
'support_invalid_message', 'support_preview_expired', 'support_package_too_large',
'support_rate_limited', 'support_unavailable', 'support_rejected', 'unauthorized',
+159
View File
@@ -7,6 +7,7 @@ from hashlib import sha256
import pytest
from custom_components.houseplan import support_package
from custom_components.houseplan.support_package import (
SupportPackageError,
build_support_package,
@@ -176,3 +177,161 @@ def test_frontend_facts_fail_closed(key, value):
facts[key] = value
with pytest.raises(SupportPackageError, match="support_rejected"):
validate_frontend_facts(facts)
def test_frontend_facts_reject_non_mapping_and_invalid_hover():
with pytest.raises(SupportPackageError, match="support_rejected"):
validate_frontend_facts(None)
facts = _facts()
facts["hover_capable"] = 1
with pytest.raises(SupportPackageError, match="support_rejected"):
validate_frontend_facts(facts)
def test_rich_plan_projection_preserves_safe_structure_and_drops_unknown_values():
config = {
"model_version": 9,
"settings": {
"north_deg": 30,
"fill_colors": {"warm": {"c": "#ffaa00", "a": 0.5, "secret": "drop"}},
"decor_default_style": {
"color": "#123456", "width_cm": 2, "secret": "drop",
},
},
"spaces": [{
"id": "floor",
"settings": {"show_names": True, "custom_fill": {"c": "#ffffff", "a": 0.4}},
"rooms": [{
"id": "kitchen", "x": 1, "y": 2, "w": 3, "h": 4,
"poly": [[0, 0], [2, 0], [False, 1], "bad"],
"wall_ids": ["wall-a"], "open_to": ["hall"],
"settings": {
"fill_mode": "custom", "custom_fill": {"c": "#000000", "a": 0.2},
"temp_source": "entity:sensor.temperature",
"hum_source": "invalid-source",
},
}],
"walls": [
{"key": "wall-a", "cm": 10, "a": [0, 0], "b": [2, 0]},
{"key": "wall-b", "cm": 12},
"bad",
],
"room_drafts": [
"bad",
{
"id": "draft-a", "points": [[0, 0], [1, 0], [True, 2]],
"segments": [{"id": "wall-a", "cm": 10}, {"cm": 12}, "bad"],
},
],
"partitions": [{"id": "partition-a", "a": [0, 1], "b": [2, 1], "cm": 8}],
"wall_columns": [{
"id": "column-a", "shape": "rect", "center": [1, 1], "cm": 20, "angle": 0,
}],
"openings": [
"bad",
{
"id": "door-a", "type": "door", "x": 1, "y": 1, "length": 0.9,
"contact": "binary_sensor.door", "lock": "lock.door",
"host": {"kind": "partition", "id": "partition-a", "t": 0.5},
},
{"id": "window-a", "type": "window", "host": {"kind": "column", "id": "x"}},
],
"decor": [
{"id": "line-a", "kind": "line", "x1": 0, "y1": 0, "x2": 1, "y2": 1},
{"id": "text-a", "kind": "text", "text": "private"},
],
"open_spans": [{"a": [0, 0], "b": [0, 1]}, "bad"],
}],
"markers": [
{
"id": "virtual-a", "binding": "virtual", "icon": "mdi:lightbulb",
"space": "floor", "room_id": "kitchen", "hidden": True,
"light_entity": "light.ceiling", "toggle_entity": "switch.ceiling",
"tap_target": "button.scene", "controls": ["sensor.temperature"],
"vacuum": {"live": True, "trail": True, "trail_mode": "line", "secret": "drop"},
"value_source": {"kind": "entity_state", "entity_id": "sensor.temperature"},
"value_badge": {
"enabled": True, "position": "bottom",
"source": {"kind": "derived_lqi"},
},
},
{
"id": "entity-a", "binding": "entity:sensor.temperature", "removed": True,
"value_source": {"kind": "derived_marker_state", "ref": "marker:virtual-a"},
},
{
"id": "unknown-a", "binding": "secret", "icon": "custom:private",
"value_source": {"kind": "private", "entity_id": "sensor.private"},
},
],
}
layout = {
"virtual-a": {"s": "floor", "x": 0.25, "y": 0.75},
"rl_kitchen": {"s": "floor", "x": 0.5, "y": 0.5, "k": 1.1},
7: {"x": 0},
"unknown-device": "bad",
}
raw, _ = build_support_package(
config, layout, config_rev=1, layout_rev=2,
card_version="invalid version!", integration_version="1.0.0",
home_assistant_version="2026.8.0", runtime=_facts(), namespace="rich",
)
package = json.loads(raw)
plan = package["plan_backup"]["config"]
space = plan["spaces"][0]
assert package["versions"]["card"] == "unknown"
assert plan["settings"]["fill_colors"] == {"warm": {"a": 0.5, "c": "#ffaa00"}}
assert plan["settings"]["decor_default_style"] == {"color": "#123456", "width_cm": 2}
assert space["rooms"][0]["poly"] == [[0, 0], [2, 0]]
assert space["rooms"][0]["settings"]["temp_source_kind"] == "entity"
assert space["rooms"][0]["settings"]["hum_source_kind"] == "unknown"
assert len(space["walls"]) == 2
assert space["walls"][1] == {"cm": 12, "key": "wall-rich-2"}
assert space["room_drafts"][0]["segments"][1] == {"cm": 12}
assert space["openings"][0]["host"]["kind"] == "partition"
assert "host" not in space["openings"][1]
assert space["decor"][1]["text"] == "[redacted text]"
virtual, entity, unknown = plan["markers"]
assert virtual["binding_kind"] == "virtual"
assert virtual["icon"] == "mdi:lightbulb"
assert virtual["vacuum"] == {"live": True, "trail": True, "trail_mode": "line"}
assert virtual["value_source"] == {
"entity_id": "entity-rich-1", "kind": "entity_state",
}
assert virtual["value_badge"]["source"] == {"kind": "derived_lqi"}
assert entity["value_source"] == {
"kind": "derived_marker_state", "ref": "marker:marker-rich-1",
}
assert unknown["binding_kind"] == "unknown"
assert "icon" not in unknown and "value_source" not in unknown
assert set(package["plan_backup"]["layout"]) == {"marker-rich-1", "rl_room-rich-1"}
assert package["summary"]["markers"] == {
"total": 3,
"lifecycle": {"active": 1, "hidden": 1, "removed": 1},
"binding": {"entity": 1, "unknown": 1, "virtual": 1},
}
def test_projection_helpers_fail_closed_on_malformed_shapes():
ids = support_package._Pseudonyms("edge")
assert ids.get("room", None) is None
assert ids.get("room", "") is None
assert ids.get("room", "same") == ids.get("room", "same")
assert support_package._point(None) is None
assert support_package._point([True, 1]) is None
assert support_package._points(None) == []
assert support_package._custom_fill(None) is None
assert support_package._global_settings(None) == {}
assert support_package._room_settings(ids, None) == {}
assert support_package._project_layout(ids, None) == {}
assert support_package._summary(None, None)["spaces"] == 0
assert support_package._binding_kind(None) == "unknown"
def test_package_size_limit_is_enforced_after_projection(monkeypatch):
monkeypatch.setattr(support_package, "MAX_SUPPORT_ATTACHMENT_BYTES", 1)
with pytest.raises(SupportPackageError, match="support_package_too_large"):
_build()