Files
houseplan-card/dist/houseplan-assets/zigbee-topology-BbetEPvj.js
T
Claude 19587a797f Release v1.78.0-beta.5 candidate refresh
Пересборка кандидата на голове dev после слияния #669–#673 и #675:
бандл из текущих исходников, снимок STATUS и строка текущего цикла.

Issue: #663
Issue: #664
Issue: #665
Issue: #666
Issue: #667
Issue: #669
Issue: #670
Issue: #671
Issue: #672
Issue: #673
Issue: #675
User-Visible: no
Release: v1.78.0-beta.5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-27 12:14:08 +03:00

2 lines
11 KiB
JavaScript

globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="d06c84d556e989bcf1e9fa8c0eb28b72de2cbf0fe7a8c35051d3497e78d9cf96";import{s as e,aM as n}from"./houseplan-card-Ddo22-SB.js";import{n as t}from"./namespace-language-CwX4Ljv1.js";var o={title:"Zigbee links",toggle:"Show Zigbee links when hovering over a device",hint:"Shows observed direct neighbours only. Nothing is fetched while you hover.",help:"Shows which Zigbee devices each device talks to directly. Line colour is link quality (LQI) on the same scale as the device's LQI reading: red at 40 and below, green at 180 and above. A dashed line means quality was not reported. An arrow points to the next device on the way to the coordinator: one arrow leads out, incoming arrows are the devices that route through this one. A line without an arrow is a spare neighbour. This is the route tree House Plan builds, not the path a packet takes right now: a label at the end of an arrow means its target is not on this plan, and no arrow at all means the route is unknown. Data comes from the last load and goes stale; links are shown with a mouse only.",help_aria:"Help: Zigbee links",admin_only:"Topology data is available to Home Assistant administrators only.",save_first:"Save this setting before loading topology data.",zha:"ZHA",zha_read:"Read ZHA data",zha_hint:"Reads ZHA's cached topology; it does not start a radio scan.",z2m:"Zigbee2MQTT",z2m_topics:"Base topics (one per line)",z2m_update:"Update map",z2m_warning:"A network-map scan can take 10 seconds to 2 minutes and may temporarily reduce Zigbee responsiveness.",status_idle:"Data not loaded",status_loading:"Loading…",status_ready:"Received {time}",status_stale:"Received {time} · stale",status_partial:"Received {time} · some nodes were omitted",status_no_links:"Received {time} · no observed links found",error_permission:"Administrator permission is required.",error_unsupported:"This provider or Home Assistant API is unavailable.",error_timeout:"The provider did not respond in time.",error_invalid_topic:"Check the Zigbee2MQTT base topic.",error_invalid_payload:"The provider returned unsupported topology data.",error_provider:"Topology data could not be loaded.",remote_count:"+{n} in other spaces",route_device_not_on_plan:"device is not on the plan",route_coordinator_not_on_plan:"coordinator is not on the plan",route_other_space:"another space"};const i=e=>new URL(`${e}?retry`,import.meta.url).href,r=t(o,{ru:e=>0===e?import("./topology-ru-Di7X71yN.js"):import(i("./topology-ru-Di7X71yN.js")),de:e=>0===e?import("./topology-de-BjBB8qiK.js"):import(i("./topology-de-BjBB8qiK.js")),fr:e=>0===e?import("./topology-fr-DXFxoYd-.js"):import(i("./topology-fr-DXFxoYd-.js"))});function s(e,n){const t=r.dictionary(e)?.[n]??o[n];return"string"==typeof t&&t.trim().length>0}function a(n,t,i){return e(r.dictionary(n)?.[t]??o[t]??t,i)}const d=3e5,c=2097152,l=6e3;function u(e){return null!==e&&"object"==typeof e?e:null}function p(e){if("string"!=typeof e&&"number"!=typeof e)return null;let n=String(e).trim().toLowerCase();return n=/^0x[0-9a-f]{16}$/.test(n)?n.slice(2):n.replace(/[:-]/g,""),/^[0-9a-f]{16}$/.test(n)?n:null}function f(e,n,t){return`${e}:${n}:${t}`}function h(e){const n=String(e||"").toLowerCase().replace(/[ _-]/g,"");return n.includes("coordinator")?"coordinator":n.includes("router")?"router":n.includes("enddevice")||"end"===n?"end":"unknown"}const g=["parent","child","sibling","none","previous_child"];function _(e){const n=u(e),t=function(e){const n=Number(e);return Number.isFinite(n)&&n>=0&&n<=255?Math.round(n):void 0}(n?.lqi??n?.linkquality??n?.link_quality),o=function(e){if("number"==typeof e)return g[e];if("string"!=typeof e)return;const n=e.trim().toLowerCase().replace(/[\s_-]+/g,"");return"previouschild"===n?"previous_child":n.slice(0,40)||void 0}(n?.relationship);return{...void 0===t?{}:{lqi:t},...o?{relationship:o}:{}}}function v(e,n){return Array.isArray(e)&&e.length<=n?e:null}function y(e){if("string"==typeof e)return e.length<=c;try{return JSON.stringify(e).length<=c}catch{return!1}}function b(e,n,t,o,i){if(t===o)return void n.push({code:"self_link",nodeKey:t});const r=t<o,s=r?`${t}|${o}`:`${o}|${t}`,a=e.get(s)||{a:r?t:o,b:r?o:t},d=r?"aToB":"bToA";a[d]?n.push({code:"duplicate_link",nodeKey:t}):a[d]=_(i),e.set(s,a)}function m(e,n=Date.now()){const t=[],o=y(e)?v(e,1e3):null;if(!o)return{provider:"zha",instanceId:"zha",obtainedAt:n,freshness:"provider-cache",nodes:[],links:[],warnings:[{code:"invalid_payload"}]};const i=new Map,r=new Map;for(const e of o){const n=u(e),o=p(n?.ieee??n?.ieee_address);if(!o){t.push({code:"invalid_payload"});continue}const r=f("zha","zha",o);i.set(r,{key:r,ieee:o,..."string"==typeof n?.device_reg_id?{deviceId:n.device_reg_id}:{},role:h(n?.device_type??n?.type),..."boolean"==typeof n?.available?{available:n.available}:{}})}for(const e of o){const n=u(e),o=p(n?.ieee??n?.ieee_address);if(!o)continue;const s=f("zha","zha",o),a=v(n?.neighbors,l);if(a)for(const e of a){if(r.size>=l){t.push({code:"invalid_payload"});break}const n=u(e),o=p(n?.ieee??n?.ieee_address);if(!o){t.push({code:"invalid_payload",nodeKey:s});continue}const a=f("zha","zha",o);i.has(a)||i.set(a,{key:a,ieee:o,role:h(n?.device_type)}),b(r,t,s,a,e)}else null!=n?.neighbors&&t.push({code:"invalid_payload",nodeKey:s})}return{provider:"zha",instanceId:"zha",obtainedAt:n,freshness:"provider-cache",nodes:[...i.values()],links:[...r.values()],warnings:t}}function k(e,n){const t=u(e),o=p(t?.ieeeAddr??t?.ieee_address??t?.ieee??e);if(o)return o;for(const o of[t?.id,t?.networkAddress,t?.network_address,e])if(null!=o){const e=n.get(String(o));if(e)return e}return null}function w(e,t,o=Date.now()){const i=[],r=n(t)||"invalid",s=y(e)?function(e){let n=e;if("string"==typeof n){if(n.length>c)return null;try{n=JSON.parse(n)}catch{return null}}const t=u(n),o=u(t?.data);if(n=o?.value??t?.value??t?.data??n,"string"==typeof n){if(n.length>c)return null;try{n=JSON.parse(n)}catch{return null}}return n}(e):null,a=u(s),d=v(a?.nodes,1e3),g=v(a?.links,l);if(!d||!g)return{provider:"z2m",instanceId:r,obtainedAt:o,freshness:"fresh-scan",nodes:[],links:[],warnings:[{code:"invalid_payload"}]};const _=new Map,m=new Map;for(const e of d){const n=u(e),t=p(n?.ieeeAddr??n?.ieee_address??n?.ieee);if(!t){i.push({code:"invalid_payload"});continue}const o=f("z2m",r,t);_.set(o,{key:o,ieee:t,role:h(n?.type??n?.device_type),..."boolean"==typeof n?.failed?{available:!n.failed}:{}});for(const e of[n?.id,n?.networkAddress,n?.network_address])null!=e&&m.set(String(e),t)}const w=new Map;for(const e of g){const n=u(e),t=p(n?.sourceIeeeAddr)??k(n?.source,m),o=p(n?.targetIeeeAddr)??k(n?.target,m);if(!t||!o){i.push({code:"invalid_payload"});continue}const s=f("z2m",r,t),a=f("z2m",r,o);_.has(s)||_.set(s,{key:s,ieee:t,role:"unknown"}),_.has(a)||_.set(a,{key:a,ieee:o,role:"unknown"}),b(w,i,s,a,e)}return{provider:"z2m",instanceId:r,obtainedAt:o,freshness:"fresh-scan",nodes:[..._.values()],links:[...w.values()],warnings:i}}function A(e){if("string"!=typeof e)return null;const n=p(e);if(n)return n;const t=e.toLowerCase().match(/^zigbee2mqtt(?:_bridge)?_(.+)$/);return t?p(t[1]):null}function S(e,n){if(e.deviceId&&n.devices[e.deviceId])return[e.deviceId];const t=new Set;for(const[o,i]of Object.entries(n.devices)){const n=u(i);(Array.isArray(n?.identifiers)?n.identifiers:[]).some(n=>Array.isArray(n)&&A(n[1])===e.ieee)&&t.add(o)}if(t.size)return[...t];for(const o of Object.values(n.entities)){const n=u(o);"string"==typeof n?.device_id&&"string"==typeof n.unique_id&&(A(n.unique_id)===e.ieee&&t.add(n.device_id))}return[...t]}function T(e){return!e.hidden&&!e.virtual&&"ha_disabled"!==e.bindingStatus?.kind&&"orphaned"!==e.bindingStatus?.kind&&"unverified"!==e.bindingStatus?.kind}function z(e){const n=new Map,t=new Map,o=e.nodes.filter(e=>"coordinator"===e.role).map(e=>e.key).sort();if(1!==o.length)return{distances:n,parents:t};const i=o[0],r=function(e){const n=new Set(e.nodes.map(e=>e.key)),t=new Map;for(const e of[...n].sort())t.set(e,[]);for(const o of[...e.links].sort((e,n)=>`${e.a}\0${e.b}`.localeCompare(`${n.a}\0${n.b}`)))n.has(o.a)&&n.has(o.b)&&(t.get(o.a).push({neighborKey:o.b,observation:o.aToB}),t.get(o.b).push({neighborKey:o.a,observation:o.bToA}));for(const e of t.values())e.sort((e,n)=>e.neighborKey.localeCompare(n.neighborKey));return t}(e);if(!r.has(i))return{distances:n,parents:t};n.set(i,0);const s=[i];for(let e=0;e<s.length;e++){const t=s[e],o=n.get(t)+1;for(const{neighborKey:e}of r.get(t)||[])n.has(e)||(n.set(e,o),s.push(e))}for(const e of[...n.keys()].sort()){const o=n.get(e);if(0===o)continue;const i=(r.get(e)||[]).filter(({neighborKey:e})=>n.get(e)===o-1).sort((e,n)=>{const t="parent"===e.observation?.relationship?1:0,o="parent"===n.observation?.relationship?1:0;if(t!==o)return o-t;const i=e.observation?.lqi??-1;return(n.observation?.lqi??-1)-i||e.neighborKey.localeCompare(n.neighborKey)});i[0]&&t.set(e,i[0].neighborKey)}return{coordinatorKey:i,distances:n,parents:t}}function I(e,n,t){const o=new Map,i=[];for(const r of e.nodes){if(!1===r.available){i.push({code:"provider_scan_failure",nodeKey:r.key});continue}const e=S(r,t);if(1!==e.length){i.push({code:"unmatched_device",nodeKey:r.key});continue}const s=e[0];let a=n.filter(e=>T(e)&&"device"===e.bindingKind&&e.bindingRef===s);a.length||(a=n.filter(e=>T(e)&&"entity"===e.bindingKind&&!!e.bindingRef&&t.entities[e.bindingRef]?.device_id===s)),1===a.length?o.set(r.key,{markerId:a[0].id,space:a[0].space}):i.push({code:a.length>1?"ambiguous_placement":"unmatched_device",nodeKey:r.key})}return{placements:o,warnings:i}}function R(e,n,t){return e.map(e=>({topology:e,placements:I(e,n,t).placements,routes:z(e)}))}function q(e,n,t){const o=new Map,i=new Set,r=new Map;let s=0;for(const{topology:a,placements:d,routes:c}of e){const e=new Set([...d].filter(([,e])=>e.markerId===t&&e.space===n).map(([e])=>e));if(e.size){for(const t of e){const e=c.parents.get(t);if(!e)continue;const o=d.get(e);if(o?.space===n)continue;let i;i=o?{kind:"remote-space",spaceId:o.space}:"coordinator"===a.nodes.find(n=>n.key===e)?.role?{kind:"unplaced-coordinator"}:{kind:"unplaced-device"};const s="remote-space"===i.kind?`${i.kind}:${i.spaceId}`:i.kind;r.set(s,i)}for(const r of a.links){const a=e.has(r.a),l=e.has(r.b);if(!a&&!l)continue;const u=a?r.a:r.b,p=a?r.b:r.a,f=d.get(p);if(!f||f.markerId===t){s++;continue}const h=c.parents.get(u)===p;if(f.space!==n){h||i.add(f.markerId);continue}const g=a?r.aToB:r.bToA,_=h?"toward-neighbor":c.parents.get(p)===u?"toward-origin":void 0,v=o.get(f.markerId);v?(void 0===v.line.lqi&&void 0!==g?.lqi&&(v.line.lqi=g.lqi),_&&v.directions.add(_)):o.set(f.markerId,{line:{neighborMarkerId:f.markerId,lqi:g?.lqi},directions:new Set(_?[_]:[])})}}}return{lines:[...o.values()].map(({line:e,directions:n})=>1===n.size?{...e,routeDirection:[...n][0]}:e),remoteCount:i.size,omittedCount:s,parentTargets:[...r.values()]}}export{d as T,r as a,R as b,w as c,s as h,I as m,m as n,q as r,a as t};